commit 1b419592bf687cf7edfdd7ea05ae176fab11e0e9 Author: Dain Nilsson Date: Fri Mar 2 13:15:13 2018 +0100 Initial import. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c6b769 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.pyc +*.egg +*.egg-info +build/ +dist/ +.eggs/ +.ropeproject/ +ChangeLog +man/*.1 + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e141caf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: +- repo: git://github.com/pre-commit/pre-commit-hooks + sha: v1.2.3 + hooks: + - id: flake8 + - id: double-quote-string-fixer +exclude: '^(fido_host|test)/pyu2f/.*' diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..dbc892d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,33 @@ +language: python +sudo: false + +python: + - "2.7" + - "3.4" + - "3.5" + - "3.6" + - "pypy-5.7" + - "pypy3.5-5.7.1-beta" + +cache: + directories: + - $HOME/.cache/pip + +addons: + apt: + packages: + - libffi-dev + - libssl-dev + - swig + +install: + - pip install pre-commit + - pip install -e . + +script: + - pre-commit run --all-files + - python setup.py test + + +after_success: + - coveralls diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..8e6c4ea --- /dev/null +++ b/COPYING @@ -0,0 +1,26 @@ +Copyright (c) 2018 Yubico AB +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/COPYING.APLv2 b/COPYING.APLv2 new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/COPYING.APLv2 @@ -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 [yyyy] [name of copyright owner] + + 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. diff --git a/COPYING.MPLv2 b/COPYING.MPLv2 new file mode 100644 index 0000000..14e2f77 --- /dev/null +++ b/COPYING.MPLv2 @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..fe29e47 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include COPYING* +include NEWS +include ChangeLog +include fido_host/public_suffix_list.dat +include examples/* diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..19ad210 --- /dev/null +++ b/NEWS @@ -0,0 +1,2 @@ +* Version 0.0.0 (unreleased) + ** Initial version. diff --git a/README b/README new file mode 100644 index 0000000..a04c3d8 --- /dev/null +++ b/README @@ -0,0 +1,49 @@ +== fido-host +Provides library functionality for communicationg with a FIDO device over USB. + +WARNING: The state of this project is alpha. Expect things to change and break at any time! + +This library aims to support the FIDO U2F and FIDO 2.0 protocols for +communicating with a USB authenticator via the Client-to-Authenticator Protocol +(CTAP 1 and 2). In addition to this low-level device access, classes defined in +the `fido_host.client` implement higher level device operations. + +For usage, see the examples/ directory. + +=== License +This project, with the exception of the files mentioned below, is licensed +under the BSD 2-clause license. +See the COPYING file for the full license text. + +This project contains source code from pyu2f (https://github.com/google/pyu2f) +which is licensed under the Apache License, version 2.0. +These files are located in `fido_host/pyu2f/` and `test/pyu2f/`. +See http://www.apache.org/licenses/LICENSE-2.0, +or the COPYING.APACHEv2 file for the full license text. + +This project also bundles the public suffix list (https://publicsuffix.org) +which is licensed under the Mozilla Public License, version 2.0. +See https://mozilla.org/MPL/2.0/, +or the COPYING.MPLv2 file for the full license text. + +=== Installation +fido-host is installable by running the following command: + + # pip install fido-host + +Under Linux you will need to add a Udev rule to be able to access the FIDO +device, or run as root. For example, the Udev rule may contain the following: + +---- +#Udev rule for allowing HID access to Yubico devices for FIDO support. + +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \ + MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050" +---- + +=== Dependencies +fido-host is compatible with CPython 2.7, 3.4 onwards, and is tested on +Windows, MacOS, and Linux. + +This project depends on Cryptography. For instructions on installing this +dependency, see link:https://cryptography.io/en/latest/installation/. diff --git a/README.adoc b/README.adoc new file mode 120000 index 0000000..100b938 --- /dev/null +++ b/README.adoc @@ -0,0 +1 @@ +README \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..1e010b7 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +# appveyor.yml + +# Building, testing and deployment for Windows + +# Syntax for this file: +# https://www.appveyor.com/docs/appveyor-yml + +environment: + + matrix: + - PYTHON: "C:\\Python27" + - PYTHON: "C:\\Python27-x64" + - PYTHON: "C:\\Python34" + - PYTHON: "C:\\Python34-x64" + - PYTHON: "C:\\Python35" + - PYTHON: "C:\\Python35-x64" + - PYTHON: "C:\\Python36" + - PYTHON: "C:\\Python36-x64" + +matrix: + fast_finish: true + +build_script: + - pip install -e . + +test_script: + - python setup.py test diff --git a/examples/credential.py b/examples/credential.py new file mode 100644 index 0000000..416b29c --- /dev/null +++ b/examples/credential.py @@ -0,0 +1,81 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +""" +Connects to the first FIDO device found, creates a new credential for it, +and authenticates the credential. This works with both FIDO 2.0 devices as well +as with U2F devices. +""" +from __future__ import print_function, absolute_import + +from fido_host.hid import CtapHidDevice +from fido_host.client import Fido2Client +import sys + + +# Locate a device +dev = next(CtapHidDevice.list_devices(), None) +if not dev: + print('No FIDO device found') + sys.exit(1) + +# Set up a FIDO 2 client using the origin https://example.com +client = Fido2Client(dev, 'https://example.com') + +# Prepare parameters for makeCredential +rp = {'id': 'example.com', 'name': 'Example RP'} +user = {'id': b'user_id', 'name': 'A. User'} +challenge = 'Y2hhbGxlbmdl' + +# Create a credential +print('\nTouch your authenticator device now...\n') +attestation_object, client_data = client.make_credential(rp, user, challenge) +print('New credential created!') + +print('CLIENT DATA:', client_data) +print('ATTESTATION OBJECT:', attestation_object) +print() +print('CREDENTIAL DATA:', attestation_object.auth_data.credential_data) + + +# Prepare parameters for getAssertion +challenge = 'Q0hBTExFTkdF' # Use a new challenge for each call. +allow_list = [{ + 'type': 'public-key', + 'id': attestation_object.auth_data.credential_data.credential_id +}] + +# Authenticate the credential +print('\nTouch your authenticator device now...\n') +assertions, client_data = client.get_assertion(rp['id'], challenge, allow_list) +print('Credential authenticated!') + +assertion = assertions[0] # Only one cred in allowList, only one response. + +print('CLIENT DATA:', client_data) +print() +print('ASSERTION DATA:', assertion) diff --git a/examples/get_info.py b/examples/get_info.py new file mode 100644 index 0000000..9814183 --- /dev/null +++ b/examples/get_info.py @@ -0,0 +1,53 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +""" +Connects to each attached FIDO device, and: + 1. If the device supports CBOR commands, perform a getInfo command. + 2. If the device supports WINK, perform the wink command. +""" +from __future__ import print_function, absolute_import + +from fido_host.hid import CtapHidDevice, CAPABILITY +from fido_host.fido2 import CTAP2 + + +for dev in CtapHidDevice.list_devices(): + print('CONNECT: %s' % dev) + + if dev.capabilities & CAPABILITY.CBOR: + ctap2 = CTAP2(dev) + info = ctap2.get_info() + print('DEVICE INFO: %s' % info) + else: + print('Device does not support CBOR') + + if dev.capabilities & CAPABILITY.WINK: + dev.wink() + print('WINK sent!') + else: + print('Device does not support WINK') diff --git a/fido_host/__init__.py b/fido_host/__init__.py new file mode 100644 index 0000000..a711356 --- /dev/null +++ b/fido_host/__init__.py @@ -0,0 +1,28 @@ +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +__version__ = '0.1.0' diff --git a/fido_host/cbor.py b/fido_host/cbor.py new file mode 100644 index 0000000..1995ecf --- /dev/null +++ b/fido_host/cbor.py @@ -0,0 +1,167 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +""" +Minimal CBOR implementation supporting a subset of functionality and types +required for FIDO 2 CTAP. +""" + +import struct +import six + + +def dump_int(data, mt=0): + if data < 0: + mt = 1 + data = -1 - data + + mt = mt << 5 + if data <= 23: + args = ('>B', mt | data) + elif data <= 0xff: + args = ('>BB', mt | 24, data) + elif data <= 0xffff: + args = ('>BH', mt | 25, data) + elif data <= 0xffffffff: + args = ('>BI', mt | 26, data) + else: + args = ('>BQ', mt | 27, data) + return struct.pack(*args) + + +def dump_bool(data): + return b'\xf5' if data else b'\xf4' + + +def dump_list(data): + return dump_int(len(data), mt=4) + b''.join([dumps(x) for x in data]) + + +def _sort_keys(entry): + key = entry[0] + return (six.indexbytes(key, 0), len(key), key) + + +def dump_dict(data): + items = [(dumps(k), dumps(v)) for k, v in data.items()] + items.sort(key=_sort_keys) + return dump_int(len(items), mt=5) + b''.join([k+v for (k, v) in items]) + + +def dump_bytes(data): + return dump_int(len(data), mt=2) + data + + +def dump_text(data): + data = data.encode('utf8') + return dump_int(len(data), mt=3) + data + + +_SERIALIZERS = [ + (bool, dump_bool), + (six.integer_types, dump_int), + (dict, dump_dict), + (list, dump_list), + (six.text_type, dump_text), + (six.binary_type, dump_bytes) +] + + +def dumps(data): + for k, v in _SERIALIZERS: + if isinstance(data, k): + return v(data) + raise ValueError('Unsupported value: {}'.format(data)) + + +def load_int(ai, data): + if ai < 24: + return ai, data + elif ai == 24: + return six.indexbytes(data, 0), data[1:] + elif ai == 25: + return struct.unpack_from('>H', data)[0], data[2:] + elif ai == 26: + return struct.unpack_from('>I', data)[0], data[4:] + elif ai == 27: + return struct.unpack_from('>Q', data)[0], data[8:] + raise ValueError('Invalid additional information') + + +def load_nint(ai, data): + val, rest = load_int(ai, data) + return -1 - val, rest + + +def load_bool(ai, data): + return ai == 21, data + + +def load_bytes(ai, data): + l, data = load_int(ai, data) + return data[:l], data[l:] + + +def load_text(ai, data): + enc, rest = load_bytes(ai, data) + return enc.decode('utf8'), rest + + +def load_array(ai, data): + l, data = load_int(ai, data) + values = [] + for i in range(l): + val, data = loads(data) + values.append(val) + return values, data + + +def load_map(ai, data): + l, data = load_int(ai, data) + values = {} + for i in range(l): + k, data = loads(data) + v, data = loads(data) + values[k] = v + return values, data + + +_DESERIALIZERS = { + 0: load_int, + 1: load_nint, + 2: load_bytes, + 3: load_text, + 4: load_array, + 5: load_map, + 7: load_bool +} + + +def loads(data): + fb = six.indexbytes(data, 0) + return _DESERIALIZERS[fb >> 5](fb & 0b11111, data[1:]) diff --git a/fido_host/client.py b/fido_host/client.py new file mode 100644 index 0000000..1d1ce32 --- /dev/null +++ b/fido_host/client.py @@ -0,0 +1,377 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from __future__ import absolute_import + +from .hid import CtapError +from .u2f import CTAP1, APDU, ApduError +from .fido2 import (CTAP2, PinProtocolV1, AttestedCredentialData, + AuthenticatorData, AttestationObject, AssertionResponse) +from .rpid import verify_rp_id, verify_app_id +from .utils import Timeout, sha256, hmac_sha256, websafe_decode, websafe_encode +from enum import IntEnum, unique +import json + + +class ClientData(bytes): + def __init__(self, data): + self.data = json.loads(data.decode()) + self.origin = self.data['origin'] + + @property + def b64(self): + return websafe_encode(self) + + @property + def hash(self): + return sha256(self) + + @classmethod + def build(cls, **kwargs): + return cls(json.dumps(kwargs).encode()) + + @classmethod + def from_b64(cls, data): + return cls(websafe_decode(data)) + + def __repr__(self): + return self.decode() + + def __str__(self): + return self.decode() + + +class ClientError(Exception): + + @unique + class ERR(IntEnum): + OTHER_ERROR = 1 + BAD_REQUEST = 2 + CONFIGURATION_UNSUPPORTED = 3 + DEVICE_INELIGIBLE = 4 + TIMEOUT = 5 + + def __call__(self): + return ClientError(self) + + def __init__(self, code): + self.code = ClientError.ERR(code) + + def __repr__(self): + return 'U2F Client error: {0} - {0.name}'.format(self.code) + + +def _call_polling(poll_delay, timeout, func, *args, **kwargs): + with Timeout(timeout or 30) as event: + while not event.is_set(): + try: + return func(*args, **kwargs) + except ApduError as e: + if e.code == APDU.USE_NOT_SATISFIED: + event.wait(poll_delay) + else: + raise + raise ClientError.ERR.TIMEOUT() + + +class U2fClient(object): + def __init__(self, device, origin, verify=verify_app_id): + self.poll_delay = 0.25 + self.ctap = CTAP1(device) + self.origin = origin + self._verify = verify_app_id + + def _verify_app_id(self, app_id): + try: + if self._verify(app_id, self.origin): + return + except Exception: + pass # Fall through to ClientError + raise ClientError.ERR.BAD_REQUEST() + + def register(self, app_id, register_requests, registered_keys, + timeout=None): + self._verify_app_id(app_id) + + version = self.ctap.get_version() + dummy_param = b'\0'*32 + for key in registered_keys: + if key['version'] != version: + continue + key_app_id = key.get('appId', app_id) + app_param = sha256(key_app_id.encode()) + self._verify_app_id(key_app_id) + key_handle = websafe_decode(key['keyHandle']) + try: + self.ctap.authenticate(dummy_param, app_param, key_handle, True) + raise ClientError.ERR.DEVICE_INELIGIBLE() # Bad response + except ApduError as e: + if e.code == APDU.USE_NOT_SATISFIED: + raise ClientError.ERR.DEVICE_INELIGIBLE() + + for request in register_requests: + if request['version'] == version: + challenge = request['challenge'] + break + else: + raise ClientError.ERR.DEVICE_INELIGIBLE() + + client_data = ClientData.build( + typ='navigator.id.finishEnrollment', + challenge=challenge, + origin=self.origin + ) + app_param = sha256(app_id.encode()) + + reg_data = _call_polling(self.poll_delay, timeout, self.ctap.register, + client_data.hash, app_param) + return { + 'registrationData': reg_data.b64, + 'clientData': client_data.b64 + } + + def sign(self, app_id, challenge, registered_keys, timeout=None): + client_data = ClientData.build( + typ='navigator.id.getAssertion', + challenge=challenge, + origin=self.origin + ) + + version = self.ctap.get_version() + for key in registered_keys: + if key['version'] == version: + key_app_id = key.get('appId', app_id) + self._verify_app_id(key_app_id) + key_handle = websafe_decode(key['keyHandle']) + app_param = sha256(key_app_id.encode()) + try: + signature_data = _call_polling( + self.poll_delay, timeout, self.ctap.authenticate, + client_data.hash, app_param, key_handle) + break + except ApduError: + pass # Ignore and try next key + else: + raise ClientError.ERR.DEVICE_INELIGIBLE() + + return { + 'clientData': client_data.b64, + 'signatureData': signature_data.b64, + 'keyHandle': key['keyHandle'] + } + + +@unique +class CRED_ALGO(IntEnum): + ES256 = -7 + RS256 = -257 + + +class Fido2Client(object): + def __init__(self, device, origin, verify=verify_rp_id): + self.ctap1_poll_delay = 0.25 + self.origin = origin + self._verify = verify + try: + self.ctap = CTAP2(device) + self.pin_protocol = PinProtocolV1(self.ctap) + self._do_make_credential = self._ctap2_make_credential + self._do_get_assertion = self._ctap2_get_assertion + except ValueError: + self.ctap = CTAP1(device) + self._do_make_credential = self._ctap1_make_credential + self._do_get_assertion = self._ctap1_get_assertion + + def _verify_rp_id(self, rp_id): + try: + if self._verify(rp_id, self.origin): + return + except Exception: + pass # Fall through to ClientError + raise ClientError.ERR.BAD_REQUEST() + + def make_credential(self, rp, user, challenge, algos=[CRED_ALGO.ES256], + exclude_list=None, extensions=None, rk=False, uv=False, + pin=None, timeout=None): + self._verify_rp_id(rp['id']) + + client_data = ClientData.build( + type='webauthn.create', + clientExtensions={}, + challenge=challenge, + origin=self.origin + ) + + attestation = self._do_make_credential( + client_data, rp, user, algos, exclude_list, extensions, rk, uv, pin, + timeout) + return attestation, client_data + + def _ctap2_make_credential(self, client_data, rp, user, algos, exclude_list, + extensions, rk, uv, pin, timeout): + key_params = [{'type': 'public-key', 'alg': alg} for alg in algos] + + info = self.ctap.get_info() + pin_auth = None + pin_protocol = None + if pin: + pin_protocol = self.pin_protocol.VERSION + if pin_protocol not in info.pin_protocols: + raise ValueError('Device does not support PIN protocol 1!') + pin_token = self.pin_protocol.get_pin_token(pin) + pin_auth = hmac_sha256(pin_token, client_data.hash)[:16] + elif info.options.get('clientPin'): + raise ValueError('PIN required!') + + if not (rk or uv): + options = None + else: + options = {} + if rk: + options['rk'] = True + if uv: + options['uv'] = True + + return self.ctap.make_credential(client_data.hash, rp, user, + key_params, exclude_list, + extensions, options, pin_auth, + pin_protocol, timeout) + + def _ctap1_make_credential(self, client_data, rp, user, algos, exclude_list, + extensions, rk, uv, pin, timeout): + if rk or uv: + raise CtapError(CtapError.ERR.UNSUPPORTED_OPTION) + + app_param = sha256(rp['id'].encode()) + + dummy_param = b'\0'*32 + for cred in exclude_list or []: + key_handle = cred['id'] + try: + self.ctap.authenticate(dummy_param, app_param, key_handle, True) + raise CtapError(CtapError.ERR.CREDENTIAL_EXCLUDED) # Invalid + except ApduError as e: + if e.code == APDU.USE_NOT_SATISFIED: + raise CtapError(CtapError.ERR.CREDENTIAL_EXCLUDED) + + reg_resp = _call_polling(self.ctap1_poll_delay, timeout, + self.ctap.register, client_data.hash, + app_param) + + return AttestationObject.create( + 'fido-u2f', + AuthenticatorData.create( + app_param, + 0x41, + 0, + AttestedCredentialData.create( + b'\0'*16, # aaguid + reg_resp.key_handle, + { # EC256 public key + 1: 2, + 3: -7, + -1: 1, + -2: reg_resp.public_key[1:1+32], + -3: reg_resp.public_key[33:33+32] + } + ) + ), + { # att_statement + 'x5c': [reg_resp.certificate], + 'sig': reg_resp.signature + } + ) + + def get_assertion(self, rp_id, challenge, allow_list=None, extensions=None, + rk=False, uv=False, pin=None, timeout=None): + self._verify_rp_id(rp_id) + + client_data = ClientData.build( + type='webauthn.get', + clientExtensions={}, + challenge=challenge, + origin=self.origin + ) + + assertions = self._do_get_assertion( + client_data, rp_id, allow_list, extensions, rk, uv, pin, timeout) + return assertions, client_data + + def _ctap2_get_assertion(self, client_data, rp_id, allow_list, extensions, + rk, uv, pin, timeout): + info = self.ctap.get_info() + pin_auth = None + pin_protocol = None + if pin: + pin_protocol = self.pin_protocol.VERSION + if pin_protocol not in info.pin_protocols: + raise ValueError('Device does not support PIN protocol 1!') + pin_token = self.pin_protocol.get_pin_token(pin) + pin_auth = hmac_sha256(pin_token, client_data.hash)[:16] + elif info.options.get('clientPin'): + raise ValueError('PIN required!') + + if not (rk or uv): + options = None + else: + options = {} + if rk: + options['rk'] = True + if uv: + options['uv'] = True + + assertions = [self.ctap.get_assertion(rp_id, client_data.hash, + allow_list, extensions, options, + pin_auth, pin_protocol, timeout)] + for _ in range((assertions[0].number_of_credentials or 1) - 1): + assertions.append(self.ctap.get_next_assertion()) + return assertions + + def _ctap1_get_assertion(self, client_data, rp_id, allow_list, extensions, + rk, uv, pin, timeout): + if rk or uv or not allow_list: + raise CtapError(CtapError.ERR.UNSUPPORTED_OPTION) + + app_param = sha256(rp_id.encode()) + client_param = client_data.hash + for cred in allow_list: + try: + auth_resp = _call_polling(self.ctap1_poll_delay, timeout, + self.ctap.authenticate, client_param, + app_param, cred['id']) + return [AssertionResponse.create( + cred, + AuthenticatorData.create( + app_param, + auth_resp.user_presence & 0x01, + auth_resp.counter + ), + auth_resp.signature + )] + except ApduError as e: + pass # Ignore this handle + raise CtapError(CtapError.ERR.NO_CREDENTIALS) diff --git a/fido_host/ctap.py b/fido_host/ctap.py new file mode 100644 index 0000000..1da3be9 --- /dev/null +++ b/fido_host/ctap.py @@ -0,0 +1,61 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import abc +import six + + +if six.PY2: + @six.add_metaclass(abc.ABCMeta) + class ABC(object): + pass + abc.ABC = ABC + abc.abstractclassmethod = abc.abstractmethod + + +class CtapDevice(abc.ABC): + """ + CTAP-capable device. Subclasses of this should implement call, as well as + list_devices, which should return a generator over discoverable devices. + """ + + @abc.abstractmethod + def call(self, cmd, data=b'', event=None): + """ + cmd is the integer value of the command. + data is the binary string value of the payload. + event is an instance of threading.Event which can be used to cancel the + invocation. + """ + pass + + @abc.abstractclassmethod + def list_devices(cls): + """ + Generates instances of cls for discoverable devices. + """ + pass diff --git a/fido_host/fido2.py b/fido_host/fido2.py new file mode 100644 index 0000000..78541f9 --- /dev/null +++ b/fido_host/fido2.py @@ -0,0 +1,443 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from __future__ import absolute_import + +from . import cbor +from .hid import CTAPHID, CAPABILITY, CtapError +from .utils import Timeout, sha256, hmac_sha256 + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + +from binascii import b2a_hex, a2b_hex +from enum import IntEnum, unique +import struct +import six + + +def args(*args): + """ + Constructs a dict from a list of arguments for sending a CBOR command. + """ + if args: + return dict((i, v) for i, v in enumerate(args, 1) if v is not None) + return None + + +def hexstr(bs): + return "h'%s'" % b2a_hex(bs).decode() + + +def _parse_cbor(data): + resp, rest = cbor.loads(data) + if rest: + raise ValueError('Extraneous data') + return resp + + +class Info(bytes): + @unique + class KEY(IntEnum): + VERSIONS = 1 + EXTENSIONS = 2 + AAGUID = 3 + OPTIONS = 4 + MAX_MSG_SIZE = 5 + PIN_PROTOCOLS = 6 + + def __init__(self, data): + data = dict((Info.KEY(k), v) for (k, v) in _parse_cbor(data).items()) + self.versions = data[Info.KEY.VERSIONS] + self.extensions = data.get(Info.KEY.EXTENSIONS, []) + self.aaguid = data[Info.KEY.AAGUID] + self.options = data.get(Info.KEY.OPTIONS, {}) + self.max_msg_size = data.get(Info.KEY.MAX_MSG_SIZE) + self.pin_protocols = data.get(Info.KEY.PIN_PROTOCOLS, []) + self.data = data + + def __repr__(self): + r = 'Info(versions: %r' % self.versions + if self.extensions: + r += ', extensions: %r' % self.extensions + r += ', aaguid: %s' % hexstr(self.aaguid) + if self.options: + r += ', options: %r' % self.options + r += ', max_message_size: %d' % self.max_msg_size + if self.pin_protocols: + r += ', pin_protocols: %r' % self.pin_protocols + return r + ')' + + def __str__(self): + return self.__repr__() + + +class AttestedCredentialData(bytes): + + def __init__(self, _): + self.aaguid, self.credential_id, self.public_key, rest = \ + AttestedCredentialData.parse(self) + if rest: + raise ValueError('Wrong length') + + def __repr__(self): + return ('AttestedCredentialData(aaguid: %s, credential_id: %s, ' + 'public_key: %s') % (hexstr(self.aaguid), + hexstr(self.credential_id), + self.public_key) + + def __str__(self): + return self.__repr__() + + @staticmethod + def parse(data): + aaguid = data[:16] + c_len = struct.unpack('>H', data[16:18])[0] + cred_id = data[18:18+c_len] + pub_key, rest = cbor.loads(data[18+c_len:]) + return aaguid, cred_id, pub_key, rest + + @classmethod + def create(cls, aaguid, credential_id, public_key): + return cls(aaguid + struct.pack('>H', len(credential_id)) + + credential_id + cbor.dumps(public_key)) + + @classmethod + def unpack_from(cls, data): + args = cls.parse(data) + return cls.create(*args[:-1]), args[-1] + + +class AuthenticatorData(bytes): + @unique + class FLAG(IntEnum): + UP = 0x01 + UV = 0x04 + AT = 0x40 + ED = 0x80 + + def __init__(self, data): + self.rp_id_hash = self[:32] + self.flags, self.counter = struct.unpack('>BI', self[32:32+5]) + rest = self[37:] + + if self.flags & AuthenticatorData.FLAG.AT: + self.credential_data, rest = \ + AttestedCredentialData.unpack_from(self[37:]) + else: + self.credential_data = None + + if self.flags & AuthenticatorData.FLAG.ED: + self.extensions, rest = cbor.loads(rest) + else: + self.extensions = None + + if rest: + raise ValueError('Wrong length') + + @classmethod + def create(cls, rp_id_hash, flags, counter, credential_data=b'', + extensions=None): + return cls( + rp_id_hash + struct.pack('>BI', flags, counter) + credential_data + + (cbor.dumps(extensions) if extensions is not None else b'') + ) + + def __repr__(self): + r = 'AuthenticatorData(rp_id_hash: %s, flags: 0x%02x, counter: %d' %\ + (hexstr(self.rp_id_hash), self.flags, self.counter) + if self.credential_data: + r += ', credential_data: %s' % self.credential_data + if self.extensions: + r += ', extensions: %s' % self.extensions + return r + ')' + + def __str__(self): + return self.__repr__() + + +class AttestationObject(bytes): + @unique + class KEY(IntEnum): + FMT = 1 + AUTH_DATA = 2 + ATT_STMT = 3 + + def __init__(self, data): + data = dict((AttestationObject.KEY(k), v) for (k, v) in + _parse_cbor(data).items()) + self.fmt = data[AttestationObject.KEY.FMT] + self.auth_data = AuthenticatorData( + data[AttestationObject.KEY.AUTH_DATA]) + data[AttestationObject.KEY.AUTH_DATA] = self.auth_data + self.att_statement = data[AttestationObject.KEY.ATT_STMT] + self.data = data + + def __repr__(self): + return 'AttestationObject(fmt: %r, auth_data: %r, att_statement: %r)' %\ + (self.fmt, self.auth_data, self.att_statement) + + def __str__(self): + return self.__repr__() + + @classmethod + def create(cls, fmt, auth_data, att_stmt): + return cls(cbor.dumps(args(fmt, auth_data, att_stmt))) + + +class AssertionResponse(bytes): + @unique + class KEY(IntEnum): + CREDENTIAL = 1 + AUTH_DATA = 2 + SIGNATURE = 3 + USER = 4 + N_CREDS = 5 + + def __init__(self, data): + data = dict((AssertionResponse.KEY(k), v) for (k, v) in + _parse_cbor(data).items()) + self.credential = data[AssertionResponse.KEY.CREDENTIAL] + self.auth_data = AuthenticatorData( + data[AssertionResponse.KEY.AUTH_DATA]) + self.signature = data[AssertionResponse.KEY.SIGNATURE] + self.user = data.get(AssertionResponse.KEY.USER) + self.number_of_credentials = data.get(AssertionResponse.KEY.N_CREDS) + self.data = data + + def __repr__(self): + r = 'AssertionResponse(credential: %r, auth_data: %r, signature: %r' %\ + (self.credential, self.auth_data, hexstr(self.signature)) + if self.user: + r += ', user: %s' % self.user + if self.number_of_credentials is not None: + r += ', number_of_credentials: %d' % self.number_of_credentials + return r + ')' + + def __str__(self): + return self.__repr__() + + @classmethod + def create(cls, credential, auth_data, signature, user=None, n_creds=None): + return cls(cbor.dumps(args(credential, auth_data, signature, user, + n_creds))) + + +class CTAP2(object): + @unique + class CMD(IntEnum): + MAKE_CREDENTIAL = 0x01 + GET_ASSERTION = 0x02 + GET_INFO = 0x04 + CLIENT_PIN = 0x06 + RESET = 0x07 + GET_NEXT_ASSERTION = 0x08 + + def __init__(self, device): + if not device.capabilities & CAPABILITY.CBOR: + raise ValueError('Device does not support CTAP2.') + self.device = device + + def send_cbor(self, cmd, data=None, timeout=None, parse=_parse_cbor): + """ + Sends a CBOR message to the device, and waits for a response. + The optional parameter 'timeout' can either be a numeric time in seconds + or a threading.Event object used to cancel the request. + """ + request = struct.pack('>B', cmd) + if data is not None: + request += cbor.dumps(data) + with Timeout(timeout) as event: + response = self.device.call(CTAPHID.CBOR, request, event) + status = six.indexbytes(response, 0) + if status != 0x00: + raise CtapError(status) + if len(response) == 1: + return None + return parse(response[1:]) + + def make_credential(self, client_data_hash, rp, user, key_params, + exclude_list=None, extensions=None, options=None, + pin_auth=None, pin_protocol=None, timeout=None): + return self.send_cbor(CTAP2.CMD.MAKE_CREDENTIAL, args( + client_data_hash, + rp, + user, + key_params, + exclude_list, + extensions, + options, + pin_auth, + pin_protocol + ), timeout, AttestationObject) + + def get_assertion(self, rp_id, client_data_hash, allow_list=None, + extensions=None, options=None, pin_auth=None, + pin_protocol=None, timeout=None): + return self.send_cbor(CTAP2.CMD.GET_ASSERTION, args( + rp_id, + client_data_hash, + allow_list, + extensions, + options, + pin_auth, + pin_protocol + ), timeout, AssertionResponse) + + def get_info(self): + return self.send_cbor(CTAP2.CMD.GET_INFO, parse=Info) + + def client_pin(self, pin_protocol, sub_cmd, key_agreement=None, + pin_auth=None, new_pin_enc=None, pin_hash_enc=None): + return self.send_cbor(CTAP2.CMD.CLIENT_PIN, args( + pin_protocol, + sub_cmd, + key_agreement, + pin_auth, + new_pin_enc, + pin_hash_enc + )) + + def reset(self, timeout=None): + self.send_cbor(CTAP2.CMD.RESET, timeout) + + def get_next_assertion(self): + return self.send_cbor(CTAP2.CMD.GET_NEXT_ASSERTION, + parse=AssertionResponse) + + +def _pad_pin(pin): + if not isinstance(pin, six.string_types): + raise ValueError('PIN of wrong type, expecting %s' % six.string_types) + if len(pin) < 4: + raise ValueError('PIN must be >= 4 characters') + pin = pin.encode('utf8').ljust(64, b'\0') + pin += b'\0' * (-(len(pin) - 16) % 16) + if len(pin) > 255: + raise ValueError('PIN must be <= 255 bytes') + return pin + + +class PinProtocolV1(object): + VERSION = 1 + IV = b'\x00' * 16 + + @unique + class CMD(IntEnum): + GET_RETRIES = 0x01 + GET_KEY_AGREEMENT = 0x02 + SET_PIN = 0x03 + CHANGE_PIN = 0x04 + GET_PIN_TOKEN = 0x05 + + @unique + class RESULT(IntEnum): + KEY_AGREEMENT = 0x01 + PIN_TOKEN = 0x02 + RETRIES = 0x03 + + def __init__(self, ctap): + self.ctap = ctap + + def _init_shared_secret(self): + be = default_backend() + sk = ec.generate_private_key(ec.SECP256R1(), be) + pk = sk.public_key().public_numbers() + key_agreement = { + 1: 2, + 3: -15, + -1: 1, + -2: a2b_hex('%064x' % pk.x), + -3: a2b_hex('%064x' % pk.y) + } + + resp = self.ctap.client_pin(PinProtocolV1.VERSION, + PinProtocolV1.CMD.GET_KEY_AGREEMENT) + pk = resp[PinProtocolV1.RESULT.KEY_AGREEMENT] + x = int(b2a_hex(pk[-2]), 16) + y = int(b2a_hex(pk[-3]), 16) + pk = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1()).public_key(be) + shared_secret = sha256(sk.exchange(ec.ECDH(), pk)) + return key_agreement, shared_secret + + def get_pin_token(self, pin): + key_agreement, shared_secret = self._init_shared_secret() + + be = default_backend() + cipher = Cipher(algorithms.AES(shared_secret), + modes.CBC(PinProtocolV1.IV), be) + pin_hash = sha256(pin.encode())[:16] + enc = cipher.encryptor() + pin_hash_enc = enc.update(pin_hash) + enc.finalize() + + resp = self.ctap.client_pin(PinProtocolV1.VERSION, + PinProtocolV1.CMD.GET_PIN_TOKEN, + key_agreement=key_agreement, + pin_hash_enc=pin_hash_enc) + dec = cipher.decryptor() + return dec.update(resp[PinProtocolV1.RESULT.PIN_TOKEN]) + dec.finalize() + + def get_pin_retries(self): + resp = self.ctap.client_pin(PinProtocolV1.VERSION, + PinProtocolV1.CMD.GET_RETRIES) + return resp[PinProtocolV1.RESULT.RETRIES] + + def set_pin(self, pin): + pin = _pad_pin(pin) + key_agreement, shared_secret = self._init_shared_secret() + + be = default_backend() + cipher = Cipher(algorithms.AES(shared_secret), + modes.CBC(PinProtocolV1.IV), be) + enc = cipher.encryptor() + pin_enc = enc.update(pin) + enc.finalize() + pin_auth = hmac_sha256(shared_secret, pin_enc)[:16] + self.ctap.client_pin(PinProtocolV1.VERSION, PinProtocolV1.CMD.SET_PIN, + key_agreement=key_agreement, + new_pin_enc=pin_enc, + pin_auth=pin_auth) + + def change_pin(self, old_pin, new_pin): + new_pin = _pad_pin(new_pin) + key_agreement, shared_secret = self._init_shared_secret() + + be = default_backend() + cipher = Cipher(algorithms.AES(shared_secret), + modes.CBC(PinProtocolV1.IV), be) + pin_hash = sha256(old_pin.encode())[:16] + enc = cipher.encryptor() + pin_hash_enc = enc.update(pin_hash) + enc.finalize() + enc = cipher.encryptor() + new_pin_enc = enc.update(new_pin) + enc.finalize() + pin_auth = hmac_sha256(shared_secret, new_pin_enc + pin_hash_enc)[:16] + self.ctap.client_pin(PinProtocolV1.VERSION, + PinProtocolV1.CMD.CHANGE_PIN, + key_agreement=key_agreement, + pin_hash_enc=pin_hash_enc, + new_pin_enc=new_pin_enc, + pin_auth=pin_auth) diff --git a/fido_host/hid.py b/fido_host/hid.py new file mode 100644 index 0000000..32cb4a7 --- /dev/null +++ b/fido_host/hid.py @@ -0,0 +1,178 @@ + +from __future__ import absolute_import + +from .ctap import CtapDevice +from .pyu2f import hidtransport + +from enum import IntEnum, unique +from threading import Event +import struct + + +@unique +class CTAPHID(IntEnum): + PING = 0x01 + MSG = 0x03 + LOCK = 0x04 + INIT = 0x06 + WINK = 0x08 + CBOR = 0x10 + CANCEL = 0x11 + + ERROR = 0x3f + KEEPALIVE = 0x3b + + VENDOR_FIRST = 0x40 + + +@unique +class CAPABILITY(IntEnum): + WINK = 0x01 + LOCK = 0x02 # Not used + CBOR = 0x04 + NMSG = 0x08 + + def supported(self, flags): + return bool(flags & self) + + +TYPE_INIT = 0x80 + + +class CtapError(Exception): + @unique + class ERR(IntEnum): + SUCCESS = 0x00 + INVALID_COMMAND = 0x01 + INVALID_PARAMETER = 0x02 + INVALID_LENGTH = 0x03 + INVALID_SEQ = 0x04 + TIMEOUT = 0x05 + CHANNEL_BUSY = 0x06 + LOCK_REQUIRED = 0x0A + INVALID_CHANNEL = 0x0B + CBOR_UNEXPECTED_TYPE = 0x11 + INVALID_CBOR = 0x12 + MISSING_PARAMETER = 0x14 + LIMIT_EXCEEDED = 0x15 + UNSUPPORTED_EXTENSION = 0x16 + CREDENTIAL_EXCLUDED = 0x19 + PROCESSING = 0x21 + INVALID_CREDENTIAL = 0x22 + USER_ACTION_PENDING = 0x23 + OPERATION_PENDING = 0x24 + NO_OPERATIONS = 0x25 + UNSUPPORTED_ALGORITHM = 0x26 + OPERATION_DENIED = 0x27 + KEY_STORE_FULL = 0x28 + NOT_BUSY = 0x29 + NO_OPERATION_PENDING = 0x2A + UNSUPPORTED_OPTION = 0x2B + INVALID_OPTION = 0x2C + KEEPALIVE_CANCEL = 0x2D + NO_CREDENTIALS = 0x2E + USER_ACTION_TIMEOUT = 0x2F + NOT_ALLOWED = 0x30 + PIN_INVALID = 0x31 + PIN_BLOCKED = 0x32 + PIN_AUTH_INVALID = 0x33 + PIN_AUTH_BLOCKED = 0x34 + PIN_NOT_SET = 0x35 + PIN_REQUIRED = 0x36 + PIN_POLICY_VIOLATION = 0x37 + PIN_TOKEN_EXPIRED = 0x38 + REQUEST_TOO_LARGE = 0x39 + ACTION_TIMEOUT = 0x3A + UP_REQUIRED = 0x3B + OTHER = 0x7F + SPEC_LAST = 0xDF + EXTENSION_FIRST = 0xE0 + EXTENSION_LAST = 0xEF + VENDOR_FIRST = 0xF0 + VENDOR_LAST = 0xFF + + def __str__(self): + return '0x%02X - %s' % (self.value, self.name) + + def __init__(self, code): + try: + code = CtapError.ERR(code) + message = 'CTAP error: %s' % code + except ValueError: + message = 'CTAP error: 0x%02X' % code + self.code = code + super(CtapError, self).__init__(message) + + +class _SingleEvent(object): + def __init__(self): + self.flag = False + + def is_set(self): + if not self.flag: + self.flag = True + return False + return True + + +class CtapHidDevice(CtapDevice): + """ + CtapDevice implementation using the HID transport. + """ + + def __init__(self, descriptor, dev): + self.descriptor = descriptor + self._dev = dev + + def __repr__(self): + return 'CtapHidDevice(%s)' % self.descriptor['path'] + + @property + def version(self): + return self._dev.u2fhid_version + + @property + def device_version(self): + return self._dev.device_version + + @property + def capabilities(self): + return self._dev.capabilities + + def call(self, cmd, data=b'', event=None): + event = event or Event() + self._dev.InternalSend(TYPE_INIT | cmd, bytearray(data)) + while not event.is_set(): + status, resp = self._dev.InternalRecv() + status ^= TYPE_INIT + if status == cmd: + return bytes(resp) + elif status == CTAPHID.ERROR: + raise CtapError(resp[0]) + elif status == CTAPHID.KEEPALIVE: + continue + else: + raise CtapError(CtapError.ERR.INVALID_COMMAND) + + self.call(CTAPHID.CANCEL, b'', _SingleEvent()) + raise CtapError(CtapError.ERR.KEEPALIVE_CANCEL) + + def wink(self): + self.call(CTAPHID.WINK) + + def ping(self, msg=b'Hello U2F'): + return self.call(CTAPHID.PING, msg) + + def lock(self, lock_time=10): + self.call(CTAPHID.LOCK, struct.pack('>B', lock_time)) + + @classmethod + def list_devices(cls, selector=hidtransport.HidUsageSelector): + for d in hidtransport.hid.Enumerate(): + if selector(d): + try: + dev = hidtransport.hid.Open(d['path']) + yield cls(d, hidtransport.UsbHidTransport(dev)) + except OSError: + # Insufficient permissions to access device + pass diff --git a/fido_host/public_suffix_list.dat b/fido_host/public_suffix_list.dat new file mode 100644 index 0000000..68a9e8c --- /dev/null +++ b/fido_host/public_suffix_list.dat @@ -0,0 +1,12392 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, +// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. + +// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. + +// ===BEGIN ICANN DOMAINS=== + +// ac : https://en.wikipedia.org/wiki/.ac +ac +com.ac +edu.ac +gov.ac +net.ac +mil.ac +org.ac + +// ad : https://en.wikipedia.org/wiki/.ad +ad +nom.ad + +// ae : https://en.wikipedia.org/wiki/.ae +// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php +ae +co.ae +net.ae +org.ae +sch.ae +ac.ae +gov.ae +mil.ae + +// aero : see https://www.information.aero/index.php?id=66 +aero +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +aircraft.aero +airline.aero +airport.aero +air-surveillance.aero +airtraffic.aero +air-traffic-control.aero +ambulance.aero +amusement.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +freight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : http://www.nic.af/help.jsp +af +gov.af +com.af +org.af +net.af +edu.af + +// ag : http://www.nic.ag/prices.htm +ag +com.ag +org.ag +net.ag +co.ag +nom.ag + +// ai : http://nic.com.ai/ +ai +off.ai +com.ai +net.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : https://en.wikipedia.org/wiki/.am +am + +// ao : https://en.wikipedia.org/wiki/.ao +// http://www.dns.ao/REGISTR.DOC +ao +ed.ao +gv.ao +og.ao +co.ao +pb.ao +it.ao + +// aq : https://en.wikipedia.org/wiki/.aq +aq + +// ar : https://nic.ar/nic-argentina/normativa-vigente +ar +com.ar +edu.ar +gob.ar +gov.ar +int.ar +mil.ar +musica.ar +net.ar +org.ar +tur.ar + +// arpa : https://en.wikipedia.org/wiki/.arpa +// Confirmed by registry 2008-06-18 +arpa +e164.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : https://en.wikipedia.org/wiki/.as +as +gov.as + +// asia : https://en.wikipedia.org/wiki/.asia +asia + +// at : https://en.wikipedia.org/wiki/.at +// Confirmed by registry 2008-06-17 +at +ac.at +co.at +gv.at +or.at + +// au : https://en.wikipedia.org/wiki/.au +// http://www.auda.org.au/ +au +// 2LDs +com.au +net.au +org.au +edu.au +gov.au +asn.au +id.au +// Historic 2LDs (closed to new registration, but sites still exist) +info.au +conf.au +oz.au +// CGDNs - http://www.cgdn.org.au/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au +// 3LDs +act.edu.au +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +// act.gov.au Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au Bug 547985 - Removed at request of +// nt.gov.au Bug 940478 - Removed at request of Greg Connors +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au + +// aw : https://en.wikipedia.org/wiki/.aw +aw +com.aw + +// ax : https://en.wikipedia.org/wiki/.ax +ax + +// az : https://en.wikipedia.org/wiki/.az +az +com.az +net.az +int.az +gov.az +org.az +edu.az +info.az +pp.az +mil.az +name.az +pro.az +biz.az + +// ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf +ba +com.ba +edu.ba +gov.ba +mil.ba +net.ba +org.ba + +// bb : https://en.wikipedia.org/wiki/.bb +bb +biz.bb +co.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb +tv.bb + +// bd : https://en.wikipedia.org/wiki/.bd +*.bd + +// be : https://en.wikipedia.org/wiki/.be +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : https://en.wikipedia.org/wiki/.bf +bf +gov.bf + +// bg : https://en.wikipedia.org/wiki/.bg +// https://www.register.bg/user/static/rules/en/index.html +bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg + +// bh : https://en.wikipedia.org/wiki/.bh +bh +com.bh +edu.bh +net.bh +org.bh +gov.bh + +// bi : https://en.wikipedia.org/wiki/.bi +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : https://en.wikipedia.org/wiki/.biz +biz + +// bj : https://en.wikipedia.org/wiki/.bj +bj +asso.bj +barreau.bj +gouv.bj + +// bm : http://www.bermudanic.bm/dnr-text.txt +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : https://en.wikipedia.org/wiki/.bn +*.bn + +// bo : https://nic.bo/delegacion2015.php#h-1.10 +bo +com.bo +edu.bo +gob.bo +int.bo +org.bo +net.bo +mil.bo +tv.bo +web.bo +// Social Domains +academia.bo +agro.bo +arte.bo +blog.bo +bolivia.bo +ciencia.bo +cooperativa.bo +democracia.bo +deporte.bo +ecologia.bo +economia.bo +empresa.bo +indigena.bo +industria.bo +info.bo +medicina.bo +movimiento.bo +musica.bo +natural.bo +nombre.bo +noticias.bo +patria.bo +politica.bo +profesional.bo +plurinacional.bo +pueblo.bo +revista.bo +salud.bo +tecnologia.bo +tksat.bo +transporte.bo +wiki.bo + +// br : http://registro.br/dominio/categoria.html +// Submitted by registry +br +9guacu.br +abc.br +adm.br +adv.br +agr.br +aju.br +am.br +anani.br +aparecida.br +arq.br +art.br +ato.br +b.br +belem.br +bhz.br +bio.br +blog.br +bmd.br +boavista.br +bsb.br +campinagrande.br +campinas.br +caxias.br +cim.br +cng.br +cnt.br +com.br +contagem.br +coop.br +cri.br +cuiaba.br +curitiba.br +def.br +ecn.br +eco.br +edu.br +emp.br +eng.br +esp.br +etc.br +eti.br +far.br +feira.br +flog.br +floripa.br +fm.br +fnd.br +fortal.br +fot.br +foz.br +fst.br +g12.br +ggf.br +goiania.br +gov.br +// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil +ac.gov.br +al.gov.br +am.gov.br +ap.gov.br +ba.gov.br +ce.gov.br +df.gov.br +es.gov.br +go.gov.br +ma.gov.br +mg.gov.br +ms.gov.br +mt.gov.br +pa.gov.br +pb.gov.br +pe.gov.br +pi.gov.br +pr.gov.br +rj.gov.br +rn.gov.br +ro.gov.br +rr.gov.br +rs.gov.br +sc.gov.br +se.gov.br +sp.gov.br +to.gov.br +gru.br +imb.br +ind.br +inf.br +jab.br +jampa.br +jdf.br +joinville.br +jor.br +jus.br +leg.br +lel.br +londrina.br +macapa.br +maceio.br +manaus.br +maringa.br +mat.br +med.br +mil.br +morena.br +mp.br +mus.br +natal.br +net.br +niteroi.br +*.nom.br +not.br +ntr.br +odo.br +org.br +osasco.br +palmas.br +poa.br +ppg.br +pro.br +psc.br +psi.br +pvh.br +qsl.br +radio.br +rec.br +recife.br +ribeirao.br +rio.br +riobranco.br +riopreto.br +salvador.br +sampa.br +santamaria.br +santoandre.br +saobernardo.br +saogonca.br +sjc.br +slg.br +slz.br +sorocaba.br +srv.br +taxi.br +teo.br +the.br +tmp.br +trd.br +tur.br +tv.br +udi.br +vet.br +vix.br +vlog.br +wiki.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +net.bs +org.bs +edu.bs +gov.bs + +// bt : https://en.wikipedia.org/wiki/.bt +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry +bv + +// bw : https://en.wikipedia.org/wiki/.bw +// http://www.gobin.info/domainname/bw.doc +// list of other 2nd level tlds ? +bw +co.bw +org.bw + +// by : https://en.wikipedia.org/wiki/.by +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by + +// http://hoster.by/ +of.by + +// bz : https://en.wikipedia.org/wiki/.bz +// http://www.belizenic.bz/ +bz +com.bz +net.bz +org.bz +edu.bz +gov.bz + +// ca : https://en.wikipedia.org/wiki/.ca +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: https://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : https://en.wikipedia.org/wiki/.cat +cat + +// cc : https://en.wikipedia.org/wiki/.cc +cc + +// cd : https://en.wikipedia.org/wiki/.cd +// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +cd +gov.cd + +// cf : https://en.wikipedia.org/wiki/.cf +cf + +// cg : https://en.wikipedia.org/wiki/.cg +cg + +// ch : https://en.wikipedia.org/wiki/.ch +ch + +// ci : https://en.wikipedia.org/wiki/.ci +// http://www.nic.ci/index.php?page=charte +ci +org.ci +or.ci +com.ci +co.ci +edu.ci +ed.ci +ac.ci +net.ci +go.ci +asso.ci +aéroport.ci +int.ci +presse.ci +md.ci +gouv.ci + +// ck : https://en.wikipedia.org/wiki/.ck +*.ck +!www.ck + +// cl : https://en.wikipedia.org/wiki/.cl +cl +gov.cl +gob.cl +co.cl +mil.cl + +// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927 +cm +co.cm +com.cm +gov.cm +net.cm + +// cn : https://en.wikipedia.org/wiki/.cn +// Submitted by registry +cn +ac.cn +com.cn +edu.cn +gov.cn +net.cn +org.cn +mil.cn +公司.cn +网络.cn +網絡.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gz.cn +gx.cn +ha.cn +hb.cn +he.cn +hi.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +xj.cn +xz.cn +yn.cn +zj.cn +hk.cn +mo.cn +tw.cn + +// co : https://en.wikipedia.org/wiki/.co +// Submitted by registry +co +arts.co +com.co +edu.co +firm.co +gov.co +info.co +int.co +mil.co +net.co +nom.co +org.co +rec.co +web.co + +// com : https://en.wikipedia.org/wiki/.com +com + +// coop : https://en.wikipedia.org/wiki/.coop +coop + +// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : https://en.wikipedia.org/wiki/.cu +cu +com.cu +edu.cu +org.cu +net.cu +gov.cu +inf.cu + +// cv : https://en.wikipedia.org/wiki/.cv +cv + +// cw : http://www.una.cw/cw_registry/ +// Confirmed by registry 2013-03-26 +cw +com.cw +edu.cw +net.cw +org.cw + +// cx : https://en.wikipedia.org/wiki/.cx +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://www.nic.cy/ +// Submitted by registry Panayiotou Fotia +cy +ac.cy +biz.cy +com.cy +ekloges.cy +gov.cy +ltd.cy +name.cy +net.cy +org.cy +parliament.cy +press.cy +pro.cy +tm.cy + +// cz : https://en.wikipedia.org/wiki/.cz +cz + +// de : https://en.wikipedia.org/wiki/.de +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : https://en.wikipedia.org/wiki/.dj +dj + +// dk : https://en.wikipedia.org/wiki/.dk +// Confirmed by registry 2008-06-17 +dk + +// dm : https://en.wikipedia.org/wiki/.dm +dm +com.dm +net.dm +org.dm +edu.dm +gov.dm + +// do : https://en.wikipedia.org/wiki/.do +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : https://en.wikipedia.org/wiki/.dz +dz +com.dz +org.dz +net.dz +gov.dz +edu.dz +asso.dz +pol.dz +art.dz + +// ec : http://www.nic.ec/reg/paso1.asp +// Submitted by registry +ec +com.ec +info.ec +net.ec +fin.ec +k12.ec +med.ec +pro.ec +org.ec +edu.ec +gov.ec +gob.ec +mil.ec + +// edu : https://en.wikipedia.org/wiki/.edu +edu + +// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +ee +edu.ee +gov.ee +riik.ee +lib.ee +med.ee +com.ee +pri.ee +aip.ee +org.ee +fie.ee + +// eg : https://en.wikipedia.org/wiki/.eg +eg +com.eg +edu.eg +eun.eg +gov.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg + +// er : https://en.wikipedia.org/wiki/.er +*.er + +// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +es +com.es +nom.es +org.es +gob.es +edu.es + +// et : https://en.wikipedia.org/wiki/.et +et +com.et +gov.et +org.et +edu.et +biz.et +name.et +info.et +net.et + +// eu : https://en.wikipedia.org/wiki/.eu +eu + +// fi : https://en.wikipedia.org/wiki/.fi +fi +// aland.fi : https://en.wikipedia.org/wiki/.ax +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +// TODO: Check for updates (expected to be phased out around Q1/2009) +aland.fi + +// fj : https://en.wikipedia.org/wiki/.fj +*.fj + +// fk : https://en.wikipedia.org/wiki/.fk +*.fk + +// fm : https://en.wikipedia.org/wiki/.fm +fm + +// fo : https://en.wikipedia.org/wiki/.fo +fo + +// fr : http://www.afnic.fr/ +// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs +fr +com.fr +asso.fr +nom.fr +prd.fr +presse.fr +tm.fr +// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels +aeroport.fr +assedic.fr +avocat.fr +avoues.fr +cci.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +geometre-expert.fr +gouv.fr +greta.fr +huissier-justice.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// ga : https://en.wikipedia.org/wiki/.ga +ga + +// gb : This registry is effectively dormant +// Submitted by registry +gb + +// gd : https://en.wikipedia.org/wiki/.gd +gd + +// ge : http://www.nic.net.ge/policy_en.pdf +ge +com.ge +edu.ge +gov.ge +org.ge +mil.ge +net.ge +pvt.ge + +// gf : https://en.wikipedia.org/wiki/.gf +gf + +// gg : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +gg +co.gg +net.gg +org.gg + +// gh : https://en.wikipedia.org/wiki/.gh +// see also: http://www.nic.gh/reg_now.php +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +com.gh +edu.gh +gov.gh +org.gh +mil.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +ltd.gi +gov.gi +mod.gi +edu.gi +org.gi + +// gl : https://en.wikipedia.org/wiki/.gl +// http://nic.gl +gl +co.gl +com.gl +edu.gl +net.gl +org.gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry +gn +ac.gn +com.gn +edu.gn +gov.gn +org.gn +net.gn + +// gov : https://en.wikipedia.org/wiki/.gov +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +com.gp +net.gp +mobi.gp +edu.gp +org.gp +asso.gp + +// gq : https://en.wikipedia.org/wiki/.gq +gq + +// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// Submitted by registry +gr +com.gr +edu.gr +net.gr +org.gr +gov.gr + +// gs : https://en.wikipedia.org/wiki/.gs +gs + +// gt : http://www.gt/politicas_de_registro.html +gt +com.gt +edu.gt +gob.gt +ind.gt +mil.gt +net.gt +org.gt + +// gu : http://gadao.gov.gu/registration.txt +*.gu + +// gw : https://en.wikipedia.org/wiki/.gw +gw + +// gy : https://en.wikipedia.org/wiki/.gy +// http://registry.gy/ +gy +co.gy +com.gy +edu.gy +gov.gy +net.gy +org.gy + +// hk : https://www.hkdnr.hk +// Submitted by registry +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +公司.hk +教育.hk +敎育.hk +政府.hk +個人.hk +个人.hk +箇人.hk +網络.hk +网络.hk +组織.hk +網絡.hk +网絡.hk +组织.hk +組織.hk +組织.hk + +// hm : https://en.wikipedia.org/wiki/.hm +hm + +// hn : http://www.nic.hn/politicas/ps02,,05.html +hn +com.hn +edu.hn +org.hn +net.hn +mil.hn +gob.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +iz.hr +from.hr +name.hr +com.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +com.ht +shop.ht +firm.ht +info.ht +adult.ht +net.ht +pro.ht +org.ht +med.ht +art.ht +coop.ht +pol.ht +asso.ht +edu.ht +rel.ht +gouv.ht +perso.ht + +// hu : http://www.domain.hu/domain/English/sld.html +// Confirmed by registry 2008-06-12 +hu +co.hu +info.hu +org.hu +priv.hu +sport.hu +tm.hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +reklam.hu +sex.hu +shop.hu +suli.hu +szex.hu +tozsde.hu +utazas.hu +video.hu + +// id : https://register.pandi.or.id/ +id +ac.id +biz.id +co.id +desa.id +go.id +mil.id +my.id +net.id +or.id +sch.id +web.id + +// ie : https://en.wikipedia.org/wiki/.ie +ie +gov.ie + +// il : http://www.isoc.org.il/domains/ +il +ac.il +co.il +gov.il +idf.il +k12.il +muni.il +net.il +org.il + +// im : https://www.nic.im/ +// Submitted by registry +im +ac.im +co.im +com.im +ltd.co.im +net.im +org.im +plc.co.im +tt.im +tv.im + +// in : https://en.wikipedia.org/wiki/.in +// see also: https://registry.in/Policies +// Please note, that nic.in is not an official eTLD, but used by most +// government institutions. +in +co.in +firm.in +net.in +org.in +gen.in +ind.in +nic.in +ac.in +edu.in +res.in +gov.in +mil.in + +// info : https://en.wikipedia.org/wiki/.info +info + +// int : https://en.wikipedia.org/wiki/.int +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.html +// list of other 2nd level tlds ? +io +com.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +gov.iq +edu.iq +mil.iq +com.iq +org.iq +net.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2008-12-06 +is +net.is +com.is +edu.is +gov.is +org.is +int.is + +// it : https://en.wikipedia.org/wiki/.it +it +gov.it +edu.it +// Reserved geo-names: +// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf +// There is also a list of reserved geo-names corresponding to Italian municipalities +// http://www.nic.it/documenti/appendice-c.pdf, but it is not included here. +// Regions +abr.it +abruzzo.it +aosta-valley.it +aostavalley.it +bas.it +basilicata.it +cal.it +calabria.it +cam.it +campania.it +emilia-romagna.it +emiliaromagna.it +emr.it +friuli-v-giulia.it +friuli-ve-giulia.it +friuli-vegiulia.it +friuli-venezia-giulia.it +friuli-veneziagiulia.it +friuli-vgiulia.it +friuliv-giulia.it +friulive-giulia.it +friulivegiulia.it +friulivenezia-giulia.it +friuliveneziagiulia.it +friulivgiulia.it +fvg.it +laz.it +lazio.it +lig.it +liguria.it +lom.it +lombardia.it +lombardy.it +lucania.it +mar.it +marche.it +mol.it +molise.it +piedmont.it +piemonte.it +pmn.it +pug.it +puglia.it +sar.it +sardegna.it +sardinia.it +sic.it +sicilia.it +sicily.it +taa.it +tos.it +toscana.it +trentino-a-adige.it +trentino-aadige.it +trentino-alto-adige.it +trentino-altoadige.it +trentino-s-tirol.it +trentino-stirol.it +trentino-sud-tirol.it +trentino-sudtirol.it +trentino-sued-tirol.it +trentino-suedtirol.it +trentinoa-adige.it +trentinoaadige.it +trentinoalto-adige.it +trentinoaltoadige.it +trentinos-tirol.it +trentinostirol.it +trentinosud-tirol.it +trentinosudtirol.it +trentinosued-tirol.it +trentinosuedtirol.it +tuscany.it +umb.it +umbria.it +val-d-aosta.it +val-daosta.it +vald-aosta.it +valdaosta.it +valle-aosta.it +valle-d-aosta.it +valle-daosta.it +valleaosta.it +valled-aosta.it +valledaosta.it +vallee-aoste.it +valleeaoste.it +vao.it +vda.it +ven.it +veneto.it +// Provinces +ag.it +agrigento.it +al.it +alessandria.it +alto-adige.it +altoadige.it +an.it +ancona.it +andria-barletta-trani.it +andria-trani-barletta.it +andriabarlettatrani.it +andriatranibarletta.it +ao.it +aosta.it +aoste.it +ap.it +aq.it +aquila.it +ar.it +arezzo.it +ascoli-piceno.it +ascolipiceno.it +asti.it +at.it +av.it +avellino.it +ba.it +balsan.it +bari.it +barletta-trani-andria.it +barlettatraniandria.it +belluno.it +benevento.it +bergamo.it +bg.it +bi.it +biella.it +bl.it +bn.it +bo.it +bologna.it +bolzano.it +bozen.it +br.it +brescia.it +brindisi.it +bs.it +bt.it +bz.it +ca.it +cagliari.it +caltanissetta.it +campidano-medio.it +campidanomedio.it +campobasso.it +carbonia-iglesias.it +carboniaiglesias.it +carrara-massa.it +carraramassa.it +caserta.it +catania.it +catanzaro.it +cb.it +ce.it +cesena-forli.it +cesenaforli.it +ch.it +chieti.it +ci.it +cl.it +cn.it +co.it +como.it +cosenza.it +cr.it +cremona.it +crotone.it +cs.it +ct.it +cuneo.it +cz.it +dell-ogliastra.it +dellogliastra.it +en.it +enna.it +fc.it +fe.it +fermo.it +ferrara.it +fg.it +fi.it +firenze.it +florence.it +fm.it +foggia.it +forli-cesena.it +forlicesena.it +fr.it +frosinone.it +ge.it +genoa.it +genova.it +go.it +gorizia.it +gr.it +grosseto.it +iglesias-carbonia.it +iglesiascarbonia.it +im.it +imperia.it +is.it +isernia.it +kr.it +la-spezia.it +laquila.it +laspezia.it +latina.it +lc.it +le.it +lecce.it +lecco.it +li.it +livorno.it +lo.it +lodi.it +lt.it +lu.it +lucca.it +macerata.it +mantova.it +massa-carrara.it +massacarrara.it +matera.it +mb.it +mc.it +me.it +medio-campidano.it +mediocampidano.it +messina.it +mi.it +milan.it +milano.it +mn.it +mo.it +modena.it +monza-brianza.it +monza-e-della-brianza.it +monza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +ms.it +mt.it +na.it +naples.it +napoli.it +no.it +novara.it +nu.it +nuoro.it +og.it +ogliastra.it +olbia-tempio.it +olbiatempio.it +or.it +oristano.it +ot.it +pa.it +padova.it +padua.it +palermo.it +parma.it +pavia.it +pc.it +pd.it +pe.it +perugia.it +pesaro-urbino.it +pesarourbino.it +pescara.it +pg.it +pi.it +piacenza.it +pisa.it +pistoia.it +pn.it +po.it +pordenone.it +potenza.it +pr.it +prato.it +pt.it +pu.it +pv.it +pz.it +ra.it +ragusa.it +ravenna.it +rc.it +re.it +reggio-calabria.it +reggio-emilia.it +reggiocalabria.it +reggioemilia.it +rg.it +ri.it +rieti.it +rimini.it +rm.it +rn.it +ro.it +roma.it +rome.it +rovigo.it +sa.it +salerno.it +sassari.it +savona.it +si.it +siena.it +siracusa.it +so.it +sondrio.it +sp.it +sr.it +ss.it +suedtirol.it +sv.it +ta.it +taranto.it +te.it +tempio-olbia.it +tempioolbia.it +teramo.it +terni.it +tn.it +to.it +torino.it +tp.it +tr.it +trani-andria-barletta.it +trani-barletta-andria.it +traniandriabarletta.it +tranibarlettaandria.it +trapani.it +trentino.it +trento.it +treviso.it +trieste.it +ts.it +turin.it +tv.it +ud.it +udine.it +urbino-pesaro.it +urbinopesaro.it +va.it +varese.it +vb.it +vc.it +ve.it +venezia.it +venice.it +verbania.it +vercelli.it +verona.it +vi.it +vibo-valentia.it +vibovalentia.it +vicenza.it +viterbo.it +vr.it +vs.it +vt.it +vv.it + +// je : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +je +co.je +net.je +org.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : http://www.dns.jo/Registration_policy.aspx +jo +com.jo +org.jo +net.jo +edu.jo +sch.jo +gov.jo +mil.jo +name.jo + +// jobs : https://en.wikipedia.org/wiki/.jobs +jobs + +// jp : https://en.wikipedia.org/wiki/.jp +// http://jprs.co.jp/en/jpdomain.html +// Submitted by registry +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp prefecture type names +aichi.jp +akita.jp +aomori.jp +chiba.jp +ehime.jp +fukui.jp +fukuoka.jp +fukushima.jp +gifu.jp +gunma.jp +hiroshima.jp +hokkaido.jp +hyogo.jp +ibaraki.jp +ishikawa.jp +iwate.jp +kagawa.jp +kagoshima.jp +kanagawa.jp +kochi.jp +kumamoto.jp +kyoto.jp +mie.jp +miyagi.jp +miyazaki.jp +nagano.jp +nagasaki.jp +nara.jp +niigata.jp +oita.jp +okayama.jp +okinawa.jp +osaka.jp +saga.jp +saitama.jp +shiga.jp +shimane.jp +shizuoka.jp +tochigi.jp +tokushima.jp +tokyo.jp +tottori.jp +toyama.jp +wakayama.jp +yamagata.jp +yamaguchi.jp +yamanashi.jp +栃木.jp +愛知.jp +愛媛.jp +兵庫.jp +熊本.jp +茨城.jp +北海道.jp +千葉.jp +和歌山.jp +長崎.jp +長野.jp +新潟.jp +青森.jp +静岡.jp +東京.jp +石川.jp +埼玉.jp +三重.jp +京都.jp +佐賀.jp +大分.jp +大阪.jp +奈良.jp +宮城.jp +宮崎.jp +富山.jp +山口.jp +山形.jp +山梨.jp +岩手.jp +岐阜.jp +岡山.jp +島根.jp +広島.jp +徳島.jp +沖縄.jp +滋賀.jp +神奈川.jp +福井.jp +福岡.jp +福島.jp +秋田.jp +群馬.jp +香川.jp +高知.jp +鳥取.jp +鹿児島.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +*.kawasaki.jp +*.kitakyushu.jp +*.kobe.jp +*.nagoya.jp +*.sapporo.jp +*.sendai.jp +*.yokohama.jp +!city.kawasaki.jp +!city.kitakyushu.jp +!city.kobe.jp +!city.nagoya.jp +!city.sapporo.jp +!city.sendai.jp +!city.yokohama.jp +// 4th level registration +aisai.aichi.jp +ama.aichi.jp +anjo.aichi.jp +asuke.aichi.jp +chiryu.aichi.jp +chita.aichi.jp +fuso.aichi.jp +gamagori.aichi.jp +handa.aichi.jp +hazu.aichi.jp +hekinan.aichi.jp +higashiura.aichi.jp +ichinomiya.aichi.jp +inazawa.aichi.jp +inuyama.aichi.jp +isshiki.aichi.jp +iwakura.aichi.jp +kanie.aichi.jp +kariya.aichi.jp +kasugai.aichi.jp +kira.aichi.jp +kiyosu.aichi.jp +komaki.aichi.jp +konan.aichi.jp +kota.aichi.jp +mihama.aichi.jp +miyoshi.aichi.jp +nishio.aichi.jp +nisshin.aichi.jp +obu.aichi.jp +oguchi.aichi.jp +oharu.aichi.jp +okazaki.aichi.jp +owariasahi.aichi.jp +seto.aichi.jp +shikatsu.aichi.jp +shinshiro.aichi.jp +shitara.aichi.jp +tahara.aichi.jp +takahama.aichi.jp +tobishima.aichi.jp +toei.aichi.jp +togo.aichi.jp +tokai.aichi.jp +tokoname.aichi.jp +toyoake.aichi.jp +toyohashi.aichi.jp +toyokawa.aichi.jp +toyone.aichi.jp +toyota.aichi.jp +tsushima.aichi.jp +yatomi.aichi.jp +akita.akita.jp +daisen.akita.jp +fujisato.akita.jp +gojome.akita.jp +hachirogata.akita.jp +happou.akita.jp +higashinaruse.akita.jp +honjo.akita.jp +honjyo.akita.jp +ikawa.akita.jp +kamikoani.akita.jp +kamioka.akita.jp +katagami.akita.jp +kazuno.akita.jp +kitaakita.akita.jp +kosaka.akita.jp +kyowa.akita.jp +misato.akita.jp +mitane.akita.jp +moriyoshi.akita.jp +nikaho.akita.jp +noshiro.akita.jp +odate.akita.jp +oga.akita.jp +ogata.akita.jp +semboku.akita.jp +yokote.akita.jp +yurihonjo.akita.jp +aomori.aomori.jp +gonohe.aomori.jp +hachinohe.aomori.jp +hashikami.aomori.jp +hiranai.aomori.jp +hirosaki.aomori.jp +itayanagi.aomori.jp +kuroishi.aomori.jp +misawa.aomori.jp +mutsu.aomori.jp +nakadomari.aomori.jp +noheji.aomori.jp +oirase.aomori.jp +owani.aomori.jp +rokunohe.aomori.jp +sannohe.aomori.jp +shichinohe.aomori.jp +shingo.aomori.jp +takko.aomori.jp +towada.aomori.jp +tsugaru.aomori.jp +tsuruta.aomori.jp +abiko.chiba.jp +asahi.chiba.jp +chonan.chiba.jp +chosei.chiba.jp +choshi.chiba.jp +chuo.chiba.jp +funabashi.chiba.jp +futtsu.chiba.jp +hanamigawa.chiba.jp +ichihara.chiba.jp +ichikawa.chiba.jp +ichinomiya.chiba.jp +inzai.chiba.jp +isumi.chiba.jp +kamagaya.chiba.jp +kamogawa.chiba.jp +kashiwa.chiba.jp +katori.chiba.jp +katsuura.chiba.jp +kimitsu.chiba.jp +kisarazu.chiba.jp +kozaki.chiba.jp +kujukuri.chiba.jp +kyonan.chiba.jp +matsudo.chiba.jp +midori.chiba.jp +mihama.chiba.jp +minamiboso.chiba.jp +mobara.chiba.jp +mutsuzawa.chiba.jp +nagara.chiba.jp +nagareyama.chiba.jp +narashino.chiba.jp +narita.chiba.jp +noda.chiba.jp +oamishirasato.chiba.jp +omigawa.chiba.jp +onjuku.chiba.jp +otaki.chiba.jp +sakae.chiba.jp +sakura.chiba.jp +shimofusa.chiba.jp +shirako.chiba.jp +shiroi.chiba.jp +shisui.chiba.jp +sodegaura.chiba.jp +sosa.chiba.jp +tako.chiba.jp +tateyama.chiba.jp +togane.chiba.jp +tohnosho.chiba.jp +tomisato.chiba.jp +urayasu.chiba.jp +yachimata.chiba.jp +yachiyo.chiba.jp +yokaichiba.chiba.jp +yokoshibahikari.chiba.jp +yotsukaido.chiba.jp +ainan.ehime.jp +honai.ehime.jp +ikata.ehime.jp +imabari.ehime.jp +iyo.ehime.jp +kamijima.ehime.jp +kihoku.ehime.jp +kumakogen.ehime.jp +masaki.ehime.jp +matsuno.ehime.jp +matsuyama.ehime.jp +namikata.ehime.jp +niihama.ehime.jp +ozu.ehime.jp +saijo.ehime.jp +seiyo.ehime.jp +shikokuchuo.ehime.jp +tobe.ehime.jp +toon.ehime.jp +uchiko.ehime.jp +uwajima.ehime.jp +yawatahama.ehime.jp +echizen.fukui.jp +eiheiji.fukui.jp +fukui.fukui.jp +ikeda.fukui.jp +katsuyama.fukui.jp +mihama.fukui.jp +minamiechizen.fukui.jp +obama.fukui.jp +ohi.fukui.jp +ono.fukui.jp +sabae.fukui.jp +sakai.fukui.jp +takahama.fukui.jp +tsuruga.fukui.jp +wakasa.fukui.jp +ashiya.fukuoka.jp +buzen.fukuoka.jp +chikugo.fukuoka.jp +chikuho.fukuoka.jp +chikujo.fukuoka.jp +chikushino.fukuoka.jp +chikuzen.fukuoka.jp +chuo.fukuoka.jp +dazaifu.fukuoka.jp +fukuchi.fukuoka.jp +hakata.fukuoka.jp +higashi.fukuoka.jp +hirokawa.fukuoka.jp +hisayama.fukuoka.jp +iizuka.fukuoka.jp +inatsuki.fukuoka.jp +kaho.fukuoka.jp +kasuga.fukuoka.jp +kasuya.fukuoka.jp +kawara.fukuoka.jp +keisen.fukuoka.jp +koga.fukuoka.jp +kurate.fukuoka.jp +kurogi.fukuoka.jp +kurume.fukuoka.jp +minami.fukuoka.jp +miyako.fukuoka.jp +miyama.fukuoka.jp +miyawaka.fukuoka.jp +mizumaki.fukuoka.jp +munakata.fukuoka.jp +nakagawa.fukuoka.jp +nakama.fukuoka.jp +nishi.fukuoka.jp +nogata.fukuoka.jp +ogori.fukuoka.jp +okagaki.fukuoka.jp +okawa.fukuoka.jp +oki.fukuoka.jp +omuta.fukuoka.jp +onga.fukuoka.jp +onojo.fukuoka.jp +oto.fukuoka.jp +saigawa.fukuoka.jp +sasaguri.fukuoka.jp +shingu.fukuoka.jp +shinyoshitomi.fukuoka.jp +shonai.fukuoka.jp +soeda.fukuoka.jp +sue.fukuoka.jp +tachiarai.fukuoka.jp +tagawa.fukuoka.jp +takata.fukuoka.jp +toho.fukuoka.jp +toyotsu.fukuoka.jp +tsuiki.fukuoka.jp +ukiha.fukuoka.jp +umi.fukuoka.jp +usui.fukuoka.jp +yamada.fukuoka.jp +yame.fukuoka.jp +yanagawa.fukuoka.jp +yukuhashi.fukuoka.jp +aizubange.fukushima.jp +aizumisato.fukushima.jp +aizuwakamatsu.fukushima.jp +asakawa.fukushima.jp +bandai.fukushima.jp +date.fukushima.jp +fukushima.fukushima.jp +furudono.fukushima.jp +futaba.fukushima.jp +hanawa.fukushima.jp +higashi.fukushima.jp +hirata.fukushima.jp +hirono.fukushima.jp +iitate.fukushima.jp +inawashiro.fukushima.jp +ishikawa.fukushima.jp +iwaki.fukushima.jp +izumizaki.fukushima.jp +kagamiishi.fukushima.jp +kaneyama.fukushima.jp +kawamata.fukushima.jp +kitakata.fukushima.jp +kitashiobara.fukushima.jp +koori.fukushima.jp +koriyama.fukushima.jp +kunimi.fukushima.jp +miharu.fukushima.jp +mishima.fukushima.jp +namie.fukushima.jp +nango.fukushima.jp +nishiaizu.fukushima.jp +nishigo.fukushima.jp +okuma.fukushima.jp +omotego.fukushima.jp +ono.fukushima.jp +otama.fukushima.jp +samegawa.fukushima.jp +shimogo.fukushima.jp +shirakawa.fukushima.jp +showa.fukushima.jp +soma.fukushima.jp +sukagawa.fukushima.jp +taishin.fukushima.jp +tamakawa.fukushima.jp +tanagura.fukushima.jp +tenei.fukushima.jp +yabuki.fukushima.jp +yamato.fukushima.jp +yamatsuri.fukushima.jp +yanaizu.fukushima.jp +yugawa.fukushima.jp +anpachi.gifu.jp +ena.gifu.jp +gifu.gifu.jp +ginan.gifu.jp +godo.gifu.jp +gujo.gifu.jp +hashima.gifu.jp +hichiso.gifu.jp +hida.gifu.jp +higashishirakawa.gifu.jp +ibigawa.gifu.jp +ikeda.gifu.jp +kakamigahara.gifu.jp +kani.gifu.jp +kasahara.gifu.jp +kasamatsu.gifu.jp +kawaue.gifu.jp +kitagata.gifu.jp +mino.gifu.jp +minokamo.gifu.jp +mitake.gifu.jp +mizunami.gifu.jp +motosu.gifu.jp +nakatsugawa.gifu.jp +ogaki.gifu.jp +sakahogi.gifu.jp +seki.gifu.jp +sekigahara.gifu.jp +shirakawa.gifu.jp +tajimi.gifu.jp +takayama.gifu.jp +tarui.gifu.jp +toki.gifu.jp +tomika.gifu.jp +wanouchi.gifu.jp +yamagata.gifu.jp +yaotsu.gifu.jp +yoro.gifu.jp +annaka.gunma.jp +chiyoda.gunma.jp +fujioka.gunma.jp +higashiagatsuma.gunma.jp +isesaki.gunma.jp +itakura.gunma.jp +kanna.gunma.jp +kanra.gunma.jp +katashina.gunma.jp +kawaba.gunma.jp +kiryu.gunma.jp +kusatsu.gunma.jp +maebashi.gunma.jp +meiwa.gunma.jp +midori.gunma.jp +minakami.gunma.jp +naganohara.gunma.jp +nakanojo.gunma.jp +nanmoku.gunma.jp +numata.gunma.jp +oizumi.gunma.jp +ora.gunma.jp +ota.gunma.jp +shibukawa.gunma.jp +shimonita.gunma.jp +shinto.gunma.jp +showa.gunma.jp +takasaki.gunma.jp +takayama.gunma.jp +tamamura.gunma.jp +tatebayashi.gunma.jp +tomioka.gunma.jp +tsukiyono.gunma.jp +tsumagoi.gunma.jp +ueno.gunma.jp +yoshioka.gunma.jp +asaminami.hiroshima.jp +daiwa.hiroshima.jp +etajima.hiroshima.jp +fuchu.hiroshima.jp +fukuyama.hiroshima.jp +hatsukaichi.hiroshima.jp +higashihiroshima.hiroshima.jp +hongo.hiroshima.jp +jinsekikogen.hiroshima.jp +kaita.hiroshima.jp +kui.hiroshima.jp +kumano.hiroshima.jp +kure.hiroshima.jp +mihara.hiroshima.jp +miyoshi.hiroshima.jp +naka.hiroshima.jp +onomichi.hiroshima.jp +osakikamijima.hiroshima.jp +otake.hiroshima.jp +saka.hiroshima.jp +sera.hiroshima.jp +seranishi.hiroshima.jp +shinichi.hiroshima.jp +shobara.hiroshima.jp +takehara.hiroshima.jp +abashiri.hokkaido.jp +abira.hokkaido.jp +aibetsu.hokkaido.jp +akabira.hokkaido.jp +akkeshi.hokkaido.jp +asahikawa.hokkaido.jp +ashibetsu.hokkaido.jp +ashoro.hokkaido.jp +assabu.hokkaido.jp +atsuma.hokkaido.jp +bibai.hokkaido.jp +biei.hokkaido.jp +bifuka.hokkaido.jp +bihoro.hokkaido.jp +biratori.hokkaido.jp +chippubetsu.hokkaido.jp +chitose.hokkaido.jp +date.hokkaido.jp +ebetsu.hokkaido.jp +embetsu.hokkaido.jp +eniwa.hokkaido.jp +erimo.hokkaido.jp +esan.hokkaido.jp +esashi.hokkaido.jp +fukagawa.hokkaido.jp +fukushima.hokkaido.jp +furano.hokkaido.jp +furubira.hokkaido.jp +haboro.hokkaido.jp +hakodate.hokkaido.jp +hamatonbetsu.hokkaido.jp +hidaka.hokkaido.jp +higashikagura.hokkaido.jp +higashikawa.hokkaido.jp +hiroo.hokkaido.jp +hokuryu.hokkaido.jp +hokuto.hokkaido.jp +honbetsu.hokkaido.jp +horokanai.hokkaido.jp +horonobe.hokkaido.jp +ikeda.hokkaido.jp +imakane.hokkaido.jp +ishikari.hokkaido.jp +iwamizawa.hokkaido.jp +iwanai.hokkaido.jp +kamifurano.hokkaido.jp +kamikawa.hokkaido.jp +kamishihoro.hokkaido.jp +kamisunagawa.hokkaido.jp +kamoenai.hokkaido.jp +kayabe.hokkaido.jp +kembuchi.hokkaido.jp +kikonai.hokkaido.jp +kimobetsu.hokkaido.jp +kitahiroshima.hokkaido.jp +kitami.hokkaido.jp +kiyosato.hokkaido.jp +koshimizu.hokkaido.jp +kunneppu.hokkaido.jp +kuriyama.hokkaido.jp +kuromatsunai.hokkaido.jp +kushiro.hokkaido.jp +kutchan.hokkaido.jp +kyowa.hokkaido.jp +mashike.hokkaido.jp +matsumae.hokkaido.jp +mikasa.hokkaido.jp +minamifurano.hokkaido.jp +mombetsu.hokkaido.jp +moseushi.hokkaido.jp +mukawa.hokkaido.jp +muroran.hokkaido.jp +naie.hokkaido.jp +nakagawa.hokkaido.jp +nakasatsunai.hokkaido.jp +nakatombetsu.hokkaido.jp +nanae.hokkaido.jp +nanporo.hokkaido.jp +nayoro.hokkaido.jp +nemuro.hokkaido.jp +niikappu.hokkaido.jp +niki.hokkaido.jp +nishiokoppe.hokkaido.jp +noboribetsu.hokkaido.jp +numata.hokkaido.jp +obihiro.hokkaido.jp +obira.hokkaido.jp +oketo.hokkaido.jp +okoppe.hokkaido.jp +otaru.hokkaido.jp +otobe.hokkaido.jp +otofuke.hokkaido.jp +otoineppu.hokkaido.jp +oumu.hokkaido.jp +ozora.hokkaido.jp +pippu.hokkaido.jp +rankoshi.hokkaido.jp +rebun.hokkaido.jp +rikubetsu.hokkaido.jp +rishiri.hokkaido.jp +rishirifuji.hokkaido.jp +saroma.hokkaido.jp +sarufutsu.hokkaido.jp +shakotan.hokkaido.jp +shari.hokkaido.jp +shibecha.hokkaido.jp +shibetsu.hokkaido.jp +shikabe.hokkaido.jp +shikaoi.hokkaido.jp +shimamaki.hokkaido.jp +shimizu.hokkaido.jp +shimokawa.hokkaido.jp +shinshinotsu.hokkaido.jp +shintoku.hokkaido.jp +shiranuka.hokkaido.jp +shiraoi.hokkaido.jp +shiriuchi.hokkaido.jp +sobetsu.hokkaido.jp +sunagawa.hokkaido.jp +taiki.hokkaido.jp +takasu.hokkaido.jp +takikawa.hokkaido.jp +takinoue.hokkaido.jp +teshikaga.hokkaido.jp +tobetsu.hokkaido.jp +tohma.hokkaido.jp +tomakomai.hokkaido.jp +tomari.hokkaido.jp +toya.hokkaido.jp +toyako.hokkaido.jp +toyotomi.hokkaido.jp +toyoura.hokkaido.jp +tsubetsu.hokkaido.jp +tsukigata.hokkaido.jp +urakawa.hokkaido.jp +urausu.hokkaido.jp +uryu.hokkaido.jp +utashinai.hokkaido.jp +wakkanai.hokkaido.jp +wassamu.hokkaido.jp +yakumo.hokkaido.jp +yoichi.hokkaido.jp +aioi.hyogo.jp +akashi.hyogo.jp +ako.hyogo.jp +amagasaki.hyogo.jp +aogaki.hyogo.jp +asago.hyogo.jp +ashiya.hyogo.jp +awaji.hyogo.jp +fukusaki.hyogo.jp +goshiki.hyogo.jp +harima.hyogo.jp +himeji.hyogo.jp +ichikawa.hyogo.jp +inagawa.hyogo.jp +itami.hyogo.jp +kakogawa.hyogo.jp +kamigori.hyogo.jp +kamikawa.hyogo.jp +kasai.hyogo.jp +kasuga.hyogo.jp +kawanishi.hyogo.jp +miki.hyogo.jp +minamiawaji.hyogo.jp +nishinomiya.hyogo.jp +nishiwaki.hyogo.jp +ono.hyogo.jp +sanda.hyogo.jp +sannan.hyogo.jp +sasayama.hyogo.jp +sayo.hyogo.jp +shingu.hyogo.jp +shinonsen.hyogo.jp +shiso.hyogo.jp +sumoto.hyogo.jp +taishi.hyogo.jp +taka.hyogo.jp +takarazuka.hyogo.jp +takasago.hyogo.jp +takino.hyogo.jp +tamba.hyogo.jp +tatsuno.hyogo.jp +toyooka.hyogo.jp +yabu.hyogo.jp +yashiro.hyogo.jp +yoka.hyogo.jp +yokawa.hyogo.jp +ami.ibaraki.jp +asahi.ibaraki.jp +bando.ibaraki.jp +chikusei.ibaraki.jp +daigo.ibaraki.jp +fujishiro.ibaraki.jp +hitachi.ibaraki.jp +hitachinaka.ibaraki.jp +hitachiomiya.ibaraki.jp +hitachiota.ibaraki.jp +ibaraki.ibaraki.jp +ina.ibaraki.jp +inashiki.ibaraki.jp +itako.ibaraki.jp +iwama.ibaraki.jp +joso.ibaraki.jp +kamisu.ibaraki.jp +kasama.ibaraki.jp +kashima.ibaraki.jp +kasumigaura.ibaraki.jp +koga.ibaraki.jp +miho.ibaraki.jp +mito.ibaraki.jp +moriya.ibaraki.jp +naka.ibaraki.jp +namegata.ibaraki.jp +oarai.ibaraki.jp +ogawa.ibaraki.jp +omitama.ibaraki.jp +ryugasaki.ibaraki.jp +sakai.ibaraki.jp +sakuragawa.ibaraki.jp +shimodate.ibaraki.jp +shimotsuma.ibaraki.jp +shirosato.ibaraki.jp +sowa.ibaraki.jp +suifu.ibaraki.jp +takahagi.ibaraki.jp +tamatsukuri.ibaraki.jp +tokai.ibaraki.jp +tomobe.ibaraki.jp +tone.ibaraki.jp +toride.ibaraki.jp +tsuchiura.ibaraki.jp +tsukuba.ibaraki.jp +uchihara.ibaraki.jp +ushiku.ibaraki.jp +yachiyo.ibaraki.jp +yamagata.ibaraki.jp +yawara.ibaraki.jp +yuki.ibaraki.jp +anamizu.ishikawa.jp +hakui.ishikawa.jp +hakusan.ishikawa.jp +kaga.ishikawa.jp +kahoku.ishikawa.jp +kanazawa.ishikawa.jp +kawakita.ishikawa.jp +komatsu.ishikawa.jp +nakanoto.ishikawa.jp +nanao.ishikawa.jp +nomi.ishikawa.jp +nonoichi.ishikawa.jp +noto.ishikawa.jp +shika.ishikawa.jp +suzu.ishikawa.jp +tsubata.ishikawa.jp +tsurugi.ishikawa.jp +uchinada.ishikawa.jp +wajima.ishikawa.jp +fudai.iwate.jp +fujisawa.iwate.jp +hanamaki.iwate.jp +hiraizumi.iwate.jp +hirono.iwate.jp +ichinohe.iwate.jp +ichinoseki.iwate.jp +iwaizumi.iwate.jp +iwate.iwate.jp +joboji.iwate.jp +kamaishi.iwate.jp +kanegasaki.iwate.jp +karumai.iwate.jp +kawai.iwate.jp +kitakami.iwate.jp +kuji.iwate.jp +kunohe.iwate.jp +kuzumaki.iwate.jp +miyako.iwate.jp +mizusawa.iwate.jp +morioka.iwate.jp +ninohe.iwate.jp +noda.iwate.jp +ofunato.iwate.jp +oshu.iwate.jp +otsuchi.iwate.jp +rikuzentakata.iwate.jp +shiwa.iwate.jp +shizukuishi.iwate.jp +sumita.iwate.jp +tanohata.iwate.jp +tono.iwate.jp +yahaba.iwate.jp +yamada.iwate.jp +ayagawa.kagawa.jp +higashikagawa.kagawa.jp +kanonji.kagawa.jp +kotohira.kagawa.jp +manno.kagawa.jp +marugame.kagawa.jp +mitoyo.kagawa.jp +naoshima.kagawa.jp +sanuki.kagawa.jp +tadotsu.kagawa.jp +takamatsu.kagawa.jp +tonosho.kagawa.jp +uchinomi.kagawa.jp +utazu.kagawa.jp +zentsuji.kagawa.jp +akune.kagoshima.jp +amami.kagoshima.jp +hioki.kagoshima.jp +isa.kagoshima.jp +isen.kagoshima.jp +izumi.kagoshima.jp +kagoshima.kagoshima.jp +kanoya.kagoshima.jp +kawanabe.kagoshima.jp +kinko.kagoshima.jp +kouyama.kagoshima.jp +makurazaki.kagoshima.jp +matsumoto.kagoshima.jp +minamitane.kagoshima.jp +nakatane.kagoshima.jp +nishinoomote.kagoshima.jp +satsumasendai.kagoshima.jp +soo.kagoshima.jp +tarumizu.kagoshima.jp +yusui.kagoshima.jp +aikawa.kanagawa.jp +atsugi.kanagawa.jp +ayase.kanagawa.jp +chigasaki.kanagawa.jp +ebina.kanagawa.jp +fujisawa.kanagawa.jp +hadano.kanagawa.jp +hakone.kanagawa.jp +hiratsuka.kanagawa.jp +isehara.kanagawa.jp +kaisei.kanagawa.jp +kamakura.kanagawa.jp +kiyokawa.kanagawa.jp +matsuda.kanagawa.jp +minamiashigara.kanagawa.jp +miura.kanagawa.jp +nakai.kanagawa.jp +ninomiya.kanagawa.jp +odawara.kanagawa.jp +oi.kanagawa.jp +oiso.kanagawa.jp +sagamihara.kanagawa.jp +samukawa.kanagawa.jp +tsukui.kanagawa.jp +yamakita.kanagawa.jp +yamato.kanagawa.jp +yokosuka.kanagawa.jp +yugawara.kanagawa.jp +zama.kanagawa.jp +zushi.kanagawa.jp +aki.kochi.jp +geisei.kochi.jp +hidaka.kochi.jp +higashitsuno.kochi.jp +ino.kochi.jp +kagami.kochi.jp +kami.kochi.jp +kitagawa.kochi.jp +kochi.kochi.jp +mihara.kochi.jp +motoyama.kochi.jp +muroto.kochi.jp +nahari.kochi.jp +nakamura.kochi.jp +nankoku.kochi.jp +nishitosa.kochi.jp +niyodogawa.kochi.jp +ochi.kochi.jp +okawa.kochi.jp +otoyo.kochi.jp +otsuki.kochi.jp +sakawa.kochi.jp +sukumo.kochi.jp +susaki.kochi.jp +tosa.kochi.jp +tosashimizu.kochi.jp +toyo.kochi.jp +tsuno.kochi.jp +umaji.kochi.jp +yasuda.kochi.jp +yusuhara.kochi.jp +amakusa.kumamoto.jp +arao.kumamoto.jp +aso.kumamoto.jp +choyo.kumamoto.jp +gyokuto.kumamoto.jp +kamiamakusa.kumamoto.jp +kikuchi.kumamoto.jp +kumamoto.kumamoto.jp +mashiki.kumamoto.jp +mifune.kumamoto.jp +minamata.kumamoto.jp +minamioguni.kumamoto.jp +nagasu.kumamoto.jp +nishihara.kumamoto.jp +oguni.kumamoto.jp +ozu.kumamoto.jp +sumoto.kumamoto.jp +takamori.kumamoto.jp +uki.kumamoto.jp +uto.kumamoto.jp +yamaga.kumamoto.jp +yamato.kumamoto.jp +yatsushiro.kumamoto.jp +ayabe.kyoto.jp +fukuchiyama.kyoto.jp +higashiyama.kyoto.jp +ide.kyoto.jp +ine.kyoto.jp +joyo.kyoto.jp +kameoka.kyoto.jp +kamo.kyoto.jp +kita.kyoto.jp +kizu.kyoto.jp +kumiyama.kyoto.jp +kyotamba.kyoto.jp +kyotanabe.kyoto.jp +kyotango.kyoto.jp +maizuru.kyoto.jp +minami.kyoto.jp +minamiyamashiro.kyoto.jp +miyazu.kyoto.jp +muko.kyoto.jp +nagaokakyo.kyoto.jp +nakagyo.kyoto.jp +nantan.kyoto.jp +oyamazaki.kyoto.jp +sakyo.kyoto.jp +seika.kyoto.jp +tanabe.kyoto.jp +uji.kyoto.jp +ujitawara.kyoto.jp +wazuka.kyoto.jp +yamashina.kyoto.jp +yawata.kyoto.jp +asahi.mie.jp +inabe.mie.jp +ise.mie.jp +kameyama.mie.jp +kawagoe.mie.jp +kiho.mie.jp +kisosaki.mie.jp +kiwa.mie.jp +komono.mie.jp +kumano.mie.jp +kuwana.mie.jp +matsusaka.mie.jp +meiwa.mie.jp +mihama.mie.jp +minamiise.mie.jp +misugi.mie.jp +miyama.mie.jp +nabari.mie.jp +shima.mie.jp +suzuka.mie.jp +tado.mie.jp +taiki.mie.jp +taki.mie.jp +tamaki.mie.jp +toba.mie.jp +tsu.mie.jp +udono.mie.jp +ureshino.mie.jp +watarai.mie.jp +yokkaichi.mie.jp +furukawa.miyagi.jp +higashimatsushima.miyagi.jp +ishinomaki.miyagi.jp +iwanuma.miyagi.jp +kakuda.miyagi.jp +kami.miyagi.jp +kawasaki.miyagi.jp +marumori.miyagi.jp +matsushima.miyagi.jp +minamisanriku.miyagi.jp +misato.miyagi.jp +murata.miyagi.jp +natori.miyagi.jp +ogawara.miyagi.jp +ohira.miyagi.jp +onagawa.miyagi.jp +osaki.miyagi.jp +rifu.miyagi.jp +semine.miyagi.jp +shibata.miyagi.jp +shichikashuku.miyagi.jp +shikama.miyagi.jp +shiogama.miyagi.jp +shiroishi.miyagi.jp +tagajo.miyagi.jp +taiwa.miyagi.jp +tome.miyagi.jp +tomiya.miyagi.jp +wakuya.miyagi.jp +watari.miyagi.jp +yamamoto.miyagi.jp +zao.miyagi.jp +aya.miyazaki.jp +ebino.miyazaki.jp +gokase.miyazaki.jp +hyuga.miyazaki.jp +kadogawa.miyazaki.jp +kawaminami.miyazaki.jp +kijo.miyazaki.jp +kitagawa.miyazaki.jp +kitakata.miyazaki.jp +kitaura.miyazaki.jp +kobayashi.miyazaki.jp +kunitomi.miyazaki.jp +kushima.miyazaki.jp +mimata.miyazaki.jp +miyakonojo.miyazaki.jp +miyazaki.miyazaki.jp +morotsuka.miyazaki.jp +nichinan.miyazaki.jp +nishimera.miyazaki.jp +nobeoka.miyazaki.jp +saito.miyazaki.jp +shiiba.miyazaki.jp +shintomi.miyazaki.jp +takaharu.miyazaki.jp +takanabe.miyazaki.jp +takazaki.miyazaki.jp +tsuno.miyazaki.jp +achi.nagano.jp +agematsu.nagano.jp +anan.nagano.jp +aoki.nagano.jp +asahi.nagano.jp +azumino.nagano.jp +chikuhoku.nagano.jp +chikuma.nagano.jp +chino.nagano.jp +fujimi.nagano.jp +hakuba.nagano.jp +hara.nagano.jp +hiraya.nagano.jp +iida.nagano.jp +iijima.nagano.jp +iiyama.nagano.jp +iizuna.nagano.jp +ikeda.nagano.jp +ikusaka.nagano.jp +ina.nagano.jp +karuizawa.nagano.jp +kawakami.nagano.jp +kiso.nagano.jp +kisofukushima.nagano.jp +kitaaiki.nagano.jp +komagane.nagano.jp +komoro.nagano.jp +matsukawa.nagano.jp +matsumoto.nagano.jp +miasa.nagano.jp +minamiaiki.nagano.jp +minamimaki.nagano.jp +minamiminowa.nagano.jp +minowa.nagano.jp +miyada.nagano.jp +miyota.nagano.jp +mochizuki.nagano.jp +nagano.nagano.jp +nagawa.nagano.jp +nagiso.nagano.jp +nakagawa.nagano.jp +nakano.nagano.jp +nozawaonsen.nagano.jp +obuse.nagano.jp +ogawa.nagano.jp +okaya.nagano.jp +omachi.nagano.jp +omi.nagano.jp +ookuwa.nagano.jp +ooshika.nagano.jp +otaki.nagano.jp +otari.nagano.jp +sakae.nagano.jp +sakaki.nagano.jp +saku.nagano.jp +sakuho.nagano.jp +shimosuwa.nagano.jp +shinanomachi.nagano.jp +shiojiri.nagano.jp +suwa.nagano.jp +suzaka.nagano.jp +takagi.nagano.jp +takamori.nagano.jp +takayama.nagano.jp +tateshina.nagano.jp +tatsuno.nagano.jp +togakushi.nagano.jp +togura.nagano.jp +tomi.nagano.jp +ueda.nagano.jp +wada.nagano.jp +yamagata.nagano.jp +yamanouchi.nagano.jp +yasaka.nagano.jp +yasuoka.nagano.jp +chijiwa.nagasaki.jp +futsu.nagasaki.jp +goto.nagasaki.jp +hasami.nagasaki.jp +hirado.nagasaki.jp +iki.nagasaki.jp +isahaya.nagasaki.jp +kawatana.nagasaki.jp +kuchinotsu.nagasaki.jp +matsuura.nagasaki.jp +nagasaki.nagasaki.jp +obama.nagasaki.jp +omura.nagasaki.jp +oseto.nagasaki.jp +saikai.nagasaki.jp +sasebo.nagasaki.jp +seihi.nagasaki.jp +shimabara.nagasaki.jp +shinkamigoto.nagasaki.jp +togitsu.nagasaki.jp +tsushima.nagasaki.jp +unzen.nagasaki.jp +ando.nara.jp +gose.nara.jp +heguri.nara.jp +higashiyoshino.nara.jp +ikaruga.nara.jp +ikoma.nara.jp +kamikitayama.nara.jp +kanmaki.nara.jp +kashiba.nara.jp +kashihara.nara.jp +katsuragi.nara.jp +kawai.nara.jp +kawakami.nara.jp +kawanishi.nara.jp +koryo.nara.jp +kurotaki.nara.jp +mitsue.nara.jp +miyake.nara.jp +nara.nara.jp +nosegawa.nara.jp +oji.nara.jp +ouda.nara.jp +oyodo.nara.jp +sakurai.nara.jp +sango.nara.jp +shimoichi.nara.jp +shimokitayama.nara.jp +shinjo.nara.jp +soni.nara.jp +takatori.nara.jp +tawaramoto.nara.jp +tenkawa.nara.jp +tenri.nara.jp +uda.nara.jp +yamatokoriyama.nara.jp +yamatotakada.nara.jp +yamazoe.nara.jp +yoshino.nara.jp +aga.niigata.jp +agano.niigata.jp +gosen.niigata.jp +itoigawa.niigata.jp +izumozaki.niigata.jp +joetsu.niigata.jp +kamo.niigata.jp +kariwa.niigata.jp +kashiwazaki.niigata.jp +minamiuonuma.niigata.jp +mitsuke.niigata.jp +muika.niigata.jp +murakami.niigata.jp +myoko.niigata.jp +nagaoka.niigata.jp +niigata.niigata.jp +ojiya.niigata.jp +omi.niigata.jp +sado.niigata.jp +sanjo.niigata.jp +seiro.niigata.jp +seirou.niigata.jp +sekikawa.niigata.jp +shibata.niigata.jp +tagami.niigata.jp +tainai.niigata.jp +tochio.niigata.jp +tokamachi.niigata.jp +tsubame.niigata.jp +tsunan.niigata.jp +uonuma.niigata.jp +yahiko.niigata.jp +yoita.niigata.jp +yuzawa.niigata.jp +beppu.oita.jp +bungoono.oita.jp +bungotakada.oita.jp +hasama.oita.jp +hiji.oita.jp +himeshima.oita.jp +hita.oita.jp +kamitsue.oita.jp +kokonoe.oita.jp +kuju.oita.jp +kunisaki.oita.jp +kusu.oita.jp +oita.oita.jp +saiki.oita.jp +taketa.oita.jp +tsukumi.oita.jp +usa.oita.jp +usuki.oita.jp +yufu.oita.jp +akaiwa.okayama.jp +asakuchi.okayama.jp +bizen.okayama.jp +hayashima.okayama.jp +ibara.okayama.jp +kagamino.okayama.jp +kasaoka.okayama.jp +kibichuo.okayama.jp +kumenan.okayama.jp +kurashiki.okayama.jp +maniwa.okayama.jp +misaki.okayama.jp +nagi.okayama.jp +niimi.okayama.jp +nishiawakura.okayama.jp +okayama.okayama.jp +satosho.okayama.jp +setouchi.okayama.jp +shinjo.okayama.jp +shoo.okayama.jp +soja.okayama.jp +takahashi.okayama.jp +tamano.okayama.jp +tsuyama.okayama.jp +wake.okayama.jp +yakage.okayama.jp +aguni.okinawa.jp +ginowan.okinawa.jp +ginoza.okinawa.jp +gushikami.okinawa.jp +haebaru.okinawa.jp +higashi.okinawa.jp +hirara.okinawa.jp +iheya.okinawa.jp +ishigaki.okinawa.jp +ishikawa.okinawa.jp +itoman.okinawa.jp +izena.okinawa.jp +kadena.okinawa.jp +kin.okinawa.jp +kitadaito.okinawa.jp +kitanakagusuku.okinawa.jp +kumejima.okinawa.jp +kunigami.okinawa.jp +minamidaito.okinawa.jp +motobu.okinawa.jp +nago.okinawa.jp +naha.okinawa.jp +nakagusuku.okinawa.jp +nakijin.okinawa.jp +nanjo.okinawa.jp +nishihara.okinawa.jp +ogimi.okinawa.jp +okinawa.okinawa.jp +onna.okinawa.jp +shimoji.okinawa.jp +taketomi.okinawa.jp +tarama.okinawa.jp +tokashiki.okinawa.jp +tomigusuku.okinawa.jp +tonaki.okinawa.jp +urasoe.okinawa.jp +uruma.okinawa.jp +yaese.okinawa.jp +yomitan.okinawa.jp +yonabaru.okinawa.jp +yonaguni.okinawa.jp +zamami.okinawa.jp +abeno.osaka.jp +chihayaakasaka.osaka.jp +chuo.osaka.jp +daito.osaka.jp +fujiidera.osaka.jp +habikino.osaka.jp +hannan.osaka.jp +higashiosaka.osaka.jp +higashisumiyoshi.osaka.jp +higashiyodogawa.osaka.jp +hirakata.osaka.jp +ibaraki.osaka.jp +ikeda.osaka.jp +izumi.osaka.jp +izumiotsu.osaka.jp +izumisano.osaka.jp +kadoma.osaka.jp +kaizuka.osaka.jp +kanan.osaka.jp +kashiwara.osaka.jp +katano.osaka.jp +kawachinagano.osaka.jp +kishiwada.osaka.jp +kita.osaka.jp +kumatori.osaka.jp +matsubara.osaka.jp +minato.osaka.jp +minoh.osaka.jp +misaki.osaka.jp +moriguchi.osaka.jp +neyagawa.osaka.jp +nishi.osaka.jp +nose.osaka.jp +osakasayama.osaka.jp +sakai.osaka.jp +sayama.osaka.jp +sennan.osaka.jp +settsu.osaka.jp +shijonawate.osaka.jp +shimamoto.osaka.jp +suita.osaka.jp +tadaoka.osaka.jp +taishi.osaka.jp +tajiri.osaka.jp +takaishi.osaka.jp +takatsuki.osaka.jp +tondabayashi.osaka.jp +toyonaka.osaka.jp +toyono.osaka.jp +yao.osaka.jp +ariake.saga.jp +arita.saga.jp +fukudomi.saga.jp +genkai.saga.jp +hamatama.saga.jp +hizen.saga.jp +imari.saga.jp +kamimine.saga.jp +kanzaki.saga.jp +karatsu.saga.jp +kashima.saga.jp +kitagata.saga.jp +kitahata.saga.jp +kiyama.saga.jp +kouhoku.saga.jp +kyuragi.saga.jp +nishiarita.saga.jp +ogi.saga.jp +omachi.saga.jp +ouchi.saga.jp +saga.saga.jp +shiroishi.saga.jp +taku.saga.jp +tara.saga.jp +tosu.saga.jp +yoshinogari.saga.jp +arakawa.saitama.jp +asaka.saitama.jp +chichibu.saitama.jp +fujimi.saitama.jp +fujimino.saitama.jp +fukaya.saitama.jp +hanno.saitama.jp +hanyu.saitama.jp +hasuda.saitama.jp +hatogaya.saitama.jp +hatoyama.saitama.jp +hidaka.saitama.jp +higashichichibu.saitama.jp +higashimatsuyama.saitama.jp +honjo.saitama.jp +ina.saitama.jp +iruma.saitama.jp +iwatsuki.saitama.jp +kamiizumi.saitama.jp +kamikawa.saitama.jp +kamisato.saitama.jp +kasukabe.saitama.jp +kawagoe.saitama.jp +kawaguchi.saitama.jp +kawajima.saitama.jp +kazo.saitama.jp +kitamoto.saitama.jp +koshigaya.saitama.jp +kounosu.saitama.jp +kuki.saitama.jp +kumagaya.saitama.jp +matsubushi.saitama.jp +minano.saitama.jp +misato.saitama.jp +miyashiro.saitama.jp +miyoshi.saitama.jp +moroyama.saitama.jp +nagatoro.saitama.jp +namegawa.saitama.jp +niiza.saitama.jp +ogano.saitama.jp +ogawa.saitama.jp +ogose.saitama.jp +okegawa.saitama.jp +omiya.saitama.jp +otaki.saitama.jp +ranzan.saitama.jp +ryokami.saitama.jp +saitama.saitama.jp +sakado.saitama.jp +satte.saitama.jp +sayama.saitama.jp +shiki.saitama.jp +shiraoka.saitama.jp +soka.saitama.jp +sugito.saitama.jp +toda.saitama.jp +tokigawa.saitama.jp +tokorozawa.saitama.jp +tsurugashima.saitama.jp +urawa.saitama.jp +warabi.saitama.jp +yashio.saitama.jp +yokoze.saitama.jp +yono.saitama.jp +yorii.saitama.jp +yoshida.saitama.jp +yoshikawa.saitama.jp +yoshimi.saitama.jp +aisho.shiga.jp +gamo.shiga.jp +higashiomi.shiga.jp +hikone.shiga.jp +koka.shiga.jp +konan.shiga.jp +kosei.shiga.jp +koto.shiga.jp +kusatsu.shiga.jp +maibara.shiga.jp +moriyama.shiga.jp +nagahama.shiga.jp +nishiazai.shiga.jp +notogawa.shiga.jp +omihachiman.shiga.jp +otsu.shiga.jp +ritto.shiga.jp +ryuoh.shiga.jp +takashima.shiga.jp +takatsuki.shiga.jp +torahime.shiga.jp +toyosato.shiga.jp +yasu.shiga.jp +akagi.shimane.jp +ama.shimane.jp +gotsu.shimane.jp +hamada.shimane.jp +higashiizumo.shimane.jp +hikawa.shimane.jp +hikimi.shimane.jp +izumo.shimane.jp +kakinoki.shimane.jp +masuda.shimane.jp +matsue.shimane.jp +misato.shimane.jp +nishinoshima.shimane.jp +ohda.shimane.jp +okinoshima.shimane.jp +okuizumo.shimane.jp +shimane.shimane.jp +tamayu.shimane.jp +tsuwano.shimane.jp +unnan.shimane.jp +yakumo.shimane.jp +yasugi.shimane.jp +yatsuka.shimane.jp +arai.shizuoka.jp +atami.shizuoka.jp +fuji.shizuoka.jp +fujieda.shizuoka.jp +fujikawa.shizuoka.jp +fujinomiya.shizuoka.jp +fukuroi.shizuoka.jp +gotemba.shizuoka.jp +haibara.shizuoka.jp +hamamatsu.shizuoka.jp +higashiizu.shizuoka.jp +ito.shizuoka.jp +iwata.shizuoka.jp +izu.shizuoka.jp +izunokuni.shizuoka.jp +kakegawa.shizuoka.jp +kannami.shizuoka.jp +kawanehon.shizuoka.jp +kawazu.shizuoka.jp +kikugawa.shizuoka.jp +kosai.shizuoka.jp +makinohara.shizuoka.jp +matsuzaki.shizuoka.jp +minamiizu.shizuoka.jp +mishima.shizuoka.jp +morimachi.shizuoka.jp +nishiizu.shizuoka.jp +numazu.shizuoka.jp +omaezaki.shizuoka.jp +shimada.shizuoka.jp +shimizu.shizuoka.jp +shimoda.shizuoka.jp +shizuoka.shizuoka.jp +susono.shizuoka.jp +yaizu.shizuoka.jp +yoshida.shizuoka.jp +ashikaga.tochigi.jp +bato.tochigi.jp +haga.tochigi.jp +ichikai.tochigi.jp +iwafune.tochigi.jp +kaminokawa.tochigi.jp +kanuma.tochigi.jp +karasuyama.tochigi.jp +kuroiso.tochigi.jp +mashiko.tochigi.jp +mibu.tochigi.jp +moka.tochigi.jp +motegi.tochigi.jp +nasu.tochigi.jp +nasushiobara.tochigi.jp +nikko.tochigi.jp +nishikata.tochigi.jp +nogi.tochigi.jp +ohira.tochigi.jp +ohtawara.tochigi.jp +oyama.tochigi.jp +sakura.tochigi.jp +sano.tochigi.jp +shimotsuke.tochigi.jp +shioya.tochigi.jp +takanezawa.tochigi.jp +tochigi.tochigi.jp +tsuga.tochigi.jp +ujiie.tochigi.jp +utsunomiya.tochigi.jp +yaita.tochigi.jp +aizumi.tokushima.jp +anan.tokushima.jp +ichiba.tokushima.jp +itano.tokushima.jp +kainan.tokushima.jp +komatsushima.tokushima.jp +matsushige.tokushima.jp +mima.tokushima.jp +minami.tokushima.jp +miyoshi.tokushima.jp +mugi.tokushima.jp +nakagawa.tokushima.jp +naruto.tokushima.jp +sanagochi.tokushima.jp +shishikui.tokushima.jp +tokushima.tokushima.jp +wajiki.tokushima.jp +adachi.tokyo.jp +akiruno.tokyo.jp +akishima.tokyo.jp +aogashima.tokyo.jp +arakawa.tokyo.jp +bunkyo.tokyo.jp +chiyoda.tokyo.jp +chofu.tokyo.jp +chuo.tokyo.jp +edogawa.tokyo.jp +fuchu.tokyo.jp +fussa.tokyo.jp +hachijo.tokyo.jp +hachioji.tokyo.jp +hamura.tokyo.jp +higashikurume.tokyo.jp +higashimurayama.tokyo.jp +higashiyamato.tokyo.jp +hino.tokyo.jp +hinode.tokyo.jp +hinohara.tokyo.jp +inagi.tokyo.jp +itabashi.tokyo.jp +katsushika.tokyo.jp +kita.tokyo.jp +kiyose.tokyo.jp +kodaira.tokyo.jp +koganei.tokyo.jp +kokubunji.tokyo.jp +komae.tokyo.jp +koto.tokyo.jp +kouzushima.tokyo.jp +kunitachi.tokyo.jp +machida.tokyo.jp +meguro.tokyo.jp +minato.tokyo.jp +mitaka.tokyo.jp +mizuho.tokyo.jp +musashimurayama.tokyo.jp +musashino.tokyo.jp +nakano.tokyo.jp +nerima.tokyo.jp +ogasawara.tokyo.jp +okutama.tokyo.jp +ome.tokyo.jp +oshima.tokyo.jp +ota.tokyo.jp +setagaya.tokyo.jp +shibuya.tokyo.jp +shinagawa.tokyo.jp +shinjuku.tokyo.jp +suginami.tokyo.jp +sumida.tokyo.jp +tachikawa.tokyo.jp +taito.tokyo.jp +tama.tokyo.jp +toshima.tokyo.jp +chizu.tottori.jp +hino.tottori.jp +kawahara.tottori.jp +koge.tottori.jp +kotoura.tottori.jp +misasa.tottori.jp +nanbu.tottori.jp +nichinan.tottori.jp +sakaiminato.tottori.jp +tottori.tottori.jp +wakasa.tottori.jp +yazu.tottori.jp +yonago.tottori.jp +asahi.toyama.jp +fuchu.toyama.jp +fukumitsu.toyama.jp +funahashi.toyama.jp +himi.toyama.jp +imizu.toyama.jp +inami.toyama.jp +johana.toyama.jp +kamiichi.toyama.jp +kurobe.toyama.jp +nakaniikawa.toyama.jp +namerikawa.toyama.jp +nanto.toyama.jp +nyuzen.toyama.jp +oyabe.toyama.jp +taira.toyama.jp +takaoka.toyama.jp +tateyama.toyama.jp +toga.toyama.jp +tonami.toyama.jp +toyama.toyama.jp +unazuki.toyama.jp +uozu.toyama.jp +yamada.toyama.jp +arida.wakayama.jp +aridagawa.wakayama.jp +gobo.wakayama.jp +hashimoto.wakayama.jp +hidaka.wakayama.jp +hirogawa.wakayama.jp +inami.wakayama.jp +iwade.wakayama.jp +kainan.wakayama.jp +kamitonda.wakayama.jp +katsuragi.wakayama.jp +kimino.wakayama.jp +kinokawa.wakayama.jp +kitayama.wakayama.jp +koya.wakayama.jp +koza.wakayama.jp +kozagawa.wakayama.jp +kudoyama.wakayama.jp +kushimoto.wakayama.jp +mihama.wakayama.jp +misato.wakayama.jp +nachikatsuura.wakayama.jp +shingu.wakayama.jp +shirahama.wakayama.jp +taiji.wakayama.jp +tanabe.wakayama.jp +wakayama.wakayama.jp +yuasa.wakayama.jp +yura.wakayama.jp +asahi.yamagata.jp +funagata.yamagata.jp +higashine.yamagata.jp +iide.yamagata.jp +kahoku.yamagata.jp +kaminoyama.yamagata.jp +kaneyama.yamagata.jp +kawanishi.yamagata.jp +mamurogawa.yamagata.jp +mikawa.yamagata.jp +murayama.yamagata.jp +nagai.yamagata.jp +nakayama.yamagata.jp +nanyo.yamagata.jp +nishikawa.yamagata.jp +obanazawa.yamagata.jp +oe.yamagata.jp +oguni.yamagata.jp +ohkura.yamagata.jp +oishida.yamagata.jp +sagae.yamagata.jp +sakata.yamagata.jp +sakegawa.yamagata.jp +shinjo.yamagata.jp +shirataka.yamagata.jp +shonai.yamagata.jp +takahata.yamagata.jp +tendo.yamagata.jp +tozawa.yamagata.jp +tsuruoka.yamagata.jp +yamagata.yamagata.jp +yamanobe.yamagata.jp +yonezawa.yamagata.jp +yuza.yamagata.jp +abu.yamaguchi.jp +hagi.yamaguchi.jp +hikari.yamaguchi.jp +hofu.yamaguchi.jp +iwakuni.yamaguchi.jp +kudamatsu.yamaguchi.jp +mitou.yamaguchi.jp +nagato.yamaguchi.jp +oshima.yamaguchi.jp +shimonoseki.yamaguchi.jp +shunan.yamaguchi.jp +tabuse.yamaguchi.jp +tokuyama.yamaguchi.jp +toyota.yamaguchi.jp +ube.yamaguchi.jp +yuu.yamaguchi.jp +chuo.yamanashi.jp +doshi.yamanashi.jp +fuefuki.yamanashi.jp +fujikawa.yamanashi.jp +fujikawaguchiko.yamanashi.jp +fujiyoshida.yamanashi.jp +hayakawa.yamanashi.jp +hokuto.yamanashi.jp +ichikawamisato.yamanashi.jp +kai.yamanashi.jp +kofu.yamanashi.jp +koshu.yamanashi.jp +kosuge.yamanashi.jp +minami-alps.yamanashi.jp +minobu.yamanashi.jp +nakamichi.yamanashi.jp +nanbu.yamanashi.jp +narusawa.yamanashi.jp +nirasaki.yamanashi.jp +nishikatsura.yamanashi.jp +oshino.yamanashi.jp +otsuki.yamanashi.jp +showa.yamanashi.jp +tabayama.yamanashi.jp +tsuru.yamanashi.jp +uenohara.yamanashi.jp +yamanakako.yamanashi.jp +yamanashi.yamanashi.jp + +// ke : http://www.kenic.or.ke/index.php/en/ke-domains/ke-domains +ke +ac.ke +co.ke +go.ke +info.ke +me.ke +mobi.ke +ne.ke +or.ke +sc.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +org.kg +net.kg +com.kg +edu.kg +gov.kg +mil.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : http://www.ki/dns/index.html +ki +edu.ki +biz.ki +net.ki +org.ki +gov.ki +info.ki +com.ki + +// km : https://en.wikipedia.org/wiki/.km +// http://www.domaine.km/documents/charte.doc +km +org.km +nom.km +gov.km +prd.km +tm.km +edu.km +mil.km +ass.km +com.km +// These are only mentioned as proposed suggestions at domaine.km, but +// https://en.wikipedia.org/wiki/.km says they're available for registration: +coop.km +asso.km +presse.km +medecin.km +notaires.km +pharmaciens.km +veterinaire.km +gouv.km + +// kn : https://en.wikipedia.org/wiki/.kn +// http://www.dot.kn/domainRules.html +kn +net.kn +org.kn +edu.kn +gov.kn + +// kp : http://www.kcce.kp/en_index.php +kp +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : https://en.wikipedia.org/wiki/.kr +// see also: http://domain.nida.or.kr/eng/registration.jsp +kr +ac.kr +co.kr +es.kr +go.kr +hs.kr +kg.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : https://en.wikipedia.org/wiki/.kw +*.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +edu.ky +gov.ky +com.ky +org.ky +net.ky + +// kz : https://en.wikipedia.org/wiki/.kz +// see also: http://www.nic.kz/rules/index.jsp +kz +org.kz +edu.kz +net.kz +gov.kz +mil.kz +com.kz + +// la : https://en.wikipedia.org/wiki/.la +// Submitted by registry +la +int.la +net.la +info.la +edu.la +gov.la +per.la +com.la +org.la + +// lb : https://en.wikipedia.org/wiki/.lb +// Submitted by registry +lb +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : https://en.wikipedia.org/wiki/.lc +// see also: http://www.nic.lc/rules.htm +lc +com.lc +net.lc +co.lc +org.lc +edu.lc +gov.lc + +// li : https://en.wikipedia.org/wiki/.li +li + +// lk : http://www.nic.lk/seclevpr.html +lk +gov.lk +sch.lk +net.lk +int.lk +com.lk +org.lk +edu.lk +ngo.lk +soc.lk +web.lk +ltd.lk +assn.lk +grp.lk +hotel.lk +ac.lk + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry +lr +com.lr +edu.lr +gov.lr +org.lr +net.lr + +// ls : https://en.wikipedia.org/wiki/.ls +ls +co.ls +org.ls + +// lt : https://en.wikipedia.org/wiki/.lt +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : http://www.nic.lv/DNS/En/generic.php +lv +com.lv +edu.lv +gov.lv +org.lv +mil.lv +id.lv +net.lv +asn.lv +conf.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +net.ly +gov.ly +plc.ly +edu.ly +sch.ly +med.ly +org.ly +id.ly + +// ma : https://en.wikipedia.org/wiki/.ma +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +co.ma +net.ma +gov.ma +org.ma +ac.ma +press.ma + +// mc : http://www.nic.mc/ +mc +tm.mc +asso.mc + +// md : https://en.wikipedia.org/wiki/.md +md + +// me : https://en.wikipedia.org/wiki/.me +me +co.me +net.me +org.me +edu.me +ac.me +gov.me +its.me +priv.me + +// mg : http://nic.mg/nicmg/?page_id=39 +mg +org.mg +nom.mg +gov.mg +prd.mg +tm.mg +edu.mg +mil.mg +com.mg +co.mg + +// mh : https://en.wikipedia.org/wiki/.mh +mh + +// mil : https://en.wikipedia.org/wiki/.mil +mil + +// mk : https://en.wikipedia.org/wiki/.mk +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +org.mk +net.mk +edu.mk +gov.mk +inf.mk +name.mk + +// ml : http://www.gobin.info/domainname/ml-template.doc +// see also: https://en.wikipedia.org/wiki/.ml +ml +com.ml +edu.ml +gouv.ml +gov.ml +net.ml +org.ml +presse.ml + +// mm : https://en.wikipedia.org/wiki/.mm +*.mm + +// mn : https://en.wikipedia.org/wiki/.mn +mn +gov.mn +edu.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +net.mo +org.mo +edu.mo +gov.mo + +// mobi : https://en.wikipedia.org/wiki/.mobi +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : https://en.wikipedia.org/wiki/.mq +mq + +// mr : https://en.wikipedia.org/wiki/.mr +mr +gov.mr + +// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf +ms +com.ms +edu.ms +gov.ms +net.ms +org.ms + +// mt : https://www.nic.org.mt/go/policy +// Submitted by registry +mt +com.mt +edu.mt +net.mt +org.mt + +// mu : https://en.wikipedia.org/wiki/.mu +mu +com.mu +net.mu +org.mu +gov.mu +ac.mu +co.mu +or.mu + +// museum : http://about.museum/naming/ +// http://index.museum/ +museum +academy.museum +agriculture.museum +air.museum +airguard.museum +alabama.museum +alaska.museum +amber.museum +ambulance.museum +american.museum +americana.museum +americanantiques.museum +americanart.museum +amsterdam.museum +and.museum +annefrank.museum +anthro.museum +anthropology.museum +antiques.museum +aquarium.museum +arboretum.museum +archaeological.museum +archaeology.museum +architecture.museum +art.museum +artanddesign.museum +artcenter.museum +artdeco.museum +arteducation.museum +artgallery.museum +arts.museum +artsandcrafts.museum +asmatart.museum +assassination.museum +assisi.museum +association.museum +astronomy.museum +atlanta.museum +austin.museum +australia.museum +automotive.museum +aviation.museum +axis.museum +badajoz.museum +baghdad.museum +bahn.museum +bale.museum +baltimore.museum +barcelona.museum +baseball.museum +basel.museum +baths.museum +bauern.museum +beauxarts.museum +beeldengeluid.museum +bellevue.museum +bergbau.museum +berkeley.museum +berlin.museum +bern.museum +bible.museum +bilbao.museum +bill.museum +birdart.museum +birthplace.museum +bonn.museum +boston.museum +botanical.museum +botanicalgarden.museum +botanicgarden.museum +botany.museum +brandywinevalley.museum +brasil.museum +bristol.museum +british.museum +britishcolumbia.museum +broadcast.museum +brunel.museum +brussel.museum +brussels.museum +bruxelles.museum +building.museum +burghof.museum +bus.museum +bushey.museum +cadaques.museum +california.museum +cambridge.museum +can.museum +canada.museum +capebreton.museum +carrier.museum +cartoonart.museum +casadelamoneda.museum +castle.museum +castres.museum +celtic.museum +center.museum +chattanooga.museum +cheltenham.museum +chesapeakebay.museum +chicago.museum +children.museum +childrens.museum +childrensgarden.museum +chiropractic.museum +chocolate.museum +christiansburg.museum +cincinnati.museum +cinema.museum +circus.museum +civilisation.museum +civilization.museum +civilwar.museum +clinton.museum +clock.museum +coal.museum +coastaldefence.museum +cody.museum +coldwar.museum +collection.museum +colonialwilliamsburg.museum +coloradoplateau.museum +columbia.museum +columbus.museum +communication.museum +communications.museum +community.museum +computer.museum +computerhistory.museum +comunicações.museum +contemporary.museum +contemporaryart.museum +convent.museum +copenhagen.museum +corporation.museum +correios-e-telecomunicações.museum +corvette.museum +costume.museum +countryestate.museum +county.museum +crafts.museum +cranbrook.museum +creation.museum +cultural.museum +culturalcenter.museum +culture.museum +cyber.museum +cymru.museum +dali.museum +dallas.museum +database.museum +ddr.museum +decorativearts.museum +delaware.museum +delmenhorst.museum +denmark.museum +depot.museum +design.museum +detroit.museum +dinosaur.museum +discovery.museum +dolls.museum +donostia.museum +durham.museum +eastafrica.museum +eastcoast.museum +education.museum +educational.museum +egyptian.museum +eisenbahn.museum +elburg.museum +elvendrell.museum +embroidery.museum +encyclopedic.museum +england.museum +entomology.museum +environment.museum +environmentalconservation.museum +epilepsy.museum +essex.museum +estate.museum +ethnology.museum +exeter.museum +exhibition.museum +family.museum +farm.museum +farmequipment.museum +farmers.museum +farmstead.museum +field.museum +figueres.museum +filatelia.museum +film.museum +fineart.museum +finearts.museum +finland.museum +flanders.museum +florida.museum +force.museum +fortmissoula.museum +fortworth.museum +foundation.museum +francaise.museum +frankfurt.museum +franziskaner.museum +freemasonry.museum +freiburg.museum +fribourg.museum +frog.museum +fundacio.museum +furniture.museum +gallery.museum +garden.museum +gateway.museum +geelvinck.museum +gemological.museum +geology.museum +georgia.museum +giessen.museum +glas.museum +glass.museum +gorge.museum +grandrapids.museum +graz.museum +guernsey.museum +halloffame.museum +hamburg.museum +handson.museum +harvestcelebration.museum +hawaii.museum +health.museum +heimatunduhren.museum +hellas.museum +helsinki.museum +hembygdsforbund.museum +heritage.museum +histoire.museum +historical.museum +historicalsociety.museum +historichouses.museum +historisch.museum +historisches.museum +history.museum +historyofscience.museum +horology.museum +house.museum +humanities.museum +illustration.museum +imageandsound.museum +indian.museum +indiana.museum +indianapolis.museum +indianmarket.museum +intelligence.museum +interactive.museum +iraq.museum +iron.museum +isleofman.museum +jamison.museum +jefferson.museum +jerusalem.museum +jewelry.museum +jewish.museum +jewishart.museum +jfk.museum +journalism.museum +judaica.museum +judygarland.museum +juedisches.museum +juif.museum +karate.museum +karikatur.museum +kids.museum +koebenhavn.museum +koeln.museum +kunst.museum +kunstsammlung.museum +kunstunddesign.museum +labor.museum +labour.museum +lajolla.museum +lancashire.museum +landes.museum +lans.museum +läns.museum +larsson.museum +lewismiller.museum +lincoln.museum +linz.museum +living.museum +livinghistory.museum +localhistory.museum +london.museum +losangeles.museum +louvre.museum +loyalist.museum +lucerne.museum +luxembourg.museum +luzern.museum +mad.museum +madrid.museum +mallorca.museum +manchester.museum +mansion.museum +mansions.museum +manx.museum +marburg.museum +maritime.museum +maritimo.museum +maryland.museum +marylhurst.museum +media.museum +medical.museum +medizinhistorisches.museum +meeres.museum +memorial.museum +mesaverde.museum +michigan.museum +midatlantic.museum +military.museum +mill.museum +miners.museum +mining.museum +minnesota.museum +missile.museum +missoula.museum +modern.museum +moma.museum +money.museum +monmouth.museum +monticello.museum +montreal.museum +moscow.museum +motorcycle.museum +muenchen.museum +muenster.museum +mulhouse.museum +muncie.museum +museet.museum +museumcenter.museum +museumvereniging.museum +music.museum +national.museum +nationalfirearms.museum +nationalheritage.museum +nativeamerican.museum +naturalhistory.museum +naturalhistorymuseum.museum +naturalsciences.museum +nature.museum +naturhistorisches.museum +natuurwetenschappen.museum +naumburg.museum +naval.museum +nebraska.museum +neues.museum +newhampshire.museum +newjersey.museum +newmexico.museum +newport.museum +newspaper.museum +newyork.museum +niepce.museum +norfolk.museum +north.museum +nrw.museum +nuernberg.museum +nuremberg.museum +nyc.museum +nyny.museum +oceanographic.museum +oceanographique.museum +omaha.museum +online.museum +ontario.museum +openair.museum +oregon.museum +oregontrail.museum +otago.museum +oxford.museum +pacific.museum +paderborn.museum +palace.museum +paleo.museum +palmsprings.museum +panama.museum +paris.museum +pasadena.museum +pharmacy.museum +philadelphia.museum +philadelphiaarea.museum +philately.museum +phoenix.museum +photography.museum +pilots.museum +pittsburgh.museum +planetarium.museum +plantation.museum +plants.museum +plaza.museum +portal.museum +portland.museum +portlligat.museum +posts-and-telecommunications.museum +preservation.museum +presidio.museum +press.museum +project.museum +public.museum +pubol.museum +quebec.museum +railroad.museum +railway.museum +research.museum +resistance.museum +riodejaneiro.museum +rochester.museum +rockart.museum +roma.museum +russia.museum +saintlouis.museum +salem.museum +salvadordali.museum +salzburg.museum +sandiego.museum +sanfrancisco.museum +santabarbara.museum +santacruz.museum +santafe.museum +saskatchewan.museum +satx.museum +savannahga.museum +schlesisches.museum +schoenbrunn.museum +schokoladen.museum +school.museum +schweiz.museum +science.museum +scienceandhistory.museum +scienceandindustry.museum +sciencecenter.museum +sciencecenters.museum +science-fiction.museum +sciencehistory.museum +sciences.museum +sciencesnaturelles.museum +scotland.museum +seaport.museum +settlement.museum +settlers.museum +shell.museum +sherbrooke.museum +sibenik.museum +silk.museum +ski.museum +skole.museum +society.museum +sologne.museum +soundandvision.museum +southcarolina.museum +southwest.museum +space.museum +spy.museum +square.museum +stadt.museum +stalbans.museum +starnberg.museum +state.museum +stateofdelaware.museum +station.museum +steam.museum +steiermark.museum +stjohn.museum +stockholm.museum +stpetersburg.museum +stuttgart.museum +suisse.museum +surgeonshall.museum +surrey.museum +svizzera.museum +sweden.museum +sydney.museum +tank.museum +tcm.museum +technology.museum +telekommunikation.museum +television.museum +texas.museum +textile.museum +theater.museum +time.museum +timekeeping.museum +topology.museum +torino.museum +touch.museum +town.museum +transport.museum +tree.museum +trolley.museum +trust.museum +trustee.museum +uhren.museum +ulm.museum +undersea.museum +university.museum +usa.museum +usantiques.museum +usarts.museum +uscountryestate.museum +usculture.museum +usdecorativearts.museum +usgarden.museum +ushistory.museum +ushuaia.museum +uslivinghistory.museum +utah.museum +uvic.museum +valley.museum +vantaa.museum +versailles.museum +viking.museum +village.museum +virginia.museum +virtual.museum +virtuel.museum +vlaanderen.museum +volkenkunde.museum +wales.museum +wallonie.museum +war.museum +washingtondc.museum +watchandclock.museum +watch-and-clock.museum +western.museum +westfalen.museum +whaling.museum +wildlife.museum +williamsburg.museum +windmill.museum +workshop.museum +york.museum +yorkshire.museum +yosemite.museum +youth.museum +zoological.museum +zoology.museum +ירושלים.museum +иком.museum + +// mv : https://en.wikipedia.org/wiki/.mv +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +museum.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry +mx +com.mx +org.mx +gob.mx +edu.mx +net.mx + +// my : http://www.mynic.net.my/ +my +com.my +net.my +org.my +gov.my +edu.my +mil.my +name.my + +// mz : http://www.uem.mz/ +// Submitted by registry +mz +ac.mz +adv.mz +co.mz +edu.mz +gov.mz +mil.mz +net.mz +org.mz + +// na : http://www.na-nic.com.na/ +// http://www.info.na/domain/ +na +info.na +pro.na +name.na +school.na +or.na +dr.na +us.na +mx.na +ca.na +in.na +cc.na +tv.na +ws.na +mobi.na +co.na +com.na +org.na + +// name : has 2nd-level tlds, but there's no list of them +name + +// nc : http://www.cctld.nc/ +nc +asso.nc +nom.nc + +// ne : https://en.wikipedia.org/wiki/.ne +ne + +// net : https://en.wikipedia.org/wiki/.net +net + +// nf : https://en.wikipedia.org/wiki/.nf +nf +com.nf +net.nf +per.nf +rec.nf +web.nf +arts.nf +firm.nf +info.nf +other.nf +store.nf + +// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds +ng +com.ng +edu.ng +gov.ng +i.ng +mil.ng +mobi.ng +name.ng +net.ng +org.ng +sch.ng + +// ni : http://www.nic.ni/ +ni +ac.ni +biz.ni +co.ni +com.ni +edu.ni +gob.ni +in.ni +info.ni +int.ni +mil.ni +net.ni +nom.ni +org.ni +web.ni + +// nl : https://en.wikipedia.org/wiki/.nl +// https://www.sidn.nl/ +// ccTLD for the Netherlands +nl + +// BV.nl will be a registry for dutch BV's (besloten vennootschap) +bv.nl + +// no : http://www.norid.no/regelverk/index.en.html +// The Norwegian registry has declined to notify us of updates. The web pages +// referenced below are the official source of the data. There is also an +// announce mailing list: +// https://postlister.uninett.no/sympa/info/norid-diskusjon +no +// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html +fhs.no +vgs.no +fylkesbibl.no +folkebibl.no +museum.no +idrett.no +priv.no +// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html +mil.no +stat.no +dep.no +kommune.no +herad.no +// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +åkrehamn.no +algard.no +ålgård.no +arna.no +brumunddal.no +bryne.no +bronnoysund.no +brønnøysund.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevåg.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +råholt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +afjord.no +åfjord.no +agdenes.no +al.no +ål.no +alesund.no +ålesund.no +alstahaug.no +alta.no +áltá.no +alaheadju.no +álaheadju.no +alvdal.no +amli.no +åmli.no +amot.no +åmot.no +andebu.no +andoy.no +andøy.no +andasuolo.no +ardal.no +årdal.no +aremark.no +arendal.no +ås.no +aseral.no +åseral.no +asker.no +askim.no +askvoll.no +askoy.no +askøy.no +asnes.no +åsnes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +balestrand.no +ballangen.no +balat.no +bálát.no +balsfjord.no +bahccavuotna.no +báhccavuotna.no +bamble.no +bardu.no +beardu.no +beiarn.no +bajddar.no +bájddar.no +baidar.no +báidár.no +berg.no +bergen.no +berlevag.no +berlevåg.no +bearalvahki.no +bearalváhki.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +badaddja.no +bådåddjå.no +budejju.no +bokn.no +bremanger.no +bronnoy.no +brønnøy.no +bygland.no +bykle.no +barum.no +bærum.no +bo.telemark.no +bø.telemark.no +bo.nordland.no +bø.nordland.no +bievat.no +bievát.no +bomlo.no +bømlo.no +batsfjord.no +båtsfjord.no +bahcavuotna.no +báhcavuotna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +donna.no +dønna.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenes.no +evenassi.no +evenášši.no +evje-og-hornnes.no +farsund.no +fauske.no +fuossko.no +fuoisku.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +fla.no +flå.no +folldal.no +forsand.no +fosnes.no +frei.no +frogn.no +froland.no +frosta.no +frana.no +fræna.no +froya.no +frøya.no +fusa.no +fyresdal.no +forde.no +førde.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +gildeskal.no +gildeskål.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +kraanghke.no +kråanghke.no +grue.no +gulen.no +hadsel.no +halden.no +halsa.no +hamar.no +hamaroy.no +habmer.no +hábmer.no +hapmir.no +hápmir.no +hammerfest.no +hammarfeasta.no +hámmárfeasta.no +haram.no +hareid.no +harstad.no +hasvik.no +aknoluokta.no +ákŋoluokta.no +hattfjelldal.no +aarborte.no +haugesund.no +hemne.no +hemnes.no +hemsedal.no +heroy.more-og-romsdal.no +herøy.møre-og-romsdal.no +heroy.nordland.no +herøy.nordland.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtålen.no +hornindal.no +horten.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +hagebostad.no +hægebostad.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +ha.no +hå.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +jevnaker.no +jondal.no +jolster.no +jølster.no +karasjok.no +karasjohka.no +kárášjohka.no +karlsoy.no +galsa.no +gálsá.no +karmoy.no +karmøy.no +kautokeino.no +guovdageaidnu.no +klepp.no +klabu.no +klæbu.no +kongsberg.no +kongsvinger.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvalsund.no +rahkkeravju.no +ráhkkerávju.no +kvam.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +kvafjord.no +kvæfjord.no +giehtavuoatna.no +kvanangen.no +kvænangen.no +navuotna.no +návuotna.no +kafjord.no +kåfjord.no +gaivuotna.no +gáivuotna.no +larvik.no +lavangen.no +lavagis.no +loabat.no +loabát.no +lebesby.no +davvesiida.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +leangaviika.no +leaŋgaviika.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindesnes.no +lindas.no +lindås.no +lom.no +loppa.no +lahppi.no +láhppi.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +ivgu.no +lardal.no +lerdal.no +lærdal.no +lodingen.no +lødingen.no +lorenskog.no +lørenskog.no +loten.no +løten.no +malvik.no +masoy.no +måsøy.no +muosat.no +muosát.no +mandal.no +marker.no +marnardal.no +masfjorden.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +meråker.no +moareke.no +moåreke.no +midsund.no +midtre-gauldal.no +modalen.no +modum.no +molde.no +moskenes.no +moss.no +mosvik.no +malselv.no +målselv.no +malatvuopmi.no +málatvuopmi.no +namdalseid.no +aejrie.no +namsos.no +namsskogan.no +naamesjevuemie.no +nååmesjevuemie.no +laakesvuemie.no +nannestad.no +narvik.no +narviika.no +naustdal.no +nedre-eiker.no +nes.akershus.no +nes.buskerud.no +nesna.no +nesodden.no +nesseby.no +unjarga.no +unjárga.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +davvenjarga.no +davvenjárga.no +nordre-land.no +nordreisa.no +raisa.no +ráisa.no +nore-og-uvdal.no +notodden.no +naroy.no +nærøy.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +oppdal.no +oppegard.no +oppegård.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +os.hedmark.no +os.hordaland.no +osen.no +osteroy.no +osterøy.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +radoy.no +radøy.no +rakkestad.no +rana.no +ruovat.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +rissa.no +risor.no +risør.no +roan.no +rollag.no +rygge.no +ralingen.no +rælingen.no +rodoy.no +rødøy.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +rade.no +råde.no +salangen.no +siellak.no +saltdal.no +salat.no +sálát.no +sálat.no +samnanger.no +sande.more-og-romsdal.no +sande.møre-og-romsdal.no +sande.vestfold.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +sigdal.no +siljan.no +sirdal.no +skaun.no +skedsmo.no +ski.no +skien.no +skiptvet.no +skjervoy.no +skjervøy.no +skierva.no +skiervá.no +skjak.no +skjåk.no +skodje.no +skanland.no +skånland.no +skanit.no +skánit.no +smola.no +smøla.no +snillfjord.no +snasa.no +snåsa.no +snoasa.no +snaase.no +snåase.no +sogndal.no +sokndal.no +sola.no +solund.no +songdalen.no +sortland.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +omasvuotna.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +sogne.no +søgne.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +matta-varjjat.no +mátta-várjjat.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sorum.no +sørum.no +tana.no +deatnu.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +dielddanuorri.no +tjome.no +tjøme.no +tokke.no +tolga.no +torsken.no +tranoy.no +tranøy.no +tromso.no +tromsø.no +tromsa.no +romsa.no +trondheim.no +troandin.no +trysil.no +trana.no +træna.no +trogstad.no +trøgstad.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +divtasvuodna.no +divttasvuotna.no +tysnes.no +tysvar.no +tysvær.no +tonsberg.no +tønsberg.no +ullensaker.no +ullensvang.no +ulvik.no +utsira.no +vadso.no +vadsø.no +cahcesuolo.no +čáhcesuolo.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +vefsn.no +vaapste.no +vega.no +vegarshei.no +vegårshei.no +vennesla.no +verdal.no +verran.no +vestby.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvågøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +volda.no +voss.no +varoy.no +værøy.no +vagan.no +vågan.no +voagat.no +vagsoy.no +vågsøy.no +vaga.no +vågå.no +valer.ostfold.no +våler.østfold.no +valer.hedmark.no +våler.hedmark.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Submitted by registry +nr +biz.nr +info.nr +gov.nr +edu.nr +org.nr +net.nr +com.nr + +// nu : https://en.wikipedia.org/wiki/.nu +nu + +// nz : https://en.wikipedia.org/wiki/.nz +// Submitted by registry +nz +ac.nz +co.nz +cri.nz +geek.nz +gen.nz +govt.nz +health.nz +iwi.nz +kiwi.nz +maori.nz +mil.nz +māori.nz +net.nz +org.nz +parliament.nz +school.nz + +// om : https://en.wikipedia.org/wiki/.om +om +co.om +com.om +edu.om +gov.om +med.om +museum.om +net.om +org.om +pro.om + +// onion : https://tools.ietf.org/html/rfc7686 +onion + +// org : https://en.wikipedia.org/wiki/.org +org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +ac.pa +gob.pa +com.pa +org.pa +sld.pa +edu.pa +net.pa +ing.pa +abo.pa +med.pa +nom.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +edu.pe +gob.pe +nom.pe +mil.pe +org.pe +com.pe +net.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +org.pf +edu.pf + +// pg : https://en.wikipedia.org/wiki/.pg +*.pg + +// ph : http://www.domains.ph/FAQ2.asp +// Submitted by registry +ph +com.ph +net.ph +org.ph +gov.ph +edu.ph +ngo.ph +mil.ph +i.ph + +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +pk +com.pk +net.pk +edu.pk +org.pk +fam.pk +biz.pk +web.pk +gov.pk +gob.pk +gok.pk +gon.pk +gop.pk +gos.pk +info.pk + +// pl http://www.dns.pl/english/index.html +// Submitted by registry +pl +com.pl +net.pl +org.pl +// pl functional domains (http://www.dns.pl/english/index.html) +aid.pl +agro.pl +atm.pl +auto.pl +biz.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +miasta.pl +media.pl +mil.pl +nieruchomosci.pl +nom.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// Government domains +gov.pl +ap.gov.pl +ic.gov.pl +is.gov.pl +us.gov.pl +kmpsp.gov.pl +kppsp.gov.pl +kwpsp.gov.pl +psp.gov.pl +wskr.gov.pl +kwp.gov.pl +mw.gov.pl +ug.gov.pl +um.gov.pl +umig.gov.pl +ugim.gov.pl +upow.gov.pl +uw.gov.pl +starostwo.gov.pl +pa.gov.pl +po.gov.pl +psse.gov.pl +pup.gov.pl +rzgw.gov.pl +sa.gov.pl +so.gov.pl +sr.gov.pl +wsa.gov.pl +sko.gov.pl +uzs.gov.pl +wiih.gov.pl +winb.gov.pl +pinb.gov.pl +wios.gov.pl +witd.gov.pl +wzmiuw.gov.pl +piw.gov.pl +wiw.gov.pl +griw.gov.pl +wif.gov.pl +oum.gov.pl +sdn.gov.pl +zp.gov.pl +uppo.gov.pl +mup.gov.pl +wuoz.gov.pl +konsulat.gov.pl +oirm.gov.pl +// pl regional domains (http://www.dns.pl/english/index.html) +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +kazimierz-dolny.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorze.pl +pomorskie.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +skoczow.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl + +// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +pm + +// pn : http://www.government.pn/PnRegistry/policies.htm +pn +gov.pn +co.pn +org.pn +edu.pn +net.pn + +// post : https://en.wikipedia.org/wiki/.post +post + +// pr : http://www.nic.pr/index.asp?f=1 +pr +com.pr +net.pr +org.pr +gov.pr +edu.pr +isla.pr +pro.pr +biz.pr +info.pr +name.pr +// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr +est.pr +prof.pr +ac.pr + +// pro : http://registry.pro/get-pro +pro +aaa.pro +aca.pro +acct.pro +avocat.pro +bar.pro +cpa.pro +eng.pro +jur.pro +law.pro +med.pro +recht.pro + +// ps : https://en.wikipedia.org/wiki/.ps +// http://www.nic.ps/registration/policy.html#reg +ps +edu.ps +gov.ps +sec.ps +plo.ps +com.ps +org.ps +net.ps + +// pt : http://online.dns.pt/dns/start_dns +pt +net.pt +gov.pt +org.pt +edu.pt +int.pt +publ.pt +com.pt +nome.pt + +// pw : https://en.wikipedia.org/wiki/.pw +pw +co.pw +ne.pw +or.pw +ed.pw +go.pw +belau.pw + +// py : http://www.nic.py/pautas.html#seccion_9 +// Submitted by registry +py +com.py +coop.py +edu.py +gov.py +mil.py +net.py +org.py + +// qa : http://domains.qa/en/ +qa +com.qa +edu.qa +gov.qa +mil.qa +name.qa +net.qa +org.qa +sch.qa + +// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +re +asso.re +com.re +nom.re + +// ro : http://www.rotld.ro/ +ro +arts.ro +com.ro +firm.ro +info.ro +nom.ro +nt.ro +org.ro +rec.ro +store.ro +tm.ro +www.ro + +// rs : https://www.rnids.rs/en/domains/national-domains +rs +ac.rs +co.rs +edu.rs +gov.rs +in.rs +org.rs + +// ru : https://cctld.ru/en/domains/domens_ru/reserved/ +ru +ac.ru +edu.ru +gov.ru +int.ru +mil.ru +test.ru + +// rw : http://www.nic.rw/cgi-bin/policy.pl +rw +gov.rw +net.rw +edu.rw +ac.rw +com.rw +co.rw +int.rw +mil.rw +gouv.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +net.sa +org.sa +gov.sa +med.sa +pub.sa +edu.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +gov.sc +net.sc +org.sc +edu.sc + +// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// Submitted by registry +sd +com.sd +net.sd +org.sd +edu.sd +med.sd +tv.sd +gov.sd +info.sd + +// se : https://en.wikipedia.org/wiki/.se +// Submitted by registry +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +sg +com.sg +net.sg +org.sg +gov.sg +edu.sg +per.sg + +// sh : http://www.nic.sh/registrar.html +sh +com.sh +net.sh +gov.sh +org.sh +mil.sh + +// si : https://en.wikipedia.org/wiki/.si +si + +// sj : No registrations at this time. +// Submitted by registry +sj + +// sk : https://en.wikipedia.org/wiki/.sk +// list of 2nd level domains ? +sk + +// sl : http://www.nic.sl +// Submitted by registry +sl +com.sl +net.sl +edu.sl +gov.sl +org.sl + +// sm : https://en.wikipedia.org/wiki/.sm +sm + +// sn : https://en.wikipedia.org/wiki/.sn +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://www.soregistry.com/ +so +com.so +net.so +org.so + +// sr : https://en.wikipedia.org/wiki/.sr +sr + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +gov.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : https://en.wikipedia.org/wiki/.su +su + +// sv : http://www.svnet.org.sv/niveldos.pdf +sv +com.sv +edu.sv +gob.sv +org.sv +red.sv + +// sx : https://en.wikipedia.org/wiki/.sx +// Submitted by registry +sx +gov.sx + +// sy : https://en.wikipedia.org/wiki/.sy +// see also: http://www.gobin.info/domainname/sy.doc +sy +edu.sy +gov.sy +net.sy +mil.sy +com.sy +org.sy + +// sz : https://en.wikipedia.org/wiki/.sz +// http://www.sispa.org.sz/ +sz +co.sz +ac.sz +org.sz + +// tc : https://en.wikipedia.org/wiki/.tc +tc + +// td : https://en.wikipedia.org/wiki/.td +td + +// tel: https://en.wikipedia.org/wiki/.tel +// http://www.telnic.org/ +tel + +// tf : https://en.wikipedia.org/wiki/.tf +tf + +// tg : https://en.wikipedia.org/wiki/.tg +// http://www.nic.tg/ +tg + +// th : https://en.wikipedia.org/wiki/.th +// Submitted by registry +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.html +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : https://en.wikipedia.org/wiki/.tk +tk + +// tl : https://en.wikipedia.org/wiki/.tl +tl +gov.tl + +// tm : http://www.nic.tm/local.html +tm +com.tm +co.tm +org.tm +net.tm +nom.tm +gov.tm +mil.tm +edu.tm + +// tn : https://en.wikipedia.org/wiki/.tn +// http://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +intl.tn +nat.tn +net.tn +org.tn +info.tn +perso.tn +tourism.tn +edunet.tn +rnrt.tn +rns.tn +rnu.tn +mincom.tn +agrinet.tn +defense.tn +turen.tn + +// to : https://en.wikipedia.org/wiki/.to +// Submitted by registry +to +com.to +gov.to +net.to +org.to +edu.to +mil.to + +// subTLDs: https://www.nic.tr/forms/eng/policies.pdf +// and: https://www.nic.tr/forms/politikalar.pdf +// Submitted by +tr +com.tr +info.tr +biz.tr +net.tr +org.tr +web.tr +gen.tr +tv.tr +av.tr +dr.tr +bbs.tr +name.tr +tel.tr +gov.tr +bel.tr +pol.tr +mil.tr +k12.tr +edu.tr +kep.tr + +// Used by Northern Cyprus +nc.tr + +// Used by government agencies of Northern Cyprus +gov.nc.tr + +// travel : https://en.wikipedia.org/wiki/.travel +travel + +// tt : http://www.nic.tt/ +tt +co.tt +com.tt +org.tt +net.tt +biz.tt +info.tt +pro.tt +int.tt +coop.tt +jobs.tt +mobi.tt +travel.tt +museum.tt +aero.tt +name.tt +gov.tt +edu.tt + +// tv : https://en.wikipedia.org/wiki/.tv +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : https://en.wikipedia.org/wiki/.tw +tw +edu.tw +gov.tw +mil.tw +com.tw +net.tw +org.tw +idv.tw +game.tw +ebiz.tw +club.tw +網路.tw +組織.tw +商業.tw + +// tz : http://www.tznic.or.tz/index.php/domains +// Submitted by registry +tz +ac.tz +co.tz +go.tz +hotel.tz +info.tz +me.tz +mil.tz +mobi.tz +ne.tz +or.tz +sc.tz +tv.tz + +// ua : https://hostmaster.ua/policy/?ua +// Submitted by registry +ua +// ua 2LD +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geographic names +// https://hostmaster.ua/2ld/ +cherkassy.ua +cherkasy.ua +chernigov.ua +chernihiv.ua +chernivtsi.ua +chernovtsy.ua +ck.ua +cn.ua +cr.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +dnipropetrovsk.ua +dominic.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkiv.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +khmelnytskyi.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +krym.ua +ks.ua +kv.ua +kyiv.ua +lg.ua +lt.ua +lugansk.ua +lutsk.ua +lv.ua +lviv.ua +mk.ua +mykolaiv.ua +nikolaev.ua +od.ua +odesa.ua +odessa.ua +pl.ua +poltava.ua +rivne.ua +rovno.ua +rv.ua +sb.ua +sebastopol.ua +sevastopol.ua +sm.ua +sumy.ua +te.ua +ternopil.ua +uz.ua +uzhgorod.ua +vinnica.ua +vinnytsia.ua +vn.ua +volyn.ua +yalta.ua +zaporizhzhe.ua +zaporizhzhia.ua +zhitomir.ua +zhytomyr.ua +zp.ua +zt.ua + +// ug : https://www.registry.co.ug/ +ug +co.ug +or.ug +ac.ug +sc.ug +go.ug +ne.ug +com.ug +org.ug + +// uk : https://en.wikipedia.org/wiki/.uk +// Submitted by registry +uk +ac.uk +co.uk +gov.uk +ltd.uk +me.uk +net.uk +nhs.uk +org.uk +plc.uk +police.uk +*.sch.uk + +// us : https://en.wikipedia.org/wiki/.us +us +dni.us +fed.us +isa.us +kids.us +nsn.us +// us geographic names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +vi.us +vt.us +va.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.de.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +k12.ri.us +k12.sc.us +// k12.sd.us Bug 934131 - Removed at request of James Booze +k12.tn.us +k12.tx.us +k12.ut.us +k12.vi.us +k12.vt.us +k12.va.us +k12.wa.us +k12.wi.us +// k12.wv.us Bug 947705 - Removed at request of Verne Britton +k12.wy.us +cc.ak.us +cc.al.us +cc.ar.us +cc.as.us +cc.az.us +cc.ca.us +cc.co.us +cc.ct.us +cc.dc.us +cc.de.us +cc.fl.us +cc.ga.us +cc.gu.us +cc.hi.us +cc.ia.us +cc.id.us +cc.il.us +cc.in.us +cc.ks.us +cc.ky.us +cc.la.us +cc.ma.us +cc.md.us +cc.me.us +cc.mi.us +cc.mn.us +cc.mo.us +cc.ms.us +cc.mt.us +cc.nc.us +cc.nd.us +cc.ne.us +cc.nh.us +cc.nj.us +cc.nm.us +cc.nv.us +cc.ny.us +cc.oh.us +cc.ok.us +cc.or.us +cc.pa.us +cc.pr.us +cc.ri.us +cc.sc.us +cc.sd.us +cc.tn.us +cc.tx.us +cc.ut.us +cc.vi.us +cc.vt.us +cc.va.us +cc.wa.us +cc.wi.us +cc.wv.us +cc.wy.us +lib.ak.us +lib.al.us +lib.ar.us +lib.as.us +lib.az.us +lib.ca.us +lib.co.us +lib.ct.us +lib.dc.us +// lib.de.us Issue #243 - Moved to Private section at request of Ed Moore +lib.fl.us +lib.ga.us +lib.gu.us +lib.hi.us +lib.ia.us +lib.id.us +lib.il.us +lib.in.us +lib.ks.us +lib.ky.us +lib.la.us +lib.ma.us +lib.md.us +lib.me.us +lib.mi.us +lib.mn.us +lib.mo.us +lib.ms.us +lib.mt.us +lib.nc.us +lib.nd.us +lib.ne.us +lib.nh.us +lib.nj.us +lib.nm.us +lib.nv.us +lib.ny.us +lib.oh.us +lib.ok.us +lib.or.us +lib.pa.us +lib.pr.us +lib.ri.us +lib.sc.us +lib.sd.us +lib.tn.us +lib.tx.us +lib.ut.us +lib.vi.us +lib.vt.us +lib.va.us +lib.wa.us +lib.wi.us +// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold +lib.wy.us +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed independently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated directly to the +// 5LD operators. +pvt.k12.ma.us +chtr.k12.ma.us +paroch.k12.ma.us +// Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following +// see also: http://domreg.merit.edu +// see also: whois -h whois.domreg.merit.edu help +ann-arbor.mi.us +cog.mi.us +dst.mi.us +eaton.mi.us +gen.mi.us +mus.mi.us +tec.mi.us +washtenaw.mi.us + +// uy : http://www.nic.org.uy/ +uy +com.uy +edu.uy +gub.uy +mil.uy +net.uy +org.uy + +// uz : http://www.reg.uz/ +uz +co.uz +com.uz +net.uz +org.uz + +// va : https://en.wikipedia.org/wiki/.va +va + +// vc : https://en.wikipedia.org/wiki/.vc +// Submitted by registry +vc +com.vc +net.vc +org.vc +gov.vc +mil.vc +edu.vc + +// ve : https://registro.nic.ve/ +// Submitted by registry +ve +arts.ve +co.ve +com.ve +e12.ve +edu.ve +firm.ve +gob.ve +gov.ve +info.ve +int.ve +mil.ve +net.ve +org.ve +rec.ve +store.ve +tec.ve +web.ve + +// vg : https://en.wikipedia.org/wiki/.vg +vg + +// vi : http://www.nic.vi/newdomainform.htm +// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other +// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they +// are available for registration (which they do not seem to be). +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +vn +com.vn +net.vn +org.vn +edu.vn +gov.vn +int.vn +ac.vn +biz.vn +info.vn +name.vn +pro.vn +health.vn + +// vu : https://en.wikipedia.org/wiki/.vu +// http://www.vunic.vu/ +vu +com.vu +edu.vu +net.vu +org.vu + +// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +wf + +// ws : https://en.wikipedia.org/wiki/.ws +// http://samoanic.ws/index.dhtml +ws +com.ws +net.ws +org.ws +gov.ws +edu.ws + +// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +yt + +// IDN ccTLDs +// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then +// U-label, and follow this format: +// // A-Label ("", [, variant info]) : +// // [sponsoring org] +// U-Label + +// xn--mgbaam7a8h ("Emerat", Arabic) : AE +// http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--y9a3aq ("hye", Armenian) : AM +// ISOC AM (operated by .am Registry) +հայ + +// xn--54b7fta0cc ("Bangla", Bangla) : BD +বাংলা + +// xn--90ae ("bg", Bulgarian) : BG +бг + +// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY +// Operated by .by registry +бел + +// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中国 + +// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中國 + +// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt/Masr", Arabic) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--e1a4c ("eu", Cyrillic) : EU +ею + +// xn--node ("ge", Georgian Mkhedruli) : GE +გე + +// xn--qxam ("el", Greek) : GR +// Hellenic Ministry of Infrastructure, Transport, and Networks +ελ + +// xn--j6w193g ("Hong Kong", Chinese) : HK +// https://www2.hkirc.hk/register/rules.jsp +香港 + +// xn--2scrj9c ("Bharat", Kannada) : IN +// India +ಭಾರತ + +// xn--3hcrj9c ("Bharat", Oriya) : IN +// India +ଭାରତ + +// xn--45br5cyl ("Bharatam", Assamese) : IN +// India +ভাৰত + +// xn--h2breg3eve ("Bharatam", Sanskrit) : IN +// India +भारतम् + +// xn--h2brj9c8c ("Bharot", Santali) : IN +// India +भारोत + +// xn--mgbgu82a ("Bharat", Sindhi) : IN +// India +ڀارت + +// xn--rvc1e0am3e ("Bharatam", Malayalam) : IN +// India +ഭാരതം + +// xn--h2brj9c ("Bharat", Devanagari) : IN +// India +भारत + +// xn--mgbbh1a71e ("Bharat", Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat", Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat", Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat", Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat", Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India", Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran", Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran", Arabic) : IR +ايران + +// xn--mgbtx2b ("Iraq", Arabic) : IQ +// Communications and Media Commission +عراق + +// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO +// National Information Technology Center (NITC) +// Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea", Hangul) : KR +한국 + +// xn--80ao21a ("Kaz", Kazakh) : KZ +қаз + +// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK +// http://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK +// http://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA +المغرب + +// xn--d1alf ("mkd", Macedonian) : MK +// MARnet +мкд + +// xn--l1acc ("mon", Mongolian) : MN +мон + +// xn--mix891f ("Macao", Chinese, Traditional) : MO +// MONIC / HNET Asia (Registry Operator for .mo) +澳門 + +// xn--mix082f ("Macao", Chinese, Simplified) : MO +澳门 + +// xn--mgbx4cd0ab ("Malaysia", Malay) : MY +مليسيا + +// xn--mgb9awbf ("Oman", Arabic) : OM +عمان + +// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK +پاکستان + +// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK +پاكستان + +// xn--ygbi2ammx ("Falasteen", Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb", Cyrillic) : RS +// https://www.rnids.rs/en/domains/national-domains +срб +пр.срб +орг.срб +обр.срб +од.срб +упр.срб +ак.срб + +// xn--p1ai ("rf", Russian-Cyrillic) : RU +// http://www.cctld.ru/en/docs/rulesrf.php +рф + +// xn--wgbl6a ("Qatar", Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA +السعوديه + +// xn--mgbpl2fh ("sudan", Arabic) : SD +// Operated by .sd registry +سودان + +// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG +சிங்கப்பூர் + +// xn--ogbpf8fl ("Syria", Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria", Arabic, variant) : SY +سوريا + +// xn--o3cw4h ("Thai", Thai) : TH +// http://www.thnic.co.th +ไทย +ศึกษา.ไทย +ธุรกิจ.ไทย +รัฐบาล.ไทย +ทหาร.ไทย +เน็ต.ไทย +องค์กร.ไทย + +// xn--pgbs0dh ("Tunisia", Arabic) : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台灣 + +// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan", Chinese, variant) : TW +臺灣 + +// xn--j1amh ("ukr", Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen", Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +*.ye + +// za : http://www.zadna.org.za/content/page/domain-information +ac.za +agric.za +alt.za +co.za +edu.za +gov.za +grondar.za +law.za +mil.za +net.za +ngo.za +nis.za +nom.za +org.za +school.za +tm.za +web.za + +// zm : https://zicta.zm/ +// Submitted by registry +zm +ac.zm +biz.zm +co.zm +com.zm +edu.zm +gov.zm +info.zm +mil.zm +net.zm +org.zm +sch.zm + +// zw : https://www.potraz.gov.zw/ +// Confirmed by registry 2017-01-25 +zw +ac.zw +co.zw +gov.zw +mil.zw +org.zw + +// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2017-02-23T00:46:09Z + +// aaa : 2015-02-26 American Automobile Association, Inc. +aaa + +// aarp : 2015-05-21 AARP +aarp + +// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V. +abarth + +// abb : 2014-10-24 ABB Ltd +abb + +// abbott : 2014-07-24 Abbott Laboratories, Inc. +abbott + +// abbvie : 2015-07-30 AbbVie Inc. +abbvie + +// abc : 2015-07-30 Disney Enterprises, Inc. +abc + +// able : 2015-06-25 Able Inc. +able + +// abogado : 2014-04-24 Top Level Domain Holdings Limited +abogado + +// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre +abudhabi + +// academy : 2013-11-07 Half Oaks, LLC +academy + +// accenture : 2014-08-15 Accenture plc +accenture + +// accountant : 2014-11-20 dot Accountant Limited +accountant + +// accountants : 2014-03-20 Knob Town, LLC +accountants + +// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +aco + +// active : 2014-05-01 The Active Network, Inc +active + +// actor : 2013-12-12 United TLD Holdco Ltd. +actor + +// adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC) +adac + +// ads : 2014-12-04 Charleston Road Registry Inc. +ads + +// adult : 2014-10-16 ICM Registry AD LLC +adult + +// aeg : 2015-03-19 Aktiebolaget Electrolux +aeg + +// aetna : 2015-05-21 Aetna Life Insurance Company +aetna + +// afamilycompany : 2015-07-23 Johnson Shareholdings, Inc. +afamilycompany + +// afl : 2014-10-02 Australian Football League +afl + +// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +africa + +// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +agakhan + +// agency : 2013-11-14 Steel Falls, LLC +agency + +// aig : 2014-12-18 American International Group, Inc. +aig + +// aigo : 2015-08-06 aigo Digital Technology Co,Ltd. +aigo + +// airbus : 2015-07-30 Airbus S.A.S. +airbus + +// airforce : 2014-03-06 United TLD Holdco Ltd. +airforce + +// airtel : 2014-10-24 Bharti Airtel Limited +airtel + +// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +akdn + +// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V. +alfaromeo + +// alibaba : 2015-01-15 Alibaba Group Holding Limited +alibaba + +// alipay : 2015-01-15 Alibaba Group Holding Limited +alipay + +// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +allfinanz + +// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company +allstate + +// ally : 2015-06-18 Ally Financial Inc. +ally + +// alsace : 2014-07-02 REGION D ALSACE +alsace + +// alstom : 2015-07-30 ALSTOM +alstom + +// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc. +americanexpress + +// americanfamily : 2015-07-23 AmFam, Inc. +americanfamily + +// amex : 2015-07-31 American Express Travel Related Services Company, Inc. +amex + +// amfam : 2015-07-23 AmFam, Inc. +amfam + +// amica : 2015-05-28 Amica Mutual Insurance Company +amica + +// amsterdam : 2014-07-24 Gemeente Amsterdam +amsterdam + +// analytics : 2014-12-18 Campus IP LLC +analytics + +// android : 2014-08-07 Charleston Road Registry Inc. +android + +// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +anquan + +// anz : 2015-07-31 Australia and New Zealand Banking Group Limited +anz + +// aol : 2015-09-17 AOL Inc. +aol + +// apartments : 2014-12-11 June Maple, LLC +apartments + +// app : 2015-05-14 Charleston Road Registry Inc. +app + +// apple : 2015-05-14 Apple Inc. +apple + +// aquarelle : 2014-07-24 Aquarelle.com +aquarelle + +// arab : 2015-11-12 League of Arab States +arab + +// aramco : 2014-11-20 Aramco Services Company +aramco + +// archi : 2014-02-06 STARTING DOT LIMITED +archi + +// army : 2014-03-06 United TLD Holdco Ltd. +army + +// art : 2016-03-24 UK Creative Ideas Limited +art + +// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +arte + +// asda : 2015-07-31 Wal-Mart Stores, Inc. +asda + +// associates : 2014-03-06 Baxter Hill, LLC +associates + +// athleta : 2015-07-30 The Gap, Inc. +athleta + +// attorney : 2014-03-20 +attorney + +// auction : 2014-03-20 +auction + +// audi : 2015-05-21 AUDI Aktiengesellschaft +audi + +// audible : 2015-06-25 Amazon EU S.à r.l. +audible + +// audio : 2014-03-20 Uniregistry, Corp. +audio + +// auspost : 2015-08-13 Australian Postal Corporation +auspost + +// author : 2014-12-18 Amazon EU S.à r.l. +author + +// auto : 2014-11-13 +auto + +// autos : 2014-01-09 DERAutos, LLC +autos + +// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca +avianca + +// aws : 2015-06-25 Amazon EU S.à r.l. +aws + +// axa : 2013-12-19 AXA SA +axa + +// azure : 2014-12-18 Microsoft Corporation +azure + +// baby : 2015-04-09 Johnson & Johnson Services, Inc. +baby + +// baidu : 2015-01-08 Baidu, Inc. +baidu + +// banamex : 2015-07-30 Citigroup Inc. +banamex + +// bananarepublic : 2015-07-31 The Gap, Inc. +bananarepublic + +// band : 2014-06-12 +band + +// bank : 2014-09-25 fTLD Registry Services LLC +bank + +// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +bar + +// barcelona : 2014-07-24 Municipi de Barcelona +barcelona + +// barclaycard : 2014-11-20 Barclays Bank PLC +barclaycard + +// barclays : 2014-11-20 Barclays Bank PLC +barclays + +// barefoot : 2015-06-11 Gallo Vineyards, Inc. +barefoot + +// bargains : 2013-11-14 Half Hallow, LLC +bargains + +// baseball : 2015-10-29 MLB Advanced Media DH, LLC +baseball + +// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA) +basketball + +// bauhaus : 2014-04-17 Werkhaus GmbH +bauhaus + +// bayern : 2014-01-23 Bayern Connect GmbH +bayern + +// bbc : 2014-12-18 British Broadcasting Corporation +bbc + +// bbt : 2015-07-23 BB&T Corporation +bbt + +// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +bbva + +// bcg : 2015-04-02 The Boston Consulting Group, Inc. +bcg + +// bcn : 2014-07-24 Municipi de Barcelona +bcn + +// beats : 2015-05-14 Beats Electronics, LLC +beats + +// beauty : 2015-12-03 L'Oréal +beauty + +// beer : 2014-01-09 Top Level Domain Holdings Limited +beer + +// bentley : 2014-12-18 Bentley Motors Limited +bentley + +// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +berlin + +// best : 2013-12-19 BestTLD Pty Ltd +best + +// bestbuy : 2015-07-31 BBY Solutions, Inc. +bestbuy + +// bet : 2015-05-07 Afilias plc +bet + +// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +bharti + +// bible : 2014-06-19 American Bible Society +bible + +// bid : 2013-12-19 dot Bid Limited +bid + +// bike : 2013-08-27 Grand Hollow, LLC +bike + +// bing : 2014-12-18 Microsoft Corporation +bing + +// bingo : 2014-12-04 Sand Cedar, LLC +bingo + +// bio : 2014-03-06 STARTING DOT LIMITED +bio + +// black : 2014-01-16 Afilias Limited +black + +// blackfriday : 2014-01-16 Uniregistry, Corp. +blackfriday + +// blanco : 2015-07-16 BLANCO GmbH + Co KG +blanco + +// blockbuster : 2015-07-30 Dish DBS Corporation +blockbuster + +// blog : 2015-05-14 +blog + +// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +bloomberg + +// blue : 2013-11-07 Afilias Limited +blue + +// bms : 2014-10-30 Bristol-Myers Squibb Company +bms + +// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +bmw + +// bnl : 2014-07-24 Banca Nazionale del Lavoro +bnl + +// bnpparibas : 2014-05-29 BNP Paribas +bnpparibas + +// boats : 2014-12-04 DERBoats, LLC +boats + +// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH +boehringer + +// bofa : 2015-07-31 NMS Services, Inc. +bofa + +// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +bom + +// bond : 2014-06-05 Bond University Limited +bond + +// boo : 2014-01-30 Charleston Road Registry Inc. +boo + +// book : 2015-08-27 Amazon EU S.à r.l. +book + +// booking : 2015-07-16 Booking.com B.V. +booking + +// boots : 2015-01-08 THE BOOTS COMPANY PLC +boots + +// bosch : 2015-06-18 Robert Bosch GMBH +bosch + +// bostik : 2015-05-28 Bostik SA +bostik + +// boston : 2015-12-10 +boston + +// bot : 2014-12-18 Amazon EU S.à r.l. +bot + +// boutique : 2013-11-14 Over Galley, LLC +boutique + +// box : 2015-11-12 NS1 Limited +box + +// bradesco : 2014-12-18 Banco Bradesco S.A. +bradesco + +// bridgestone : 2014-12-18 Bridgestone Corporation +bridgestone + +// broadway : 2014-12-22 Celebrate Broadway, Inc. +broadway + +// broker : 2014-12-11 IG Group Holdings PLC +broker + +// brother : 2015-01-29 Brother Industries, Ltd. +brother + +// brussels : 2014-02-06 DNS.be vzw +brussels + +// budapest : 2013-11-21 Top Level Domain Holdings Limited +budapest + +// bugatti : 2015-07-23 Bugatti International SA +bugatti + +// build : 2013-11-07 Plan Bee LLC +build + +// builders : 2013-11-07 Atomic Madison, LLC +builders + +// business : 2013-11-07 Spring Cross, LLC +business + +// buy : 2014-12-18 Amazon EU S.à r.l. +buy + +// buzz : 2013-10-02 DOTSTRATEGY CO. +buzz + +// bzh : 2014-02-27 Association www.bzh +bzh + +// cab : 2013-10-24 Half Sunset, LLC +cab + +// cafe : 2015-02-11 Pioneer Canyon, LLC +cafe + +// cal : 2014-07-24 Charleston Road Registry Inc. +cal + +// call : 2014-12-18 Amazon EU S.à r.l. +call + +// calvinklein : 2015-07-30 PVH gTLD Holdings LLC +calvinklein + +// cam : 2016-04-21 AC Webconnecting Holding B.V. +cam + +// camera : 2013-08-27 Atomic Maple, LLC +camera + +// camp : 2013-11-07 Delta Dynamite, LLC +camp + +// cancerresearch : 2014-05-15 Australian Cancer Research Foundation +cancerresearch + +// canon : 2014-09-12 Canon Inc. +canon + +// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +capetown + +// capital : 2014-03-06 Delta Mill, LLC +capital + +// capitalone : 2015-08-06 Capital One Financial Corporation +capitalone + +// car : 2015-01-22 +car + +// caravan : 2013-12-12 Caravan International, Inc. +caravan + +// cards : 2013-12-05 Foggy Hollow, LLC +cards + +// care : 2014-03-06 Goose Cross +care + +// career : 2013-10-09 dotCareer LLC +career + +// careers : 2013-10-02 Wild Corner, LLC +careers + +// cars : 2014-11-13 +cars + +// cartier : 2014-06-23 Richemont DNS Inc. +cartier + +// casa : 2013-11-21 Top Level Domain Holdings Limited +casa + +// case : 2015-09-03 CNH Industrial N.V. +case + +// caseih : 2015-09-03 CNH Industrial N.V. +caseih + +// cash : 2014-03-06 Delta Lake, LLC +cash + +// casino : 2014-12-18 Binky Sky, LLC +casino + +// catering : 2013-12-05 New Falls. LLC +catering + +// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +catholic + +// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +cba + +// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +cbn + +// cbre : 2015-07-02 CBRE, Inc. +cbre + +// cbs : 2015-08-06 CBS Domains Inc. +cbs + +// ceb : 2015-04-09 The Corporate Executive Board Company +ceb + +// center : 2013-11-07 Tin Mill, LLC +center + +// ceo : 2013-11-07 CEOTLD Pty Ltd +ceo + +// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +cern + +// cfa : 2014-08-28 CFA Institute +cfa + +// cfd : 2014-12-11 IG Group Holdings PLC +cfd + +// chanel : 2015-04-09 Chanel International B.V. +chanel + +// channel : 2014-05-08 Charleston Road Registry Inc. +channel + +// chase : 2015-04-30 JPMorgan Chase & Co. +chase + +// chat : 2014-12-04 Sand Fields, LLC +chat + +// cheap : 2013-11-14 Sand Cover, LLC +cheap + +// chintai : 2015-06-11 CHINTAI Corporation +chintai + +// christmas : 2013-11-21 Uniregistry, Corp. +christmas + +// chrome : 2014-07-24 Charleston Road Registry Inc. +chrome + +// chrysler : 2015-07-30 FCA US LLC. +chrysler + +// church : 2014-02-06 Holly Fields, LLC +church + +// cipriani : 2015-02-19 Hotel Cipriani Srl +cipriani + +// circle : 2014-12-18 Amazon EU S.à r.l. +circle + +// cisco : 2014-12-22 Cisco Technology, Inc. +cisco + +// citadel : 2015-07-23 Citadel Domain LLC +citadel + +// citi : 2015-07-30 Citigroup Inc. +citi + +// citic : 2014-01-09 CITIC Group Corporation +citic + +// city : 2014-05-29 Snow Sky, LLC +city + +// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. +cityeats + +// claims : 2014-03-20 Black Corner, LLC +claims + +// cleaning : 2013-12-05 Fox Shadow, LLC +cleaning + +// click : 2014-06-05 Uniregistry, Corp. +click + +// clinic : 2014-03-20 Goose Park, LLC +clinic + +// clinique : 2015-10-01 The Estée Lauder Companies Inc. +clinique + +// clothing : 2013-08-27 Steel Lake, LLC +clothing + +// cloud : 2015-04-16 ARUBA S.p.A. +cloud + +// club : 2013-11-08 .CLUB DOMAINS, LLC +club + +// clubmed : 2015-06-25 Club Méditerranée S.A. +clubmed + +// coach : 2014-10-09 Koko Island, LLC +coach + +// codes : 2013-10-31 Puff Willow, LLC +codes + +// coffee : 2013-10-17 Trixy Cover, LLC +coffee + +// college : 2014-01-16 XYZ.COM LLC +college + +// cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH +cologne + +// comcast : 2015-07-23 Comcast IP Holdings I, LLC +comcast + +// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +commbank + +// community : 2013-12-05 Fox Orchard, LLC +community + +// company : 2013-11-07 Silver Avenue, LLC +company + +// compare : 2015-10-08 iSelect Ltd +compare + +// computer : 2013-10-24 Pine Mill, LLC +computer + +// comsec : 2015-01-08 VeriSign, Inc. +comsec + +// condos : 2013-12-05 Pine House, LLC +condos + +// construction : 2013-09-16 Fox Dynamite, LLC +construction + +// consulting : 2013-12-05 +consulting + +// contact : 2015-01-08 Top Level Spectrum, Inc. +contact + +// contractors : 2013-09-10 Magic Woods, LLC +contractors + +// cooking : 2013-11-21 Top Level Domain Holdings Limited +cooking + +// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +cookingchannel + +// cool : 2013-11-14 Koko Lake, LLC +cool + +// corsica : 2014-09-25 Collectivité Territoriale de Corse +corsica + +// country : 2013-12-19 Top Level Domain Holdings Limited +country + +// coupon : 2015-02-26 Amazon EU S.à r.l. +coupon + +// coupons : 2015-03-26 Black Island, LLC +coupons + +// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD +courses + +// credit : 2014-03-20 Snow Shadow, LLC +credit + +// creditcard : 2014-03-20 Binky Frostbite, LLC +creditcard + +// creditunion : 2015-01-22 CUNA Performance Resources, LLC +creditunion + +// cricket : 2014-10-09 dot Cricket Limited +cricket + +// crown : 2014-10-24 Crown Equipment Corporation +crown + +// crs : 2014-04-03 Federated Co-operatives Limited +crs + +// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd. +cruise + +// cruises : 2013-12-05 Spring Way, LLC +cruises + +// csc : 2014-09-25 Alliance-One Services, Inc. +csc + +// cuisinella : 2014-04-03 SALM S.A.S. +cuisinella + +// cymru : 2014-05-08 Nominet UK +cymru + +// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd. +cyou + +// dabur : 2014-02-06 Dabur India Limited +dabur + +// dad : 2014-01-23 Charleston Road Registry Inc. +dad + +// dance : 2013-10-24 United TLD Holdco Ltd. +dance + +// data : 2016-06-02 Dish DBS Corporation +data + +// date : 2014-11-20 dot Date Limited +date + +// dating : 2013-12-05 Pine Fest, LLC +dating + +// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +datsun + +// day : 2014-01-30 Charleston Road Registry Inc. +day + +// dclk : 2014-11-20 Charleston Road Registry Inc. +dclk + +// dds : 2015-05-07 Top Level Domain Holdings Limited +dds + +// deal : 2015-06-25 Amazon EU S.à r.l. +deal + +// dealer : 2014-12-22 Dealer Dot Com, Inc. +dealer + +// deals : 2014-05-22 Sand Sunset, LLC +deals + +// degree : 2014-03-06 +degree + +// delivery : 2014-09-11 Steel Station, LLC +delivery + +// dell : 2014-10-24 Dell Inc. +dell + +// deloitte : 2015-07-31 Deloitte Touche Tohmatsu +deloitte + +// delta : 2015-02-19 Delta Air Lines, Inc. +delta + +// democrat : 2013-10-24 United TLD Holdco Ltd. +democrat + +// dental : 2014-03-20 Tin Birch, LLC +dental + +// dentist : 2014-03-20 +dentist + +// desi : 2013-11-14 Desi Networks LLC +desi + +// design : 2014-11-07 Top Level Design, LLC +design + +// dev : 2014-10-16 Charleston Road Registry Inc. +dev + +// dhl : 2015-07-23 Deutsche Post AG +dhl + +// diamonds : 2013-09-22 John Edge, LLC +diamonds + +// diet : 2014-06-26 Uniregistry, Corp. +diet + +// digital : 2014-03-06 Dash Park, LLC +digital + +// direct : 2014-04-10 Half Trail, LLC +direct + +// directory : 2013-09-20 Extra Madison, LLC +directory + +// discount : 2014-03-06 Holly Hill, LLC +discount + +// discover : 2015-07-23 Discover Financial Services +discover + +// dish : 2015-07-30 Dish DBS Corporation +dish + +// diy : 2015-11-05 Lifestyle Domain Holdings, Inc. +diy + +// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +dnp + +// docs : 2014-10-16 Charleston Road Registry Inc. +docs + +// doctor : 2016-06-02 Brice Trail, LLC +doctor + +// dodge : 2015-07-30 FCA US LLC. +dodge + +// dog : 2014-12-04 Koko Mill, LLC +dog + +// doha : 2014-09-18 Communications Regulatory Authority (CRA) +doha + +// domains : 2013-10-17 Sugar Cross, LLC +domains + +// dot : 2015-05-21 Dish DBS Corporation +dot + +// download : 2014-11-20 dot Support Limited +download + +// drive : 2015-03-05 Charleston Road Registry Inc. +drive + +// dtv : 2015-06-04 Dish DBS Corporation +dtv + +// dubai : 2015-01-01 Dubai Smart Government Department +dubai + +// duck : 2015-07-23 Johnson Shareholdings, Inc. +duck + +// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company +dunlop + +// duns : 2015-08-06 The Dun & Bradstreet Corporation +duns + +// dupont : 2015-06-25 E. I. du Pont de Nemours and Company +dupont + +// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +durban + +// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +dvag + +// dvr : 2016-05-26 Hughes Satellite Systems Corporation +dvr + +// earth : 2014-12-04 Interlink Co., Ltd. +earth + +// eat : 2014-01-23 Charleston Road Registry Inc. +eat + +// eco : 2016-07-08 Big Room Inc. +eco + +// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +edeka + +// education : 2013-11-07 Brice Way, LLC +education + +// email : 2013-10-31 Spring Madison, LLC +email + +// emerck : 2014-04-03 Merck KGaA +emerck + +// energy : 2014-09-11 Binky Birch, LLC +energy + +// engineer : 2014-03-06 United TLD Holdco Ltd. +engineer + +// engineering : 2014-03-06 Romeo Canyon +engineering + +// enterprises : 2013-09-20 Snow Oaks, LLC +enterprises + +// epost : 2015-07-23 Deutsche Post AG +epost + +// epson : 2014-12-04 Seiko Epson Corporation +epson + +// equipment : 2013-08-27 Corn Station, LLC +equipment + +// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson +ericsson + +// erni : 2014-04-03 ERNI Group Holding AG +erni + +// esq : 2014-05-08 Charleston Road Registry Inc. +esq + +// estate : 2013-08-27 Trixy Park, LLC +estate + +// esurance : 2015-07-23 Esurance Insurance Company +esurance + +// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +etisalat + +// eurovision : 2014-04-24 European Broadcasting Union (EBU) +eurovision + +// eus : 2013-12-12 Puntueus Fundazioa +eus + +// events : 2013-12-05 Pioneer Maple, LLC +events + +// everbank : 2014-05-15 EverBank +everbank + +// exchange : 2014-03-06 Spring Falls, LLC +exchange + +// expert : 2013-11-21 Magic Pass, LLC +expert + +// exposed : 2013-12-05 Victor Beach, LLC +exposed + +// express : 2015-02-11 Sea Sunset, LLC +express + +// extraspace : 2015-05-14 Extra Space Storage LLC +extraspace + +// fage : 2014-12-18 Fage International S.A. +fage + +// fail : 2014-03-06 Atomic Pipe, LLC +fail + +// fairwinds : 2014-11-13 FairWinds Partners, LLC +fairwinds + +// faith : 2014-11-20 dot Faith Limited +faith + +// family : 2015-04-02 +family + +// fan : 2014-03-06 +fan + +// fans : 2014-11-07 Asiamix Digital Limited +fans + +// farm : 2013-11-07 Just Maple, LLC +farm + +// farmers : 2015-07-09 Farmers Insurance Exchange +farmers + +// fashion : 2014-07-03 Top Level Domain Holdings Limited +fashion + +// fast : 2014-12-18 Amazon EU S.à r.l. +fast + +// fedex : 2015-08-06 Federal Express Corporation +fedex + +// feedback : 2013-12-19 Top Level Spectrum, Inc. +feedback + +// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V. +ferrari + +// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +ferrero + +// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V. +fiat + +// fidelity : 2015-07-30 Fidelity Brokerage Services LLC +fidelity + +// fido : 2015-08-06 Rogers Communications Partnership +fido + +// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +film + +// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +final + +// finance : 2014-03-20 Cotton Cypress, LLC +finance + +// financial : 2014-03-06 Just Cover, LLC +financial + +// fire : 2015-06-25 Amazon EU S.à r.l. +fire + +// firestone : 2014-12-18 Bridgestone Corporation +firestone + +// firmdale : 2014-03-27 Firmdale Holdings Limited +firmdale + +// fish : 2013-12-12 Fox Woods, LLC +fish + +// fishing : 2013-11-21 Top Level Domain Holdings Limited +fishing + +// fit : 2014-11-07 Top Level Domain Holdings Limited +fit + +// fitness : 2014-03-06 Brice Orchard, LLC +fitness + +// flickr : 2015-04-02 Yahoo! Domain Services Inc. +flickr + +// flights : 2013-12-05 Fox Station, LLC +flights + +// flir : 2015-07-23 FLIR Systems, Inc. +flir + +// florist : 2013-11-07 Half Cypress, LLC +florist + +// flowers : 2014-10-09 Uniregistry, Corp. +flowers + +// fly : 2014-05-08 Charleston Road Registry Inc. +fly + +// foo : 2014-01-23 Charleston Road Registry Inc. +foo + +// food : 2016-04-21 Lifestyle Domain Holdings, Inc. +food + +// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. +foodnetwork + +// football : 2014-12-18 Foggy Farms, LLC +football + +// ford : 2014-11-13 Ford Motor Company +ford + +// forex : 2014-12-11 IG Group Holdings PLC +forex + +// forsale : 2014-05-22 +forsale + +// forum : 2015-04-02 Fegistry, LLC +forum + +// foundation : 2013-12-05 John Dale, LLC +foundation + +// fox : 2015-09-11 FOX Registry, LLC +fox + +// free : 2015-12-10 Amazon EU S.à r.l. +free + +// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH +fresenius + +// frl : 2014-05-15 FRLregistry B.V. +frl + +// frogans : 2013-12-19 OP3FT +frogans + +// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. +frontdoor + +// frontier : 2015-02-05 Frontier Communications Corporation +frontier + +// ftr : 2015-07-16 Frontier Communications Corporation +ftr + +// fujitsu : 2015-07-30 Fujitsu Limited +fujitsu + +// fujixerox : 2015-07-23 Xerox DNHC LLC +fujixerox + +// fun : 2016-01-14 +fun + +// fund : 2014-03-20 John Castle, LLC +fund + +// furniture : 2014-03-20 Lone Fields, LLC +furniture + +// futbol : 2013-09-20 +futbol + +// fyi : 2015-04-02 Silver Tigers, LLC +fyi + +// gal : 2013-11-07 Asociación puntoGAL +gal + +// gallery : 2013-09-13 Sugar House, LLC +gallery + +// gallo : 2015-06-11 Gallo Vineyards, Inc. +gallo + +// gallup : 2015-02-19 Gallup, Inc. +gallup + +// game : 2015-05-28 Uniregistry, Corp. +game + +// games : 2015-05-28 +games + +// gap : 2015-07-31 The Gap, Inc. +gap + +// garden : 2014-06-26 Top Level Domain Holdings Limited +garden + +// gbiz : 2014-07-17 Charleston Road Registry Inc. +gbiz + +// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +gdn + +// gea : 2014-12-04 GEA Group Aktiengesellschaft +gea + +// gent : 2014-01-23 COMBELL GROUP NV/SA +gent + +// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +genting + +// george : 2015-07-31 Wal-Mart Stores, Inc. +george + +// ggee : 2014-01-09 GMO Internet, Inc. +ggee + +// gift : 2013-10-17 Uniregistry, Corp. +gift + +// gifts : 2014-07-03 Goose Sky, LLC +gifts + +// gives : 2014-03-06 United TLD Holdco Ltd. +gives + +// giving : 2014-11-13 Giving Limited +giving + +// glade : 2015-07-23 Johnson Shareholdings, Inc. +glade + +// glass : 2013-11-07 Black Cover, LLC +glass + +// gle : 2014-07-24 Charleston Road Registry Inc. +gle + +// global : 2014-04-17 Dot GLOBAL AS +global + +// globo : 2013-12-19 Globo Comunicação e Participações S.A +globo + +// gmail : 2014-05-01 Charleston Road Registry Inc. +gmail + +// gmbh : 2016-01-29 Extra Dynamite, LLC +gmbh + +// gmo : 2014-01-09 GMO Internet, Inc. +gmo + +// gmx : 2014-04-24 1&1 Mail & Media GmbH +gmx + +// godaddy : 2015-07-23 Go Daddy East, LLC +godaddy + +// gold : 2015-01-22 June Edge, LLC +gold + +// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +goldpoint + +// golf : 2014-12-18 Lone falls, LLC +golf + +// goo : 2014-12-18 NTT Resonant Inc. +goo + +// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company +goodhands + +// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company +goodyear + +// goog : 2014-11-20 Charleston Road Registry Inc. +goog + +// google : 2014-07-24 Charleston Road Registry Inc. +google + +// gop : 2014-01-16 Republican State Leadership Committee, Inc. +gop + +// got : 2014-12-18 Amazon EU S.à r.l. +got + +// grainger : 2015-05-07 Grainger Registry Services, LLC +grainger + +// graphics : 2013-09-13 Over Madison, LLC +graphics + +// gratis : 2014-03-20 Pioneer Tigers, LLC +gratis + +// green : 2014-05-08 Afilias Limited +green + +// gripe : 2014-03-06 Corn Sunset, LLC +gripe + +// grocery : 2016-06-16 Wal-Mart Stores, Inc. +grocery + +// group : 2014-08-15 Romeo Town, LLC +group + +// guardian : 2015-07-30 The Guardian Life Insurance Company of America +guardian + +// gucci : 2014-11-13 Guccio Gucci S.p.a. +gucci + +// guge : 2014-08-28 Charleston Road Registry Inc. +guge + +// guide : 2013-09-13 Snow Moon, LLC +guide + +// guitars : 2013-11-14 Uniregistry, Corp. +guitars + +// guru : 2013-08-27 Pioneer Cypress, LLC +guru + +// hair : 2015-12-03 L'Oréal +hair + +// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +hamburg + +// hangout : 2014-11-13 Charleston Road Registry Inc. +hangout + +// haus : 2013-12-05 +haus + +// hbo : 2015-07-30 HBO Registry Services, Inc. +hbo + +// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +hdfc + +// hdfcbank : 2015-02-12 HDFC Bank Limited +hdfcbank + +// health : 2015-02-11 DotHealth, LLC +health + +// healthcare : 2014-06-12 Silver Glen, LLC +healthcare + +// help : 2014-06-26 Uniregistry, Corp. +help + +// helsinki : 2015-02-05 City of Helsinki +helsinki + +// here : 2014-02-06 Charleston Road Registry Inc. +here + +// hermes : 2014-07-10 HERMES INTERNATIONAL +hermes + +// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. +hgtv + +// hiphop : 2014-03-06 Uniregistry, Corp. +hiphop + +// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. +hisamitsu + +// hitachi : 2014-10-31 Hitachi, Ltd. +hitachi + +// hiv : 2014-03-13 +hiv + +// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited +hkt + +// hockey : 2015-03-19 Half Willow, LLC +hockey + +// holdings : 2013-08-27 John Madison, LLC +holdings + +// holiday : 2013-11-07 Goose Woods, LLC +holiday + +// homedepot : 2015-04-02 Homer TLC, Inc. +homedepot + +// homegoods : 2015-07-16 The TJX Companies, Inc. +homegoods + +// homes : 2014-01-09 DERHomes, LLC +homes + +// homesense : 2015-07-16 The TJX Companies, Inc. +homesense + +// honda : 2014-12-18 Honda Motor Co., Ltd. +honda + +// honeywell : 2015-07-23 Honeywell GTLD LLC +honeywell + +// horse : 2013-11-21 Top Level Domain Holdings Limited +horse + +// hospital : 2016-10-20 Ruby Pike, LLC +hospital + +// host : 2014-04-17 DotHost Inc. +host + +// hosting : 2014-05-29 Uniregistry, Corp. +hosting + +// hot : 2015-08-27 Amazon EU S.à r.l. +hot + +// hoteles : 2015-03-05 Travel Reservations SRL +hoteles + +// hotels : 2016-04-07 Booking.com B.V. +hotels + +// hotmail : 2014-12-18 Microsoft Corporation +hotmail + +// house : 2013-11-07 Sugar Park, LLC +house + +// how : 2014-01-23 Charleston Road Registry Inc. +how + +// hsbc : 2014-10-24 HSBC Holdings PLC +hsbc + +// hughes : 2015-07-30 Hughes Satellite Systems Corporation +hughes + +// hyatt : 2015-07-30 Hyatt GTLD, L.L.C. +hyatt + +// hyundai : 2015-07-09 Hyundai Motor Company +hyundai + +// ibm : 2014-07-31 International Business Machines Corporation +ibm + +// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +icbc + +// ice : 2014-10-30 IntercontinentalExchange, Inc. +ice + +// icu : 2015-01-08 One.com A/S +icu + +// ieee : 2015-07-23 IEEE Global LLC +ieee + +// ifm : 2014-01-30 ifm electronic gmbh +ifm + +// ikano : 2015-07-09 Ikano S.A. +ikano + +// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +imamat + +// imdb : 2015-06-25 Amazon EU S.à r.l. +imdb + +// immo : 2014-07-10 Auburn Bloom, LLC +immo + +// immobilien : 2013-11-07 United TLD Holdco Ltd. +immobilien + +// industries : 2013-12-05 Outer House, LLC +industries + +// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +infiniti + +// ing : 2014-01-23 Charleston Road Registry Inc. +ing + +// ink : 2013-12-05 Top Level Design, LLC +ink + +// institute : 2013-11-07 Outer Maple, LLC +institute + +// insurance : 2015-02-19 fTLD Registry Services LLC +insurance + +// insure : 2014-03-20 Pioneer Willow, LLC +insure + +// intel : 2015-08-06 Intel Corporation +intel + +// international : 2013-11-07 Wild Way, LLC +international + +// intuit : 2015-07-30 Intuit Administrative Services, Inc. +intuit + +// investments : 2014-03-20 Holly Glen, LLC +investments + +// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +ipiranga + +// irish : 2014-08-07 Dot-Irish LLC +irish + +// iselect : 2015-02-11 iSelect Ltd +iselect + +// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +ismaili + +// ist : 2014-08-28 Istanbul Metropolitan Municipality +ist + +// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +istanbul + +// itau : 2014-10-02 Itau Unibanco Holding S.A. +itau + +// itv : 2015-07-09 ITV Services Limited +itv + +// iveco : 2015-09-03 CNH Industrial N.V. +iveco + +// iwc : 2014-06-23 Richemont DNS Inc. +iwc + +// jaguar : 2014-11-13 Jaguar Land Rover Ltd +jaguar + +// java : 2014-06-19 Oracle Corporation +java + +// jcb : 2014-11-20 JCB Co., Ltd. +jcb + +// jcp : 2015-04-23 JCP Media, Inc. +jcp + +// jeep : 2015-07-30 FCA US LLC. +jeep + +// jetzt : 2014-01-09 +jetzt + +// jewelry : 2015-03-05 Wild Bloom, LLC +jewelry + +// jio : 2015-04-02 Affinity Names, Inc. +jio + +// jlc : 2014-12-04 Richemont DNS Inc. +jlc + +// jll : 2015-04-02 Jones Lang LaSalle Incorporated +jll + +// jmp : 2015-03-26 Matrix IP LLC +jmp + +// jnj : 2015-06-18 Johnson & Johnson Services, Inc. +jnj + +// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +joburg + +// jot : 2014-12-18 Amazon EU S.à r.l. +jot + +// joy : 2014-12-18 Amazon EU S.à r.l. +joy + +// jpmorgan : 2015-04-30 JPMorgan Chase & Co. +jpmorgan + +// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +jprs + +// juegos : 2014-03-20 Uniregistry, Corp. +juegos + +// juniper : 2015-07-30 JUNIPER NETWORKS, INC. +juniper + +// kaufen : 2013-11-07 United TLD Holdco Ltd. +kaufen + +// kddi : 2014-09-12 KDDI CORPORATION +kddi + +// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +kerryhotels + +// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +kerrylogistics + +// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +kerryproperties + +// kfh : 2014-12-04 Kuwait Finance House +kfh + +// kia : 2015-07-09 KIA MOTORS CORPORATION +kia + +// kim : 2013-09-23 Afilias Limited +kim + +// kinder : 2014-11-07 Ferrero Trading Lux S.A. +kinder + +// kindle : 2015-06-25 Amazon EU S.à r.l. +kindle + +// kitchen : 2013-09-20 Just Goodbye, LLC +kitchen + +// kiwi : 2013-09-20 DOT KIWI LIMITED +kiwi + +// koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH +koeln + +// komatsu : 2015-01-08 Komatsu Ltd. +komatsu + +// kosher : 2015-08-20 Kosher Marketing Assets LLC +kosher + +// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +kpmg + +// kpn : 2015-01-08 Koninklijke KPN N.V. +kpn + +// krd : 2013-12-05 KRG Department of Information Technology +krd + +// kred : 2013-12-19 KredTLD Pty Ltd +kred + +// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +kuokgroup + +// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +kyoto + +// lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA +lacaixa + +// ladbrokes : 2015-08-06 LADBROKES INTERNATIONAL PLC +ladbrokes + +// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. +lamborghini + +// lamer : 2015-10-01 The Estée Lauder Companies Inc. +lamer + +// lancaster : 2015-02-12 LANCASTER +lancaster + +// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V. +lancia + +// lancome : 2015-07-23 L'Oréal +lancome + +// land : 2013-09-10 Pine Moon, LLC +land + +// landrover : 2014-11-13 Jaguar Land Rover Ltd +landrover + +// lanxess : 2015-07-30 LANXESS Corporation +lanxess + +// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +lasalle + +// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico +lat + +// latino : 2015-07-30 Dish DBS Corporation +latino + +// latrobe : 2014-06-16 La Trobe University +latrobe + +// law : 2015-01-22 Minds + Machines Group Limited +law + +// lawyer : 2014-03-20 +lawyer + +// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant") +lds + +// lease : 2014-03-06 Victor Trail, LLC +lease + +// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +leclerc + +// lefrak : 2015-07-16 LeFrak Organization, Inc. +lefrak + +// legal : 2014-10-16 Blue Falls, LLC +legal + +// lego : 2015-07-16 LEGO Juris A/S +lego + +// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +lexus + +// lgbt : 2014-05-08 Afilias Limited +lgbt + +// liaison : 2014-10-02 Liaison Technologies, Incorporated +liaison + +// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +lidl + +// life : 2014-02-06 Trixy Oaks, LLC +life + +// lifeinsurance : 2015-01-15 American Council of Life Insurers +lifeinsurance + +// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +lifestyle + +// lighting : 2013-08-27 John McCook, LLC +lighting + +// like : 2014-12-18 Amazon EU S.à r.l. +like + +// lilly : 2015-07-31 Eli Lilly and Company +lilly + +// limited : 2014-03-06 Big Fest, LLC +limited + +// limo : 2013-10-17 Hidden Frostbite, LLC +limo + +// lincoln : 2014-11-13 Ford Motor Company +lincoln + +// linde : 2014-12-04 Linde Aktiengesellschaft +linde + +// link : 2013-11-14 Uniregistry, Corp. +link + +// lipsy : 2015-06-25 Lipsy Ltd +lipsy + +// live : 2014-12-04 +live + +// living : 2015-07-30 Lifestyle Domain Holdings, Inc. +living + +// lixil : 2015-03-19 LIXIL Group Corporation +lixil + +// loan : 2014-11-20 dot Loan Limited +loan + +// loans : 2014-03-20 June Woods, LLC +loans + +// locker : 2015-06-04 Dish DBS Corporation +locker + +// locus : 2015-06-25 Locus Analytics LLC +locus + +// loft : 2015-07-30 Annco, Inc. +loft + +// lol : 2015-01-30 Uniregistry, Corp. +lol + +// london : 2013-11-14 Dot London Domains Limited +london + +// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +lotte + +// lotto : 2014-04-10 Afilias Limited +lotto + +// love : 2014-12-22 Merchant Law Group LLP +love + +// lpl : 2015-07-30 LPL Holdings, Inc. +lpl + +// lplfinancial : 2015-07-30 LPL Holdings, Inc. +lplfinancial + +// ltd : 2014-09-25 Over Corner, LLC +ltd + +// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA +ltda + +// lundbeck : 2015-08-06 H. Lundbeck A/S +lundbeck + +// lupin : 2014-11-07 LUPIN LIMITED +lupin + +// luxe : 2014-01-09 Top Level Domain Holdings Limited +luxe + +// luxury : 2013-10-17 Luxury Partners, LLC +luxury + +// macys : 2015-07-31 Macys, Inc. +macys + +// madrid : 2014-05-01 Comunidad de Madrid +madrid + +// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +maif + +// maison : 2013-12-05 Victor Frostbite, LLC +maison + +// makeup : 2015-01-15 L'Oréal +makeup + +// man : 2014-12-04 MAN SE +man + +// management : 2013-11-07 John Goodbye, LLC +management + +// mango : 2013-10-24 PUNTO FA S.L. +mango + +// map : 2016-06-09 Charleston Road Registry Inc. +map + +// market : 2014-03-06 +market + +// marketing : 2013-11-07 Fern Pass, LLC +marketing + +// markets : 2014-12-11 IG Group Holdings PLC +markets + +// marriott : 2014-10-09 Marriott Worldwide Corporation +marriott + +// marshalls : 2015-07-16 The TJX Companies, Inc. +marshalls + +// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V. +maserati + +// mattel : 2015-08-06 Mattel Sites, Inc. +mattel + +// mba : 2015-04-02 Lone Hollow, LLC +mba + +// mckinsey : 2015-07-31 McKinsey Holdings, Inc. +mckinsey + +// med : 2015-08-06 Medistry LLC +med + +// media : 2014-03-06 Grand Glen, LLC +media + +// meet : 2014-01-16 +meet + +// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +melbourne + +// meme : 2014-01-30 Charleston Road Registry Inc. +meme + +// memorial : 2014-10-16 Dog Beach, LLC +memorial + +// men : 2015-02-26 Exclusive Registry Limited +men + +// menu : 2013-09-11 Wedding TLD2, LLC +menu + +// meo : 2014-11-07 PT Comunicacoes S.A. +meo + +// merckmsd : 2016-07-14 MSD Registry Holdings, Inc. +merckmsd + +// metlife : 2015-05-07 MetLife Services and Solutions, LLC +metlife + +// miami : 2013-12-19 Top Level Domain Holdings Limited +miami + +// microsoft : 2014-12-18 Microsoft Corporation +microsoft + +// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +mini + +// mint : 2015-07-30 Intuit Administrative Services, Inc. +mint + +// mit : 2015-07-02 Massachusetts Institute of Technology +mit + +// mitsubishi : 2015-07-23 Mitsubishi Corporation +mitsubishi + +// mlb : 2015-05-21 MLB Advanced Media DH, LLC +mlb + +// mls : 2015-04-23 The Canadian Real Estate Association +mls + +// mma : 2014-11-07 MMA IARD +mma + +// mobile : 2016-06-02 Dish DBS Corporation +mobile + +// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L. +mobily + +// moda : 2013-11-07 United TLD Holdco Ltd. +moda + +// moe : 2013-11-13 Interlink Co., Ltd. +moe + +// moi : 2014-12-18 Amazon EU S.à r.l. +moi + +// mom : 2015-04-16 Uniregistry, Corp. +mom + +// monash : 2013-09-30 Monash University +monash + +// money : 2014-10-16 Outer McCook, LLC +money + +// monster : 2015-09-11 Monster Worldwide, Inc. +monster + +// mopar : 2015-07-30 FCA US LLC. +mopar + +// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant") +mormon + +// mortgage : 2014-03-20 +mortgage + +// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +moscow + +// moto : 2015-06-04 +moto + +// motorcycles : 2014-01-09 DERMotorcycles, LLC +motorcycles + +// mov : 2014-01-30 Charleston Road Registry Inc. +mov + +// movie : 2015-02-05 New Frostbite, LLC +movie + +// movistar : 2014-10-16 Telefónica S.A. +movistar + +// msd : 2015-07-23 MSD Registry Holdings, Inc. +msd + +// mtn : 2014-12-04 MTN Dubai Limited +mtn + +// mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation +mtpc + +// mtr : 2015-03-12 MTR Corporation Limited +mtr + +// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC +mutual + +// nab : 2015-08-20 National Australia Bank Limited +nab + +// nadex : 2014-12-11 IG Group Holdings PLC +nadex + +// nagoya : 2013-10-24 GMO Registry, Inc. +nagoya + +// nationwide : 2015-07-23 Nationwide Mutual Insurance Company +nationwide + +// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +natura + +// navy : 2014-03-06 United TLD Holdco Ltd. +navy + +// nba : 2015-07-31 NBA REGISTRY, LLC +nba + +// nec : 2015-01-08 NEC Corporation +nec + +// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +netbank + +// netflix : 2015-06-18 Netflix, Inc. +netflix + +// network : 2013-11-14 Trixy Manor, LLC +network + +// neustar : 2013-12-05 NeuStar, Inc. +neustar + +// new : 2014-01-30 Charleston Road Registry Inc. +new + +// newholland : 2015-09-03 CNH Industrial N.V. +newholland + +// news : 2014-12-18 +news + +// next : 2015-06-18 Next plc +next + +// nextdirect : 2015-06-18 Next plc +nextdirect + +// nexus : 2014-07-24 Charleston Road Registry Inc. +nexus + +// nfl : 2015-07-23 NFL Reg Ops LLC +nfl + +// ngo : 2014-03-06 Public Interest Registry +ngo + +// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +nhk + +// nico : 2014-12-04 DWANGO Co., Ltd. +nico + +// nike : 2015-07-23 NIKE, Inc. +nike + +// nikon : 2015-05-21 NIKON CORPORATION +nikon + +// ninja : 2013-11-07 United TLD Holdco Ltd. +ninja + +// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +nissan + +// nissay : 2015-10-29 Nippon Life Insurance Company +nissay + +// nokia : 2015-01-08 Nokia Corporation +nokia + +// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC +northwesternmutual + +// norton : 2014-12-04 Symantec Corporation +norton + +// now : 2015-06-25 Amazon EU S.à r.l. +now + +// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +nowruz + +// nowtv : 2015-05-14 Starbucks (HK) Limited +nowtv + +// nra : 2014-05-22 NRA Holdings Company, INC. +nra + +// nrw : 2013-11-21 Minds + Machines GmbH +nrw + +// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +ntt + +// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +nyc + +// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +obi + +// observer : 2015-04-30 +observer + +// off : 2015-07-23 Johnson Shareholdings, Inc. +off + +// office : 2015-03-12 Microsoft Corporation +office + +// okinawa : 2013-12-05 BusinessRalliart Inc. +okinawa + +// olayan : 2015-05-14 Crescent Holding GmbH +olayan + +// olayangroup : 2015-05-14 Crescent Holding GmbH +olayangroup + +// oldnavy : 2015-07-31 The Gap, Inc. +oldnavy + +// ollo : 2015-06-04 Dish DBS Corporation +ollo + +// omega : 2015-01-08 The Swatch Group Ltd +omega + +// one : 2014-11-07 One.com A/S +one + +// ong : 2014-03-06 Public Interest Registry +ong + +// onl : 2013-09-16 I-Registry Ltd. +onl + +// online : 2015-01-15 DotOnline Inc. +online + +// onyourside : 2015-07-23 Nationwide Mutual Insurance Company +onyourside + +// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED +ooo + +// open : 2015-07-31 American Express Travel Related Services Company, Inc. +open + +// oracle : 2014-06-19 Oracle Corporation +oracle + +// orange : 2015-03-12 Orange Brand Services Limited +orange + +// organic : 2014-03-27 Afilias Limited +organic + +// origins : 2015-10-01 The Estée Lauder Companies Inc. +origins + +// osaka : 2014-09-04 Interlink Co., Ltd. +osaka + +// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +otsuka + +// ott : 2015-06-04 Dish DBS Corporation +ott + +// ovh : 2014-01-16 OVH SAS +ovh + +// page : 2014-12-04 Charleston Road Registry Inc. +page + +// panasonic : 2015-07-30 Panasonic Corporation +panasonic + +// panerai : 2014-11-07 Richemont DNS Inc. +panerai + +// paris : 2014-01-30 City of Paris +paris + +// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +pars + +// partners : 2013-12-05 Magic Glen, LLC +partners + +// parts : 2013-12-05 Sea Goodbye, LLC +parts + +// party : 2014-09-11 Blue Sky Registry Limited +party + +// passagens : 2015-03-05 Travel Reservations SRL +passagens + +// pay : 2015-08-27 Amazon EU S.à r.l. +pay + +// pccw : 2015-05-14 PCCW Enterprises Limited +pccw + +// pet : 2015-05-07 Afilias plc +pet + +// pfizer : 2015-09-11 Pfizer Inc. +pfizer + +// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +pharmacy + +// phd : 2016-07-28 Charleston Road Registry Inc. +phd + +// philips : 2014-11-07 Koninklijke Philips N.V. +philips + +// phone : 2016-06-02 Dish DBS Corporation +phone + +// photo : 2013-11-14 Uniregistry, Corp. +photo + +// photography : 2013-09-20 Sugar Glen, LLC +photography + +// photos : 2013-10-17 Sea Corner, LLC +photos + +// physio : 2014-05-01 PhysBiz Pty Ltd +physio + +// piaget : 2014-10-16 Richemont DNS Inc. +piaget + +// pics : 2013-11-14 Uniregistry, Corp. +pics + +// pictet : 2014-06-26 Pictet Europe S.A. +pictet + +// pictures : 2014-03-06 Foggy Sky, LLC +pictures + +// pid : 2015-01-08 Top Level Spectrum, Inc. +pid + +// pin : 2014-12-18 Amazon EU S.à r.l. +pin + +// ping : 2015-06-11 Ping Registry Provider, Inc. +ping + +// pink : 2013-10-01 Afilias Limited +pink + +// pioneer : 2015-07-16 Pioneer Corporation +pioneer + +// pizza : 2014-06-26 Foggy Moon, LLC +pizza + +// place : 2014-04-24 Snow Galley, LLC +place + +// play : 2015-03-05 Charleston Road Registry Inc. +play + +// playstation : 2015-07-02 Sony Computer Entertainment Inc. +playstation + +// plumbing : 2013-09-10 Spring Tigers, LLC +plumbing + +// plus : 2015-02-05 Sugar Mill, LLC +plus + +// pnc : 2015-07-02 PNC Domain Co., LLC +pnc + +// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +pohl + +// poker : 2014-07-03 Afilias Domains No. 5 Limited +poker + +// politie : 2015-08-20 Politie Nederland +politie + +// porn : 2014-10-16 ICM Registry PN LLC +porn + +// pramerica : 2015-07-30 Prudential Financial, Inc. +pramerica + +// praxi : 2013-12-05 Praxi S.p.A. +praxi + +// press : 2014-04-03 DotPress Inc. +press + +// prime : 2015-06-25 Amazon EU S.à r.l. +prime + +// prod : 2014-01-23 Charleston Road Registry Inc. +prod + +// productions : 2013-12-05 Magic Birch, LLC +productions + +// prof : 2014-07-24 Charleston Road Registry Inc. +prof + +// progressive : 2015-07-23 Progressive Casualty Insurance Company +progressive + +// promo : 2014-12-18 +promo + +// properties : 2013-12-05 Big Pass, LLC +properties + +// property : 2014-05-22 Uniregistry, Corp. +property + +// protection : 2015-04-23 +protection + +// pru : 2015-07-30 Prudential Financial, Inc. +pru + +// prudential : 2015-07-30 Prudential Financial, Inc. +prudential + +// pub : 2013-12-12 United TLD Holdco Ltd. +pub + +// pwc : 2015-10-29 PricewaterhouseCoopers LLP +pwc + +// qpon : 2013-11-14 dotCOOL, Inc. +qpon + +// quebec : 2013-12-19 PointQuébec Inc +quebec + +// quest : 2015-03-26 Quest ION Limited +quest + +// qvc : 2015-07-30 QVC, Inc. +qvc + +// racing : 2014-12-04 Premier Registry Limited +racing + +// radio : 2016-07-21 European Broadcasting Union (EBU) +radio + +// raid : 2015-07-23 Johnson Shareholdings, Inc. +raid + +// read : 2014-12-18 Amazon EU S.à r.l. +read + +// realestate : 2015-09-11 dotRealEstate LLC +realestate + +// realtor : 2014-05-29 Real Estate Domains LLC +realtor + +// realty : 2015-03-19 Fegistry, LLC +realty + +// recipes : 2013-10-17 Grand Island, LLC +recipes + +// red : 2013-11-07 Afilias Limited +red + +// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +redstone + +// redumbrella : 2015-03-26 Travelers TLD, LLC +redumbrella + +// rehab : 2014-03-06 United TLD Holdco Ltd. +rehab + +// reise : 2014-03-13 +reise + +// reisen : 2014-03-06 New Cypress, LLC +reisen + +// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +reit + +// reliance : 2015-04-02 Reliance Industries Limited +reliance + +// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd. +ren + +// rent : 2014-12-04 DERRent, LLC +rent + +// rentals : 2013-12-05 Big Hollow,LLC +rentals + +// repair : 2013-11-07 Lone Sunset, LLC +repair + +// report : 2013-12-05 Binky Glen, LLC +report + +// republican : 2014-03-20 United TLD Holdco Ltd. +republican + +// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +rest + +// restaurant : 2014-07-03 Snow Avenue, LLC +restaurant + +// review : 2014-11-20 dot Review Limited +review + +// reviews : 2013-09-13 +reviews + +// rexroth : 2015-06-18 Robert Bosch GMBH +rexroth + +// rich : 2013-11-21 I-Registry Ltd. +rich + +// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited +richardli + +// ricoh : 2014-11-20 Ricoh Company, Ltd. +ricoh + +// rightathome : 2015-07-23 Johnson Shareholdings, Inc. +rightathome + +// ril : 2015-04-02 Reliance Industries Limited +ril + +// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +rio + +// rip : 2014-07-10 United TLD Holdco Ltd. +rip + +// rmit : 2015-11-19 Royal Melbourne Institute of Technology +rmit + +// rocher : 2014-12-18 Ferrero Trading Lux S.A. +rocher + +// rocks : 2013-11-14 +rocks + +// rodeo : 2013-12-19 Top Level Domain Holdings Limited +rodeo + +// rogers : 2015-08-06 Rogers Communications Partnership +rogers + +// room : 2014-12-18 Amazon EU S.à r.l. +room + +// rsvp : 2014-05-08 Charleston Road Registry Inc. +rsvp + +// rugby : 2016-12-15 World Rugby Strategic Developments Limited +rugby + +// ruhr : 2013-10-02 regiodot GmbH & Co. KG +ruhr + +// run : 2015-03-19 Snow Park, LLC +run + +// rwe : 2015-04-02 RWE AG +rwe + +// ryukyu : 2014-01-09 BusinessRalliart Inc. +ryukyu + +// saarland : 2013-12-12 dotSaarland GmbH +saarland + +// safe : 2014-12-18 Amazon EU S.à r.l. +safe + +// safety : 2015-01-08 Safety Registry Services, LLC. +safety + +// sakura : 2014-12-18 SAKURA Internet Inc. +sakura + +// sale : 2014-10-16 +sale + +// salon : 2014-12-11 Outer Orchard, LLC +salon + +// samsclub : 2015-07-31 Wal-Mart Stores, Inc. +samsclub + +// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +samsung + +// sandvik : 2014-11-13 Sandvik AB +sandvik + +// sandvikcoromant : 2014-11-07 Sandvik AB +sandvikcoromant + +// sanofi : 2014-10-09 Sanofi +sanofi + +// sap : 2014-03-27 SAP AG +sap + +// sapo : 2014-11-07 PT Comunicacoes S.A. +sapo + +// sarl : 2014-07-03 Delta Orchard, LLC +sarl + +// sas : 2015-04-02 Research IP LLC +sas + +// save : 2015-06-25 Amazon EU S.à r.l. +save + +// saxo : 2014-10-31 Saxo Bank A/S +saxo + +// sbi : 2015-03-12 STATE BANK OF INDIA +sbi + +// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION +sbs + +// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +sca + +// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +scb + +// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG +schaeffler + +// schmidt : 2014-04-03 SALM S.A.S. +schmidt + +// scholarships : 2014-04-24 Scholarships.com, LLC +scholarships + +// school : 2014-12-18 Little Galley, LLC +school + +// schule : 2014-03-06 Outer Moon, LLC +schule + +// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +schwarz + +// science : 2014-09-11 dot Science Limited +science + +// scjohnson : 2015-07-23 Johnson Shareholdings, Inc. +scjohnson + +// scor : 2014-10-31 SCOR SE +scor + +// scot : 2014-01-23 Dot Scot Registry Limited +scot + +// search : 2016-06-09 Charleston Road Registry Inc. +search + +// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +seat + +// secure : 2015-08-27 Amazon EU S.à r.l. +secure + +// security : 2015-05-14 +security + +// seek : 2014-12-04 Seek Limited +seek + +// select : 2015-10-08 iSelect Ltd +select + +// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +sener + +// services : 2014-02-27 Fox Castle, LLC +services + +// ses : 2015-07-23 SES +ses + +// seven : 2015-08-06 Seven West Media Ltd +seven + +// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +sew + +// sex : 2014-11-13 ICM Registry SX LLC +sex + +// sexy : 2013-09-11 Uniregistry, Corp. +sexy + +// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR +sfr + +// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited +shangrila + +// sharp : 2014-05-01 Sharp Corporation +sharp + +// shaw : 2015-04-23 Shaw Cablesystems G.P. +shaw + +// shell : 2015-07-30 Shell Information Technology International Inc +shell + +// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +shia + +// shiksha : 2013-11-14 Afilias Limited +shiksha + +// shoes : 2013-10-02 Binky Galley, LLC +shoes + +// shop : 2016-04-08 GMO Registry, Inc. +shop + +// shopping : 2016-03-31 +shopping + +// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +shouji + +// show : 2015-03-05 Snow Beach, LLC +show + +// showtime : 2015-08-06 CBS Domains Inc. +showtime + +// shriram : 2014-01-23 Shriram Capital Ltd. +shriram + +// silk : 2015-06-25 Amazon EU S.à r.l. +silk + +// sina : 2015-03-12 Sina Corporation +sina + +// singles : 2013-08-27 Fern Madison, LLC +singles + +// site : 2015-01-15 DotSite Inc. +site + +// ski : 2015-04-09 STARTING DOT LIMITED +ski + +// skin : 2015-01-15 L'Oréal +skin + +// sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch +sky + +// skype : 2014-12-18 Microsoft Corporation +skype + +// sling : 2015-07-30 Hughes Satellite Systems Corporation +sling + +// smart : 2015-07-09 Smart Communications, Inc. (SMART) +smart + +// smile : 2014-12-18 Amazon EU S.à r.l. +smile + +// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F +sncf + +// soccer : 2015-03-26 Foggy Shadow, LLC +soccer + +// social : 2013-11-07 United TLD Holdco Ltd. +social + +// softbank : 2015-07-02 SoftBank Corp. +softbank + +// software : 2014-03-20 +software + +// sohu : 2013-12-19 Sohu.com Limited +sohu + +// solar : 2013-11-07 Ruby Town, LLC +solar + +// solutions : 2013-11-07 Silver Cover, LLC +solutions + +// song : 2015-02-26 Amazon EU S.à r.l. +song + +// sony : 2015-01-08 Sony Corporation +sony + +// soy : 2014-01-23 Charleston Road Registry Inc. +soy + +// space : 2014-04-03 DotSpace Inc. +space + +// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG +spiegel + +// spot : 2015-02-26 Amazon EU S.à r.l. +spot + +// spreadbetting : 2014-12-11 IG Group Holdings PLC +spreadbetting + +// srl : 2015-05-07 mySRL GmbH +srl + +// srt : 2015-07-30 FCA US LLC. +srt + +// stada : 2014-11-13 STADA Arzneimittel AG +stada + +// staples : 2015-07-30 Staples, Inc. +staples + +// star : 2015-01-08 Star India Private Limited +star + +// starhub : 2015-02-05 StarHub Ltd +starhub + +// statebank : 2015-03-12 STATE BANK OF INDIA +statebank + +// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company +statefarm + +// statoil : 2014-12-04 Statoil ASA +statoil + +// stc : 2014-10-09 Saudi Telecom Company +stc + +// stcgroup : 2014-10-09 Saudi Telecom Company +stcgroup + +// stockholm : 2014-12-18 Stockholms kommun +stockholm + +// storage : 2014-12-22 Self Storage Company LLC +storage + +// store : 2015-04-09 DotStore Inc. +store + +// stream : 2016-01-08 dot Stream Limited +stream + +// studio : 2015-02-11 +studio + +// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD +study + +// style : 2014-12-04 Binky Moon, LLC +style + +// sucks : 2014-12-22 Vox Populi Registry Inc. +sucks + +// supplies : 2013-12-19 Atomic Fields, LLC +supplies + +// supply : 2013-12-19 Half Falls, LLC +supply + +// support : 2013-10-24 Grand Orchard, LLC +support + +// surf : 2014-01-09 Top Level Domain Holdings Limited +surf + +// surgery : 2014-03-20 Tin Avenue, LLC +surgery + +// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +suzuki + +// swatch : 2015-01-08 The Swatch Group Ltd +swatch + +// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited +swiftcover + +// swiss : 2014-10-16 Swiss Confederation +swiss + +// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +sydney + +// symantec : 2014-12-04 Symantec Corporation +symantec + +// systems : 2013-11-07 Dash Cypress, LLC +systems + +// tab : 2014-12-04 Tabcorp Holdings Limited +tab + +// taipei : 2014-07-10 Taipei City Government +taipei + +// talk : 2015-04-09 Amazon EU S.à r.l. +talk + +// taobao : 2015-01-15 Alibaba Group Holding Limited +taobao + +// target : 2015-07-31 Target Domain Holdings, LLC +target + +// tatamotors : 2015-03-12 Tata Motors Ltd +tatamotors + +// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +tatar + +// tattoo : 2013-08-30 Uniregistry, Corp. +tattoo + +// tax : 2014-03-20 Storm Orchard, LLC +tax + +// taxi : 2015-03-19 Pine Falls, LLC +taxi + +// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +tci + +// tdk : 2015-06-11 TDK Corporation +tdk + +// team : 2015-03-05 Atomic Lake, LLC +team + +// tech : 2015-01-30 Dot Tech LLC +tech + +// technology : 2013-09-13 Auburn Falls +technology + +// telecity : 2015-02-19 TelecityGroup International Limited +telecity + +// telefonica : 2014-10-16 Telefónica S.A. +telefonica + +// temasek : 2014-08-07 Temasek Holdings (Private) Limited +temasek + +// tennis : 2014-12-04 Cotton Bloom, LLC +tennis + +// teva : 2015-07-02 Teva Pharmaceutical Industries Limited +teva + +// thd : 2015-04-02 Homer TLC, Inc. +thd + +// theater : 2015-03-19 Blue Tigers, LLC +theater + +// theatre : 2015-05-07 +theatre + +// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America +tiaa + +// tickets : 2015-02-05 Accent Media Limited +tickets + +// tienda : 2013-11-14 Victor Manor, LLC +tienda + +// tiffany : 2015-01-30 Tiffany and Company +tiffany + +// tips : 2013-09-20 Corn Willow, LLC +tips + +// tires : 2014-11-07 Dog Edge, LLC +tires + +// tirol : 2014-04-24 punkt Tirol GmbH +tirol + +// tjmaxx : 2015-07-16 The TJX Companies, Inc. +tjmaxx + +// tjx : 2015-07-16 The TJX Companies, Inc. +tjx + +// tkmaxx : 2015-07-16 The TJX Companies, Inc. +tkmaxx + +// tmall : 2015-01-15 Alibaba Group Holding Limited +tmall + +// today : 2013-09-20 Pearl Woods, LLC +today + +// tokyo : 2013-11-13 GMO Registry, Inc. +tokyo + +// tools : 2013-11-21 Pioneer North, LLC +tools + +// top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd. +top + +// toray : 2014-12-18 Toray Industries, Inc. +toray + +// toshiba : 2014-04-10 TOSHIBA Corporation +toshiba + +// total : 2015-08-06 Total SA +total + +// tours : 2015-01-22 Sugar Station, LLC +tours + +// town : 2014-03-06 Koko Moon, LLC +town + +// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +toyota + +// toys : 2014-03-06 Pioneer Orchard, LLC +toys + +// trade : 2014-01-23 Elite Registry Limited +trade + +// trading : 2014-12-11 IG Group Holdings PLC +trading + +// training : 2013-11-07 Wild Willow, LLC +training + +// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +travelchannel + +// travelers : 2015-03-26 Travelers TLD, LLC +travelers + +// travelersinsurance : 2015-03-26 Travelers TLD, LLC +travelersinsurance + +// trust : 2014-10-16 +trust + +// trv : 2015-03-26 Travelers TLD, LLC +trv + +// tube : 2015-06-11 Latin American Telecom LLC +tube + +// tui : 2014-07-03 TUI AG +tui + +// tunes : 2015-02-26 Amazon EU S.à r.l. +tunes + +// tushu : 2014-12-18 Amazon EU S.à r.l. +tushu + +// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +tvs + +// ubank : 2015-08-20 National Australia Bank Limited +ubank + +// ubs : 2014-12-11 UBS AG +ubs + +// uconnect : 2015-07-30 FCA US LLC. +uconnect + +// unicom : 2015-10-15 China United Network Communications Corporation Limited +unicom + +// university : 2014-03-06 Little Station, LLC +university + +// uno : 2013-09-11 Dot Latin LLC +uno + +// uol : 2014-05-01 UBN INTERNET LTDA. +uol + +// ups : 2015-06-25 UPS Market Driver, Inc. +ups + +// vacations : 2013-12-05 Atomic Tigers, LLC +vacations + +// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +vana + +// vanguard : 2015-09-03 The Vanguard Group, Inc. +vanguard + +// vegas : 2014-01-16 Dot Vegas, Inc. +vegas + +// ventures : 2013-08-27 Binky Lake, LLC +ventures + +// verisign : 2015-08-13 VeriSign, Inc. +verisign + +// versicherung : 2014-03-20 +versicherung + +// vet : 2014-03-06 +vet + +// viajes : 2013-10-17 Black Madison, LLC +viajes + +// video : 2014-10-16 +video + +// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +vig + +// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +viking + +// villas : 2013-12-05 New Sky, LLC +villas + +// vin : 2015-06-18 Holly Shadow, LLC +vin + +// vip : 2015-01-22 Minds + Machines Group Limited +vip + +// virgin : 2014-09-25 Virgin Enterprises Limited +virgin + +// visa : 2015-07-30 Visa Worldwide Pte. Limited +visa + +// vision : 2013-12-05 Koko Station, LLC +vision + +// vista : 2014-09-18 Vistaprint Limited +vista + +// vistaprint : 2014-09-18 Vistaprint Limited +vistaprint + +// viva : 2014-11-07 Saudi Telecom Company +viva + +// vivo : 2015-07-31 Telefonica Brasil S.A. +vivo + +// vlaanderen : 2014-02-06 DNS.be vzw +vlaanderen + +// vodka : 2013-12-19 Top Level Domain Holdings Limited +vodka + +// volkswagen : 2015-05-14 Volkswagen Group of America Inc. +volkswagen + +// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag +volvo + +// vote : 2013-11-21 Monolith Registry LLC +vote + +// voting : 2013-11-13 Valuetainment Corp. +voting + +// voto : 2013-11-21 Monolith Registry LLC +voto + +// voyage : 2013-08-27 Ruby House, LLC +voyage + +// vuelos : 2015-03-05 Travel Reservations SRL +vuelos + +// wales : 2014-05-08 Nominet UK +wales + +// walmart : 2015-07-31 Wal-Mart Stores, Inc. +walmart + +// walter : 2014-11-13 Sandvik AB +walter + +// wang : 2013-10-24 Zodiac Leo Limited +wang + +// wanggou : 2014-12-18 Amazon EU S.à r.l. +wanggou + +// warman : 2015-06-18 Weir Group IP Limited +warman + +// watch : 2013-11-14 Sand Shadow, LLC +watch + +// watches : 2014-12-22 Richemont DNS Inc. +watches + +// weather : 2015-01-08 The Weather Channel, LLC +weather + +// weatherchannel : 2015-03-12 The Weather Channel, LLC +weatherchannel + +// webcam : 2014-01-23 dot Webcam Limited +webcam + +// weber : 2015-06-04 Saint-Gobain Weber SA +weber + +// website : 2014-04-03 DotWebsite Inc. +website + +// wed : 2013-10-01 Atgron, Inc. +wed + +// wedding : 2014-04-24 Top Level Domain Holdings Limited +wedding + +// weibo : 2015-03-05 Sina Corporation +weibo + +// weir : 2015-01-29 Weir Group IP Limited +weir + +// whoswho : 2014-02-20 Who's Who Registry +whoswho + +// wien : 2013-10-28 punkt.wien GmbH +wien + +// wiki : 2013-11-07 Top Level Design, LLC +wiki + +// williamhill : 2014-03-13 William Hill Organization Limited +williamhill + +// win : 2014-11-20 First Registry Limited +win + +// windows : 2014-12-18 Microsoft Corporation +windows + +// wine : 2015-06-18 June Station, LLC +wine + +// winners : 2015-07-16 The TJX Companies, Inc. +winners + +// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +wme + +// wolterskluwer : 2015-08-06 Wolters Kluwer N.V. +wolterskluwer + +// woodside : 2015-07-09 Woodside Petroleum Limited +woodside + +// work : 2013-12-19 Top Level Domain Holdings Limited +work + +// works : 2013-11-14 Little Dynamite, LLC +works + +// world : 2014-06-12 Bitter Fields, LLC +world + +// wow : 2015-10-08 Amazon EU S.à r.l. +wow + +// wtc : 2013-12-19 World Trade Centers Association, Inc. +wtc + +// wtf : 2014-03-06 Hidden Way, LLC +wtf + +// xbox : 2014-12-18 Microsoft Corporation +xbox + +// xerox : 2014-10-24 Xerox DNHC LLC +xerox + +// xfinity : 2015-07-09 Comcast IP Holdings I, LLC +xfinity + +// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +xihuan + +// xin : 2014-12-11 Elegant Leader Limited +xin + +// xn--11b4c3d : 2015-01-15 VeriSign Sarl +कॉम + +// xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l. +セール + +// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +佛山 + +// xn--30rr7y : 2014-06-12 Excellent First Limited +慈善 + +// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +集团 + +// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED +在线 + +// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd. +大众汽车 + +// xn--3pxu8k : 2015-01-15 VeriSign Sarl +点看 + +// xn--42c2d9a : 2015-01-15 VeriSign Sarl +คอม + +// xn--45q11c : 2013-11-21 Zodiac Scorpio Limited +八卦 + +// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment +موقع + +// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +公益 + +// xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) +公司 + +// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited +香格里拉 + +// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +网站 + +// xn--6frz82g : 2013-09-23 Afilias Limited +移动 + +// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +我爱你 + +// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +москва + +// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +католик + +// xn--80asehdb : 2013-07-14 CORE Association +онлайн + +// xn--80aswg : 2013-07-14 CORE Association +сайт + +// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +联通 + +// xn--9dbq2a : 2015-01-15 VeriSign Sarl +קום + +// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +时尚 + +// xn--9krt00a : 2015-03-12 Sina Corporation +微博 + +// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +淡马锡 + +// xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l. +ファッション + +// xn--c1avg : 2013-11-14 Public Interest Registry +орг + +// xn--c2br7g : 2015-01-15 VeriSign Sarl +नेट + +// xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l. +ストア + +// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +삼성 + +// xn--czr694b : 2014-01-16 Dot Trademark TLD Holding Company Limited +商标 + +// xn--czrs0t : 2013-12-19 Wild Island, LLC +商店 + +// xn--czru2d : 2013-11-21 Zodiac Capricorn Limited +商城 + +// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +дети + +// xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l. +ポイント + +// xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社 +新闻 + +// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited +工行 + +// xn--fct429k : 2015-04-09 Amazon EU S.à r.l. +家電 + +// xn--fhbei : 2015-01-15 VeriSign Sarl +كوم + +// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED +中文网 + +// xn--fiq64b : 2013-10-14 CITIC Group Corporation +中信 + +// xn--fjq720a : 2014-05-22 Will Bloom, LLC +娱乐 + +// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +谷歌 + +// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited +電訊盈科 + +// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited +购物 + +// xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l. +クラウド + +// xn--gk3at1e : 2015-10-08 Amazon EU S.à r.l. +通販 + +// xn--hxt814e : 2014-05-15 Zodiac Libra Limited +网店 + +// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +संगठन + +// xn--imr513n : 2014-12-11 Dot Trademark TLD Holding Company Limited +餐厅 + +// xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) +网络 + +// xn--j1aef : 2015-01-15 VeriSign Sarl +ком + +// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation +诺基亚 + +// xn--jvr189m : 2015-02-26 Amazon EU S.à r.l. +食品 + +// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +飞利浦 + +// xn--kpu716f : 2014-12-22 Richemont DNS Inc. +手表 + +// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +手机 + +// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +ارامكو + +// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH +العليان + +// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +اتصالات + +// xn--mgbab2bd : 2013-10-31 CORE Association +بازار + +// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L. +موبايلي + +// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre +ابوظبي + +// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +كاثوليك + +// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +همراه + +// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +닷컴 + +// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +政府 + +// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +شبكة + +// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +بيتك + +// xn--ngbrx : 2015-11-12 League of Arab States +عرب + +// xn--nqv7f : 2013-11-14 Public Interest Registry +机构 + +// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +组织机构 + +// xn--nyqy26a : 2014-11-07 Stable Tone Limited +健康 + +// xn--p1acf : 2013-12-12 Rusnames Limited +рус + +// xn--pbt977c : 2014-12-22 Richemont DNS Inc. +珠宝 + +// xn--pssy2u : 2015-01-15 VeriSign Sarl +大拿 + +// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +みんな + +// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +グーグル + +// xn--rhqv96g : 2013-09-11 Stable Tone Limited +世界 + +// xn--rovu88b : 2015-02-26 Amazon EU S.à r.l. +書籍 + +// xn--ses554g : 2014-01-16 +网址 + +// xn--t60b56a : 2015-01-15 VeriSign Sarl +닷넷 + +// xn--tckwe : 2015-01-15 VeriSign Sarl +コム + +// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +天主教 + +// xn--unup4y : 2013-07-14 Spring Fields, LLC +游戏 + +// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberater + +// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberatung + +// xn--vhquv : 2013-08-27 Dash McCook, LLC +企业 + +// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +信息 + +// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +嘉里大酒店 + +// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited +嘉里 + +// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +广东 + +// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +政务 + +// xperia : 2015-05-14 Sony Mobile Communications AB +xperia + +// xyz : 2013-12-05 XYZ.COM LLC +xyz + +// yachts : 2014-01-09 DERYachts, LLC +yachts + +// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +yahoo + +// yamaxun : 2014-12-18 Amazon EU S.à r.l. +yamaxun + +// yandex : 2014-04-10 YANDEX, LLC +yandex + +// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +yodobashi + +// yoga : 2014-05-29 Top Level Domain Holdings Limited +yoga + +// yokohama : 2013-12-12 GMO Registry, Inc. +yokohama + +// you : 2015-04-09 Amazon EU S.à r.l. +you + +// youtube : 2014-05-01 Charleston Road Registry Inc. +youtube + +// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +yun + +// zappos : 2015-06-25 Amazon EU S.à r.l. +zappos + +// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +zara + +// zero : 2014-12-18 Amazon EU S.à r.l. +zero + +// zip : 2014-05-08 Charleston Road Registry Inc. +zip + +// zippo : 2015-07-02 Zadco Company +zippo + +// zone : 2013-11-14 Outer Falls, LLC +zone + +// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +zuerich + + +// ===END ICANN DOMAINS=== +// ===BEGIN PRIVATE DOMAINS=== +// (Note: these are in alphabetical order by company name) + +// 1GB LLC : https://www.1gb.ua/ +// Submitted by 1GB LLC +cc.ua +inf.ua +ltd.ua + +// AgileBits Inc : https://agilebits.com +// Submitted by Roustem Karimov +1password.ca +1password.com +1password.eu + +// Agnat sp. z o.o. : https://domena.pl +// Submitted by Przemyslaw Plewa +beep.pl + +// Alces Software Ltd : http://alces-software.com +// Submitted by Mark J. Titorenko +*.compute.estate +*.alces.network + +// alwaysdata : https://www.alwaysdata.com +// Submitted by Cyril +alwaysdata.net + +// Amazon CloudFront : https://aws.amazon.com/cloudfront/ +// Submitted by Donavan Miller +cloudfront.net + +// Amazon Elastic Compute Cloud : https://aws.amazon.com/ec2/ +// Submitted by Luke Wells +*.compute.amazonaws.com +*.compute-1.amazonaws.com +*.compute.amazonaws.com.cn +us-east-1.amazonaws.com + +// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/ +// Submitted by Luke Wells +cn-north-1.eb.amazonaws.com.cn +elasticbeanstalk.com +ap-northeast-1.elasticbeanstalk.com +ap-northeast-2.elasticbeanstalk.com +ap-south-1.elasticbeanstalk.com +ap-southeast-1.elasticbeanstalk.com +ap-southeast-2.elasticbeanstalk.com +ca-central-1.elasticbeanstalk.com +eu-central-1.elasticbeanstalk.com +eu-west-1.elasticbeanstalk.com +eu-west-2.elasticbeanstalk.com +eu-west-3.elasticbeanstalk.com +sa-east-1.elasticbeanstalk.com +us-east-1.elasticbeanstalk.com +us-east-2.elasticbeanstalk.com +us-gov-west-1.elasticbeanstalk.com +us-west-1.elasticbeanstalk.com +us-west-2.elasticbeanstalk.com + +// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/ +// Submitted by Luke Wells +*.elb.amazonaws.com +*.elb.amazonaws.com.cn + +// Amazon S3 : https://aws.amazon.com/s3/ +// Submitted by Luke Wells +s3.amazonaws.com +s3-ap-northeast-1.amazonaws.com +s3-ap-northeast-2.amazonaws.com +s3-ap-south-1.amazonaws.com +s3-ap-southeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3-ca-central-1.amazonaws.com +s3-eu-central-1.amazonaws.com +s3-eu-west-1.amazonaws.com +s3-eu-west-2.amazonaws.com +s3-eu-west-3.amazonaws.com +s3-external-1.amazonaws.com +s3-fips-us-gov-west-1.amazonaws.com +s3-sa-east-1.amazonaws.com +s3-us-gov-west-1.amazonaws.com +s3-us-east-2.amazonaws.com +s3-us-west-1.amazonaws.com +s3-us-west-2.amazonaws.com +s3.ap-northeast-2.amazonaws.com +s3.ap-south-1.amazonaws.com +s3.cn-north-1.amazonaws.com.cn +s3.ca-central-1.amazonaws.com +s3.eu-central-1.amazonaws.com +s3.eu-west-2.amazonaws.com +s3.eu-west-3.amazonaws.com +s3.us-east-2.amazonaws.com +s3.dualstack.ap-northeast-1.amazonaws.com +s3.dualstack.ap-northeast-2.amazonaws.com +s3.dualstack.ap-south-1.amazonaws.com +s3.dualstack.ap-southeast-1.amazonaws.com +s3.dualstack.ap-southeast-2.amazonaws.com +s3.dualstack.ca-central-1.amazonaws.com +s3.dualstack.eu-central-1.amazonaws.com +s3.dualstack.eu-west-1.amazonaws.com +s3.dualstack.eu-west-2.amazonaws.com +s3.dualstack.eu-west-3.amazonaws.com +s3.dualstack.sa-east-1.amazonaws.com +s3.dualstack.us-east-1.amazonaws.com +s3.dualstack.us-east-2.amazonaws.com +s3-website-us-east-1.amazonaws.com +s3-website-us-west-1.amazonaws.com +s3-website-us-west-2.amazonaws.com +s3-website-ap-northeast-1.amazonaws.com +s3-website-ap-southeast-1.amazonaws.com +s3-website-ap-southeast-2.amazonaws.com +s3-website-eu-west-1.amazonaws.com +s3-website-sa-east-1.amazonaws.com +s3-website.ap-northeast-2.amazonaws.com +s3-website.ap-south-1.amazonaws.com +s3-website.ca-central-1.amazonaws.com +s3-website.eu-central-1.amazonaws.com +s3-website.eu-west-2.amazonaws.com +s3-website.eu-west-3.amazonaws.com +s3-website.us-east-2.amazonaws.com + +// Amune : https://amune.org/ +// Submitted by Team Amune +t3l3p0rt.net +tele.amune.org + +// Aptible : https://www.aptible.com/ +// Submitted by Thomas Orozco +on-aptible.com + +// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ +// Submitted by Hector Martin +user.party.eus + +// Association potager.org : https://potager.org/ +// Submitted by Lunar +pimienta.org +poivron.org +potager.org +sweetpepper.org + +// ASUSTOR Inc. : http://www.asustor.com +// Submitted by Vincent Tseng +myasustor.com + +// AVM : https://avm.de +// Submitted by Andreas Weise +myfritz.net + +// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com +// Submitted by James Kennedy +*.awdev.ca +*.advisor.ws + +// backplane : https://www.backplane.io +// Submitted by Anthony Voutas +backplaneapp.io + +// BetaInABox +// Submitted by Adrian +betainabox.com + +// BinaryLane : http://www.binarylane.com +// Submitted by Nathan O'Sullivan +bnr.la + +// Boomla : https://boomla.com +// Submitted by Tibor Halter +boomla.net + +// Boxfuse : https://boxfuse.com +// Submitted by Axel Fontaine +boxfuse.io + +// bplaced : https://www.bplaced.net/ +// Submitted by Miroslav Bozic +square7.ch +bplaced.com +bplaced.de +square7.de +bplaced.net +square7.net + +// BrowserSafetyMark +// Submitted by Dave Tharp +browsersafetymark.io + +// callidomus : https://www.callidomus.com/ +// Submitted by Marcus Popp +mycd.eu + +// CentralNic : http://www.centralnic.com/names/domains +// Submitted by registry +ae.org +ar.com +br.com +cn.com +com.de +com.se +de.com +eu.com +gb.com +gb.net +hu.com +hu.net +jp.net +jpn.com +kr.com +mex.com +no.com +qc.com +ru.com +sa.com +se.com +se.net +uk.com +uk.net +us.com +uy.com +za.bz +za.com + +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown +africa.com + +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown +gr.com + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown +in.net + +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown +us.org + +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown +co.com + +// c.la : http://www.c.la/ +c.la + +// certmgr.org : https://certmgr.org +// Submitted by B. Blechschmidt +certmgr.org + +// Citrix : https://citrix.com +// Submitted by Alex Stoddard +xenapponazure.com + +// ClearVox : http://www.clearvox.nl/ +// Submitted by Leon Rowland +virtueeldomein.nl + +// Cloud66 : https://www.cloud66.com/ +// Submitted by Khash Sajadi +c66.me +cloud66.ws + +// CloudAccess.net : https://www.cloudaccess.net/ +// Submitted by Pawel Panek +jdevcloud.com +wpdevcloud.com +cloudaccess.host +freesite.host +cloudaccess.net + +// cloudControl : https://www.cloudcontrol.com/ +// Submitted by Tobias Wilken +cloudcontrolled.com +cloudcontrolapp.com + +// co.ca : http://registry.co.ca/ +co.ca + +// i-registry s.r.o. : http://www.i-registry.cz/ +// Submitted by Martin Semrad +co.cz + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes +c.cdn77.org +cdn77-ssl.net +r.cdn77.net +rsc.cdn77.org +ssl.origin.cdn77-secure.org + +// Cloud DNS Ltd : http://www.cloudns.net +// Submitted by Aleksander Hristov +cloudns.asia +cloudns.biz +cloudns.club +cloudns.cc +cloudns.eu +cloudns.in +cloudns.info +cloudns.org +cloudns.pro +cloudns.pw +cloudns.us + +// CoDNS B.V. +co.nl +co.no + +// Combell.com : https://www.combell.com +// Submitted by Thomas Wouters +webhosting.be +hosting-cluster.nl + +// COSIMO GmbH : http://www.cosimo.de +// Submitted by Rene Marticke +dyn.cosidns.de +dynamisches-dns.de +dnsupdater.de +internet-dns.de +l-o-g-i-n.de +dynamic-dns.info +feste-ip.net +knx-server.net +static-access.net + +// Craynic, s.r.o. : http://www.craynic.com/ +// Submitted by Ales Krajnik +realm.cz + +// Cryptonomic : https://cryptonomic.net/ +// Submitted by Andrew Cady +*.cryptonomic.net + +// Cupcake : https://cupcake.io/ +// Submitted by Jonathan Rudenberg +cupcake.is + +// cyon GmbH : https://www.cyon.ch/ +// Submitted by Dominic Luechinger +cyon.link +cyon.site + +// Daplie, Inc : https://daplie.com +// Submitted by AJ ONeal +daplie.me +localhost.daplie.me + +// Dansk.net : http://www.dansk.net/ +// Submitted by Anani Voule +biz.dk +co.dk +firm.dk +reg.dk +store.dk + +// Debian : https://www.debian.org/ +// Submitted by Peter Palfrader / Debian Sysadmin Team +debian.net + +// deSEC : https://desec.io/ +// Submitted by Peter Thomassen +dedyn.io + +// DNShome : https://www.dnshome.de/ +// Submitted by Norbert Auler +dnshome.de + +// DrayTek Corp. : https://www.draytek.com/ +// Submitted by Paul Fang +drayddns.com + +// DreamHost : http://www.dreamhost.com/ +// Submitted by Andrew Farmer +dreamhosters.com + +// Drobo : http://www.drobo.com/ +// Submitted by Ricardo Padilha +mydrobo.com + +// Drud Holdings, LLC. : https://www.drud.com/ +// Submitted by Kevin Bridges +drud.io +drud.us + +// DuckDNS : http://www.duckdns.org/ +// Submitted by Richard Harper +duckdns.org + +// dy.fi : http://dy.fi/ +// Submitted by Heikki Hannikainen +dy.fi +tunk.org + +// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com +dyndns.biz +dyndns.info +dyndns.org +dyndns.tv +at-band-camp.net +ath.cx +barrel-of-knowledge.info +barrell-of-knowledge.info +better-than.tv +blogdns.com +blogdns.net +blogdns.org +blogsite.org +boldlygoingnowhere.org +broke-it.net +buyshouses.net +cechire.com +dnsalias.com +dnsalias.net +dnsalias.org +dnsdojo.com +dnsdojo.net +dnsdojo.org +does-it.net +doesntexist.com +doesntexist.org +dontexist.com +dontexist.net +dontexist.org +doomdns.com +doomdns.org +dvrdns.org +dyn-o-saur.com +dynalias.com +dynalias.net +dynalias.org +dynathome.net +dyndns.ws +endofinternet.net +endofinternet.org +endoftheinternet.org +est-a-la-maison.com +est-a-la-masion.com +est-le-patron.com +est-mon-blogueur.com +for-better.biz +for-more.biz +for-our.info +for-some.biz +for-the.biz +forgot.her.name +forgot.his.name +from-ak.com +from-al.com +from-ar.com +from-az.net +from-ca.com +from-co.net +from-ct.com +from-dc.com +from-de.com +from-fl.com +from-ga.com +from-hi.com +from-ia.com +from-id.com +from-il.com +from-in.com +from-ks.com +from-ky.com +from-la.net +from-ma.com +from-md.com +from-me.org +from-mi.com +from-mn.com +from-mo.com +from-ms.com +from-mt.com +from-nc.com +from-nd.com +from-ne.com +from-nh.com +from-nj.com +from-nm.com +from-nv.com +from-ny.net +from-oh.com +from-ok.com +from-or.com +from-pa.com +from-pr.com +from-ri.com +from-sc.com +from-sd.com +from-tn.com +from-tx.com +from-ut.com +from-va.com +from-vt.com +from-wa.com +from-wi.com +from-wv.com +from-wy.com +ftpaccess.cc +fuettertdasnetz.de +game-host.org +game-server.cc +getmyip.com +gets-it.net +go.dyndns.org +gotdns.com +gotdns.org +groks-the.info +groks-this.info +ham-radio-op.net +here-for-more.info +hobby-site.com +hobby-site.org +home.dyndns.org +homedns.org +homeftp.net +homeftp.org +homeip.net +homelinux.com +homelinux.net +homelinux.org +homeunix.com +homeunix.net +homeunix.org +iamallama.com +in-the-band.net +is-a-anarchist.com +is-a-blogger.com +is-a-bookkeeper.com +is-a-bruinsfan.org +is-a-bulls-fan.com +is-a-candidate.org +is-a-caterer.com +is-a-celticsfan.org +is-a-chef.com +is-a-chef.net +is-a-chef.org +is-a-conservative.com +is-a-cpa.com +is-a-cubicle-slave.com +is-a-democrat.com +is-a-designer.com +is-a-doctor.com +is-a-financialadvisor.com +is-a-geek.com +is-a-geek.net +is-a-geek.org +is-a-green.com +is-a-guru.com +is-a-hard-worker.com +is-a-hunter.com +is-a-knight.org +is-a-landscaper.com +is-a-lawyer.com +is-a-liberal.com +is-a-libertarian.com +is-a-linux-user.org +is-a-llama.com +is-a-musician.com +is-a-nascarfan.com +is-a-nurse.com +is-a-painter.com +is-a-patsfan.org +is-a-personaltrainer.com +is-a-photographer.com +is-a-player.com +is-a-republican.com +is-a-rockstar.com +is-a-socialist.com +is-a-soxfan.org +is-a-student.com +is-a-teacher.com +is-a-techie.com +is-a-therapist.com +is-an-accountant.com +is-an-actor.com +is-an-actress.com +is-an-anarchist.com +is-an-artist.com +is-an-engineer.com +is-an-entertainer.com +is-by.us +is-certified.com +is-found.org +is-gone.com +is-into-anime.com +is-into-cars.com +is-into-cartoons.com +is-into-games.com +is-leet.com +is-lost.org +is-not-certified.com +is-saved.org +is-slick.com +is-uberleet.com +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +is-with-theband.com +isa-geek.com +isa-geek.net +isa-geek.org +isa-hockeynut.com +issmarterthanyou.com +isteingeek.de +istmein.de +kicks-ass.net +kicks-ass.org +knowsitall.info +land-4-sale.us +lebtimnetz.de +leitungsen.de +likes-pie.com +likescandy.com +merseine.nu +mine.nu +misconfused.org +mypets.ws +myphotos.cc +neat-url.com +office-on-the.net +on-the-web.tv +podzone.net +podzone.org +readmyblog.org +saves-the-whales.com +scrapper-site.net +scrapping.cc +selfip.biz +selfip.com +selfip.info +selfip.net +selfip.org +sells-for-less.com +sells-for-u.com +sells-it.net +sellsyourhome.org +servebbs.com +servebbs.net +servebbs.org +serveftp.net +serveftp.org +servegame.org +shacknet.nu +simple-url.com +space-to-rent.com +stuff-4-sale.org +stuff-4-sale.us +teaches-yoga.com +thruhere.net +traeumtgerade.de +webhop.biz +webhop.info +webhop.net +webhop.org +worse-than.tv +writesthisblog.com + +// ddnss.de : https://www.ddnss.de/ +// Submitted by Robert Niedziela +ddnss.de +dyn.ddnss.de +dyndns.ddnss.de +dyndns1.de +dyn-ip24.de +home-webserver.de +dyn.home-webserver.de +myhome-server.de +ddnss.org + +// Definima : http://www.definima.com/ +// Submitted by Maxence Bitterli +definima.net +definima.io + +// Dynu.com : https://www.dynu.com/ +// Submitted by Sue Ye +ddnsfree.com +ddnsgeek.com +giize.com +gleeze.com +kozow.com +loseyourip.com +ooguy.com +theworkpc.com +casacam.net +dynu.net +accesscam.org +camdvr.org +freeddns.org +mywire.org +webredirect.org +myddns.rocks +blogsite.xyz + +// dynv6 : https://dynv6.com +// Submitted by Dominik Menke +dynv6.net + +// E4YOU spol. s.r.o. : https://e4you.cz/ +// Submitted by Vladimir Dudr +e4.cz + +// Enalean SAS: https://www.enalean.com +// Submitted by Thomas Cottier +mytuleap.com + +// Enonic : http://enonic.com/ +// Submitted by Erik Kaareng-Sunde +enonic.io +customer.enonic.io + +// EU.org https://eu.org/ +// Submitted by Pierre Beyssac +eu.org +al.eu.org +asso.eu.org +at.eu.org +au.eu.org +be.eu.org +bg.eu.org +ca.eu.org +cd.eu.org +ch.eu.org +cn.eu.org +cy.eu.org +cz.eu.org +de.eu.org +dk.eu.org +edu.eu.org +ee.eu.org +es.eu.org +fi.eu.org +fr.eu.org +gr.eu.org +hr.eu.org +hu.eu.org +ie.eu.org +il.eu.org +in.eu.org +int.eu.org +is.eu.org +it.eu.org +jp.eu.org +kr.eu.org +lt.eu.org +lu.eu.org +lv.eu.org +mc.eu.org +me.eu.org +mk.eu.org +mt.eu.org +my.eu.org +net.eu.org +ng.eu.org +nl.eu.org +no.eu.org +nz.eu.org +paris.eu.org +pl.eu.org +pt.eu.org +q-a.eu.org +ro.eu.org +ru.eu.org +se.eu.org +si.eu.org +sk.eu.org +tr.eu.org +uk.eu.org +us.eu.org + +// Evennode : http://www.evennode.com/ +// Submitted by Michal Kralik +eu-1.evennode.com +eu-2.evennode.com +eu-3.evennode.com +eu-4.evennode.com +us-1.evennode.com +us-2.evennode.com +us-3.evennode.com +us-4.evennode.com + +// eDirect Corp. : https://hosting.url.com.tw/ +// Submitted by C.S. chang +twmail.cc +twmail.net +twmail.org +mymailer.com.tw +url.tw + +// Facebook, Inc. +// Submitted by Peter Ruibal +apps.fbsbx.com + +// FAITID : https://faitid.org/ +// Submitted by Maxim Alzoba +// https://www.flexireg.net/stat_info +ru.net +adygeya.ru +bashkiria.ru +bir.ru +cbg.ru +com.ru +dagestan.ru +grozny.ru +kalmykia.ru +kustanai.ru +marine.ru +mordovia.ru +msk.ru +mytis.ru +nalchik.ru +nov.ru +pyatigorsk.ru +spb.ru +vladikavkaz.ru +vladimir.ru +abkhazia.su +adygeya.su +aktyubinsk.su +arkhangelsk.su +armenia.su +ashgabad.su +azerbaijan.su +balashov.su +bashkiria.su +bryansk.su +bukhara.su +chimkent.su +dagestan.su +east-kazakhstan.su +exnet.su +georgia.su +grozny.su +ivanovo.su +jambyl.su +kalmykia.su +kaluga.su +karacol.su +karaganda.su +karelia.su +khakassia.su +krasnodar.su +kurgan.su +kustanai.su +lenug.su +mangyshlak.su +mordovia.su +msk.su +murmansk.su +nalchik.su +navoi.su +north-kazakhstan.su +nov.su +obninsk.su +penza.su +pokrovsk.su +sochi.su +spb.su +tashkent.su +termez.su +togliatti.su +troitsk.su +tselinograd.su +tula.su +tuva.su +vladikavkaz.su +vladimir.su +vologda.su + +// Fancy Bits, LLC : http://getchannels.com +// Submitted by Aman Gupta +channelsdvr.net + +// Fastly Inc. : http://www.fastly.com/ +// Submitted by Fastly Security +fastlylb.net +map.fastlylb.net +freetls.fastly.net +map.fastly.net +a.prod.fastly.net +global.prod.fastly.net +a.ssl.fastly.net +b.ssl.fastly.net +global.ssl.fastly.net + +// Featherhead : https://featherhead.xyz/ +// Submitted by Simon Menke +fhapp.xyz + +// Fedora : https://fedoraproject.org/ +// submitted by Patrick Uiterwijk +fedorainfracloud.org +fedorapeople.org +cloud.fedoraproject.org +app.os.fedoraproject.org +app.os.stg.fedoraproject.org + +// Filegear Inc. : https://www.filegear.com +// Submitted by Jason Zhu +filegear.me + +// Firebase, Inc. +// Submitted by Chris Raynor +firebaseapp.com + +// Flynn : https://flynn.io +// Submitted by Jonathan Rudenberg +flynnhub.com +flynnhosting.net + +// Freebox : http://www.freebox.fr +// Submitted by Romain Fliedel +freebox-os.com +freeboxos.com +fbx-os.fr +fbxos.fr +freebox-os.fr +freeboxos.fr + +// Futureweb OG : http://www.futureweb.at +// Submitted by Andreas Schnederle-Wagner +*.futurecms.at +futurehosting.at +futuremailing.at +*.ex.ortsinfo.at +*.kunden.ortsinfo.at +*.statics.cloud + +// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains +// Submitted by David Illsley +service.gov.uk + +// GitHub, Inc. +// Submitted by Patrick Toomey +github.io +githubusercontent.com + +// GitLab, Inc. +// Submitted by Alex Hanselka +gitlab.io + +// UKHomeOffice : https://www.gov.uk/government/organisations/home-office +// Submitted by Jon Shanks +homeoffice.gov.uk + +// GlobeHosting, Inc. +// Submitted by Zoltan Egresi +ro.im +shop.ro + +// GoIP DNS Services : http://www.goip.de +// Submitted by Christian Poulter +goip.de + +// Google, Inc. +// Submitted by Eduardo Vela +*.0emm.com +appspot.com +blogspot.ae +blogspot.al +blogspot.am +blogspot.ba +blogspot.be +blogspot.bg +blogspot.bj +blogspot.ca +blogspot.cf +blogspot.ch +blogspot.cl +blogspot.co.at +blogspot.co.id +blogspot.co.il +blogspot.co.ke +blogspot.co.nz +blogspot.co.uk +blogspot.co.za +blogspot.com +blogspot.com.ar +blogspot.com.au +blogspot.com.br +blogspot.com.by +blogspot.com.co +blogspot.com.cy +blogspot.com.ee +blogspot.com.eg +blogspot.com.es +blogspot.com.mt +blogspot.com.ng +blogspot.com.tr +blogspot.com.uy +blogspot.cv +blogspot.cz +blogspot.de +blogspot.dk +blogspot.fi +blogspot.fr +blogspot.gr +blogspot.hk +blogspot.hr +blogspot.hu +blogspot.ie +blogspot.in +blogspot.is +blogspot.it +blogspot.jp +blogspot.kr +blogspot.li +blogspot.lt +blogspot.lu +blogspot.md +blogspot.mk +blogspot.mr +blogspot.mx +blogspot.my +blogspot.nl +blogspot.no +blogspot.pe +blogspot.pt +blogspot.qa +blogspot.re +blogspot.ro +blogspot.rs +blogspot.ru +blogspot.se +blogspot.sg +blogspot.si +blogspot.sk +blogspot.sn +blogspot.td +blogspot.tw +blogspot.ug +blogspot.vn +cloudfunctions.net +cloud.goog +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +publishproxy.com +withgoogle.com +withyoutube.com + +// Hashbang : https://hashbang.sh +hashbang.sh + +// Hasura : https://hasura.io +// Submitted by Shahidh K Muhammed +hasura-app.io + +// Hepforge : https://www.hepforge.org +// Submitted by David Grellscheid +hepforge.org + +// Heroku : https://www.heroku.com/ +// Submitted by Tom Maher +herokuapp.com +herokussl.com + +// Ici la Lune : http://www.icilalune.com/ +// Submitted by Simon Morvan +moonscale.net + +// iki.fi +// Submitted by Hannu Aronsson +iki.fi + +// info.at : http://www.info.at/ +biz.at +info.at + +// info.cx : http://info.cx +// Submitted by Jacob Slater +info.cx + +// Interlegis : http://www.interlegis.leg.br +// Submitted by Gabriel Ferreira +ac.leg.br +al.leg.br +am.leg.br +ap.leg.br +ba.leg.br +ce.leg.br +df.leg.br +es.leg.br +go.leg.br +ma.leg.br +mg.leg.br +ms.leg.br +mt.leg.br +pa.leg.br +pb.leg.br +pe.leg.br +pi.leg.br +pr.leg.br +rj.leg.br +rn.leg.br +ro.leg.br +rr.leg.br +rs.leg.br +sc.leg.br +se.leg.br +sp.leg.br +to.leg.br + +// intermetrics GmbH : https://pixolino.com/ +// Submitted by Wolfgang Schwarz +pixolino.com + +// IPiFony Systems, Inc. : https://www.ipifony.com/ +// Submitted by Matthew Hardeman +ipifony.net + +// Joyent : https://www.joyent.com/ +// Submitted by Brian Bennett +*.triton.zone +*.cns.joyent.com + +// JS.ORG : http://dns.js.org +// Submitted by Stefan Keim +js.org + +// Keyweb AG : https://www.keyweb.de +// Submitted by Martin Dannehl +keymachine.de + +// KnightPoint Systems, LLC : http://www.knightpoint.com/ +// Submitted by Roy Keene +knightpoint.systems + +// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf +co.krd +edu.krd + +// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de +// Submitted by Lars Laehn +git-repos.de +lcube-server.de +svn-repos.de + +// linkyard ldt: https://www.linkyard.ch/ +// Submitted by Mario Siegenthaler +linkyard.cloud +linkyard-cloud.ch + +// LiquidNet Ltd : http://www.liquidnetlimited.com/ +// Submitted by Victor Velchev +we.bs + +// Lukanet Ltd : https://lukanet.com +// Submitted by Anton Avramov +barsy.bg +barsyonline.com +barsy.de +barsy.eu +barsy.in +barsy.net +barsy.online +barsy.support + +// Magento Commerce +// Submitted by Damien Tournoud +*.magentosite.cloud + +// Mail.Ru Group : https://hb.cldmail.ru +// Submitted by Ilya Zaretskiy +hb.cldmail.ru + +// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ +// Submitted by Zdeněk Šustr +cloud.metacentrum.cz +custom.metacentrum.cz + +// Meteor Development Group : https://www.meteor.com/hosting +// Submitted by Pierre Carrier +meteorapp.com +eu.meteorapp.com + +// Michau Enterprises Limited : http://www.co.pl/ +co.pl + +// Microsoft : http://microsoft.com +// Submitted by Barry Dorrans +azurewebsites.net +azure-mobile.net +cloudapp.net + +// Mozilla Corporation : https://mozilla.com +// Submitted by Ben Francis +mozilla-iot.org + +// Mozilla Foundation : https://mozilla.org/ +// Submitted by glob +bmoattachments.org + +// MSK-IX : https://www.msk-ix.ru/ +// Submitted by Khannanov Roman +net.ru +org.ru +pp.ru + +// Netlify : https://www.netlify.com +// Submitted by Jessica Parsons +bitballoon.com +netlify.com + +// Neustar Inc. +// Submitted by Trung Tran +4u.com + +// ngrok : https://ngrok.com/ +// Submitted by Alan Shreve +ngrok.io + +// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ +// Submitted by Nicholas Ford +nh-serv.co.uk + +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse +nfshost.com + +// nsupdate.info : https://www.nsupdate.info/ +// Submitted by Thomas Waldmann +nsupdate.info +nerdpol.ovh + +// No-IP.com : https://noip.com/ +// Submitted by Deven Reza +blogsyte.com +brasilia.me +cable-modem.org +ciscofreak.com +collegefan.org +couchpotatofries.org +damnserver.com +ddns.me +ditchyourip.com +dnsfor.me +dnsiskinky.com +dvrcam.info +dynns.com +eating-organic.net +fantasyleague.cc +geekgalaxy.com +golffan.us +health-carereform.com +homesecuritymac.com +homesecuritypc.com +hopto.me +ilovecollege.info +loginto.me +mlbfan.org +mmafan.biz +myactivedirectory.com +mydissent.net +myeffect.net +mymediapc.net +mypsx.net +mysecuritycamera.com +mysecuritycamera.net +mysecuritycamera.org +net-freaks.com +nflfan.org +nhlfan.net +no-ip.ca +no-ip.co.uk +no-ip.net +noip.us +onthewifi.com +pgafan.net +point2this.com +pointto.us +privatizehealthinsurance.net +quicksytes.com +read-books.org +securitytactics.com +serveexchange.com +servehumour.com +servep2p.com +servesarcasm.com +stufftoread.com +ufcfan.org +unusualperson.com +workisboring.com +3utilities.com +bounceme.net +ddns.net +ddnsking.com +gotdns.ch +hopto.org +myftp.biz +myftp.org +myvnc.com +no-ip.biz +no-ip.info +no-ip.org +noip.me +redirectme.net +servebeer.com +serveblog.net +servecounterstrike.com +serveftp.com +servegame.com +servehalflife.com +servehttp.com +serveirc.com +serveminecraft.net +servemp3.com +servepics.com +servequake.com +sytes.net +webhop.me +zapto.org + +// NodeArt : https://nodeart.io +// Submitted by Konstantin Nosov +stage.nodeart.io + +// Nodum B.V. : https://nodum.io/ +// Submitted by Wietse Wind +nodum.co +nodum.io + +// NYC.mn : http://www.information.nyc.mn +// Submitted by Matthew Brown +nyc.mn + +// NymNom : https://nymnom.com/ +// Submitted by Dave McCormack +nom.ae +nom.ai +nom.al +nym.by +nym.bz +nom.cl +nom.gd +nom.gl +nym.gr +nom.gt +nom.hn +nom.im +nym.kz +nym.la +nom.li +nym.li +nym.lt +nym.lu +nym.me +nom.mk +nym.mx +nom.nu +nym.nz +nym.pe +nym.pt +nom.pw +nom.qa +nom.rs +nom.si +nym.sk +nym.su +nym.sx +nym.tw +nom.ug +nom.uy +nom.vc +nom.vg + +// Octopodal Solutions, LLC. : https://ulterius.io/ +// Submitted by Andrew Sampson +cya.gg + +// One Fold Media : http://www.onefoldmedia.com/ +// Submitted by Eddie Jones +nid.io + +// OpenCraft GmbH : http://opencraft.com/ +// Submitted by Sven Marnach +opencraft.hosting + +// Opera Software, A.S.A. +// Submitted by Yngve Pettersen +operaunite.com + +// OutSystems +// Submitted by Duarte Santos +outsystemscloud.com + +// OwnProvider : http://www.ownprovider.com +// Submitted by Jan Moennich +ownprovider.com + +// oy.lc +// Submitted by Charly Coste +oy.lc + +// Pagefog : https://pagefog.com/ +// Submitted by Derek Myers +pgfog.com + +// Pagefront : https://www.pagefronthq.com/ +// Submitted by Jason Kriss +pagefrontapp.com + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// Pantheon Systems, Inc. : https://pantheon.io/ +// Submitted by Gary Dylina +pantheonsite.io +gotpantheon.com + +// Peplink | Pepwave : http://peplink.com/ +// Submitted by Steve Leung +mypep.link + +// Planet-Work : https://www.planet-work.com/ +// Submitted by Frédéric VANNIÈRE +on-web.fr + +// Platform.sh : https://platform.sh +// Submitted by Nikola Kotur +*.platform.sh +*.platformsh.site + +// prgmr.com : https://prgmr.com/ +// Submitted by Sarah Newman +xen.prgmr.com + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry +priv.at + +// Protonet GmbH : http://protonet.io +// Submitted by Martin Meier +protonet.io + +// Publication Presse Communication SARL : https://ppcom.fr +// Submitted by Yaacov Akiba Slama +chirurgiens-dentistes-en-france.fr +byen.site + +// QA2 +// Submitted by Daniel Dent (https://www.danieldent.com/) +qa2.com + +// QNAP System Inc : https://www.qnap.com +// Submitted by Nick Chang +dev-myqnapcloud.com +alpha-myqnapcloud.com +myqnapcloud.com + +// Quip : https://quip.com +// Submitted by Patrick Linehan +*.quipelements.com + +// Qutheory LLC : http://qutheory.io +// Submitted by Jonas Schwartz +vapor.cloud +vaporcloud.io + +// Rackmaze LLC : https://www.rackmaze.com +// Submitted by Kirill Pertsev +rackmaze.com +rackmaze.net + +// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ +// Submitted by Tim Kramer +rhcloud.com + +// Resin.io : https://resin.io +// Submitted by Tim Perry +resindevice.io +devices.resinstaging.io + +// RethinkDB : https://www.rethinkdb.com/ +// Submitted by Chris Kastorff +hzc.io + +// Revitalised Limited : http://www.revitalised.co.uk +// Submitted by Jack Price +wellbeingzone.eu +ptplus.fit +wellbeingzone.co.uk + +// Sandstorm Development Group, Inc. : https://sandcats.io/ +// Submitted by Asheesh Laroia +sandcats.io + +// SBE network solutions GmbH : https://www.sbe.de/ +// Submitted by Norman Meilick +logoip.de +logoip.com + +// schokokeks.org GbR : https://schokokeks.org/ +// Submitted by Hanno Böck +schokokeks.net + +// Scry Security : http://www.scrysec.com +// Submitted by Shante Adam +scrysec.com + +// Securepoint GmbH : https://www.securepoint.de +// Submitted by Erik Anders +firewall-gateway.com +firewall-gateway.de +my-gateway.de +my-router.de +spdns.de +spdns.eu +firewall-gateway.net +my-firewall.org +myfirewall.org +spdns.org + +// SensioLabs, SAS : https://sensiolabs.com/ +// Submitted by Fabien Potencier +*.s5y.io +*.sensiosite.cloud + +// Service Online LLC : http://drs.ua/ +// Submitted by Serhii Bulakh +biz.ua +co.ua +pp.ua + +// ShiftEdit : https://shiftedit.net/ +// Submitted by Adam Jimenez +shiftedit.io + +// Shopblocks : http://www.shopblocks.com/ +// Submitted by Alex Bowers +myshopblocks.com + +// SinaAppEngine : http://sae.sina.com.cn/ +// Submitted by SinaAppEngine +1kapp.com +appchizi.com +applinzi.com +sinaapp.com +vipsinaapp.com + +// Skyhat : http://www.skyhat.io +// Submitted by Shante Adam +bounty-full.com +alpha.bounty-full.com +beta.bounty-full.com + +// staticland : https://static.land +// Submitted by Seth Vincent +static.land +dev.static.land +sites.static.land + +// SourceLair PC : https://www.sourcelair.com +// Submitted by Antonis Kalipetis +apps.lair.io +*.stolos.io + +// SpaceKit : https://www.spacekit.io/ +// Submitted by Reza Akhavan +spacekit.io + +// Stackspace : https://www.stackspace.io/ +// Submitted by Lina He +stackspace.space + +// Storj Labs Inc. : https://storj.io/ +// Submitted by Philip Hutchins +storj.farm + +// Sub 6 Limited: http://www.sub6.com +// Submitted by Dan Miller +temp-dns.com + +// Synology, Inc. : https://www.synology.com/ +// Submitted by Rony Weng +diskstation.me +dscloud.biz +dscloud.me +dscloud.mobi +dsmynas.com +dsmynas.net +dsmynas.org +familyds.com +familyds.net +familyds.org +i234.me +myds.me +synology.me +vpnplus.to + +// TAIFUN Software AG : http://taifun-software.de +// Submitted by Bjoern Henke +taifun-dns.de + +// TASK geographical domains (www.task.gda.pl/uslugi/dns) +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl + +// Thingdust AG : https://thingdust.com/ +// Submitted by Adrian Imboden +cust.dev.thingdust.io +cust.disrec.thingdust.io +cust.prod.thingdust.io +cust.testing.thingdust.io + +// TownNews.com : http://www.townnews.com +// Submitted by Dustin Ward +bloxcms.com +townnews-staging.com + +// TrafficPlex GmbH : https://www.trafficplex.de/ +// Submitted by Phillipp Röll +12hp.at +2ix.at +4lima.at +lima-city.at +12hp.ch +2ix.ch +4lima.ch +lima-city.ch +trafficplex.cloud +de.cool +12hp.de +2ix.de +4lima.de +lima-city.de +1337.pictures +clan.rip +lima-city.rocks +webspace.rocks +lima.zone + +// TransIP : htts://www.transip.nl +// Submitted by Rory Breuk +*.transurl.be +*.transurl.eu +*.transurl.nl + +// TuxFamily : http://tuxfamily.org +// Submitted by TuxFamily administrators +tuxfamily.org + +// TwoDNS : https://www.twodns.de/ +// Submitted by TwoDNS-Support +dd-dns.de +diskstation.eu +diskstation.org +dray-dns.de +draydns.de +dyn-vpn.de +dynvpn.de +mein-vigor.de +my-vigor.de +my-wan.de +syno-ds.de +synology-diskstation.de +synology-ds.de + +// Uberspace : https://uberspace.de +// Submitted by Moritz Werner +uber.space + +// UDR Limited : http://www.udr.hk.com +// Submitted by registry +hk.com +hk.org +ltd.hk +inc.hk + +// .US +// Submitted by Ed Moore +lib.de.us + +// VeryPositive SIA : http://very.lv +// Submitted by Danko Aleksejevs +2038.io + +// Viprinet Europe GmbH : http://www.viprinet.com +// Submitted by Simon Kissel +router.management + +// Virtual-Info : https://www.virtual-info.info/ +// Submitted by Adnan RIHAN +v-info.info + +// WeDeploy by Liferay, Inc. : https://www.wedeploy.com +// Submitted by Henrique Vicente +wedeploy.io +wedeploy.me +wedeploy.sh + +// Western Digital Technologies, Inc : https://www.wdc.com +// Submitted by Jung Jin +remotewd.com + +// Wikimedia Labs : https://wikitech.wikimedia.org +// Submitted by Yuvi Panda +wmflabs.org + +// XS4ALL Internet bv : https://www.xs4all.nl/ +// Submitted by Daniel Mostertman +cistron.nl +demon.nl +xs4all.space + +// YesCourse Pty Ltd : https://yescourse.com +// Submitted by Atul Bhouraskar +official.academy + +// Yola : https://www.yola.com/ +// Submitted by Stefano Rivera +yolasite.com + +// Yombo : https://yombo.net +// Submitted by Mitch Schwenk +ybo.faith +yombo.me +homelink.one +ybo.party +ybo.review +ybo.science +ybo.trade + +// ZaNiC : http://www.za.net/ +// Submitted by registry +za.net +za.org + +// Zeit, Inc. : https://zeit.domains/ +// Submitted by Olli Vanhoja +now.sh + +// ===END PRIVATE DOMAINS=== diff --git a/fido_host/pyu2f/__init__.py b/fido_host/pyu2f/__init__.py new file mode 100644 index 0000000..bfe95c1 --- /dev/null +++ b/fido_host/pyu2f/__init__.py @@ -0,0 +1,56 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Implements interface for talking to hid devices. + +This module implenets an interface for talking to low level hid devices +using various methods on different platforms. +""" + +from __future__ import absolute_import + +import sys + + +class hid(object): + @staticmethod + def Enumerate(): + return InternalPlatformSwitch('Enumerate') + + + @staticmethod + def Open(path): + return InternalPlatformSwitch('__init__', path) + + +def InternalPlatformSwitch(funcname, *args, **kwargs): + """Determine, on a platform-specific basis, which module to use.""" + # pylint: disable=g-import-not-at-top + clz = None + if sys.platform.startswith('linux'): + from . import linux + clz = linux.LinuxHidDevice + elif sys.platform.startswith('win32'): + from . import windows + clz = windows.WindowsHidDevice + elif sys.platform.startswith('darwin'): + from . import macos + clz = macos.MacOsHidDevice + + if not clz: + raise Exception('Unsupported platform: ' + sys.platform) + + if funcname == '__init__': + return clz(*args, **kwargs) + return getattr(clz, funcname)(*args, **kwargs) diff --git a/fido_host/pyu2f/base.py b/fido_host/pyu2f/base.py new file mode 100644 index 0000000..73e0252 --- /dev/null +++ b/fido_host/pyu2f/base.py @@ -0,0 +1,101 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Implement base classes for hid package. + +This module provides the base classes implemented by the +platform-specific modules. It includes a base class for +all implementations built on interacting with file-like objects. +""" + + +class HidDevice(object): + """Base class for all HID devices in this package.""" + + @staticmethod + def Enumerate(): + """Enumerates all the hid devices. + + This function enumerates all the hid device and provides metadata + for helping the client select one. + + Returns: + A list of dictionaries of metadata. Each implementation is required + to provide at least: vendor_id, product_id, product_string, usage, + usage_page, and path. + """ + pass + + def __init__(self, path): + """Initialize the device at path.""" + pass + + def GetInReportDataLength(self): + """Returns the max input report data length in bytes. + + Returns the max input report data length in bytes. This excludes the + report id. + """ + pass + + def GetOutReportDataLength(self): + """Returns the max output report data length in bytes. + + Returns the max output report data length in bytes. This excludes the + report id. + """ + pass + + def Write(self, packet): + """Writes packet to device. + + Writes the packet to the device. + + Args: + packet: An array of integers to write to the device. Excludes the report + ID. Must be equal to GetOutReportLength(). + """ + pass + + def Read(self): + """Reads packet from device. + + Reads the packet from the device. + + Returns: + An array of integers read from the device. Excludes the report ID. + The length is equal to GetInReportDataLength(). + """ + pass + + +class DeviceDescriptor(object): + """Descriptor for basic attributes of the device.""" + + usage_page = None + usage = None + vendor_id = None + product_id = None + product_string = None + path = None + + internal_max_in_report_len = 0 + internal_max_out_report_len = 0 + + def ToPublicDict(self): + out = {} + for k, v in self.__dict__.items(): + if not k.startswith('internal_'): + out[k] = v + return out diff --git a/fido_host/pyu2f/errors.py b/fido_host/pyu2f/errors.py new file mode 100644 index 0000000..a149212 --- /dev/null +++ b/fido_host/pyu2f/errors.py @@ -0,0 +1,99 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Exceptions that can be raised by the pyu2f library. + +All exceptions that can be raised by the pyu2f library. Most of these +are internal coditions, but U2FError and NoDeviceFoundError are public +errors that clients should expect to handle. +""" + + +class NoDeviceFoundError(Exception): + pass + + +class U2FError(Exception): + OK = 0 + OTHER_ERROR = 1 + BAD_REQUEST = 2 + CONFIGURATION_UNSUPPORTED = 3 + DEVICE_INELIGIBLE = 4 + TIMEOUT = 5 + + def __init__(self, code, cause=None): + self.code = code + if cause: + self.cause = cause + super(U2FError, self).__init__('U2F Error code: %d (cause: %s)' % + (code, str(cause))) + + +class HidError(Exception): + """Errors in the hid usb transport protocol.""" + pass + + +class InvalidPacketError(HidError): + pass + + +class HardwareError(Exception): + """Errors in the security key hardware that are transport independent.""" + pass + + +class InvalidRequestError(HardwareError): + pass + + +class ApduError(HardwareError): + + def __init__(self, sw1, sw2): + self.sw1 = sw1 + self.sw2 = sw2 + super(ApduError, self).__init__('Device returned status: %d %d' % + (sw1, sw2)) + + +class TUPRequiredError(HardwareError): + pass + + +class InvalidKeyHandleError(HardwareError): + pass + + +class UnsupportedVersionException(Exception): + pass + + +class InvalidCommandError(Exception): + pass + + +class InvalidResponseError(Exception): + pass + + +class InvalidModelError(Exception): + pass + + +class OsHidError(Exception): + pass + + +class PluginError(Exception): + pass diff --git a/fido_host/pyu2f/hidtransport.py b/fido_host/pyu2f/hidtransport.py new file mode 100644 index 0000000..e349ba9 --- /dev/null +++ b/fido_host/pyu2f/hidtransport.py @@ -0,0 +1,338 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""HID Transport for U2F. + +This module imports the U2F HID Transport protocol as well as methods +for discovering devices implementing this protocol. +""" +from __future__ import absolute_import + +import logging +import os +import struct +import time +import six + +from . import errors, hid + + +def HidUsageSelector(device): + if device['usage_page'] == 0xf1d0 and device['usage'] == 0x01: + return True + return False + + +def DiscoverLocalHIDU2FDevices(selector=HidUsageSelector): + for d in hid.Enumerate(): + if selector(d): + try: + dev = hid.Open(d['path']) + yield UsbHidTransport(dev) + except OSError: + # Insufficient permissions to access device + pass + + +class UsbHidTransport(object): + """Implements the U2FHID transport protocol. + + This class implements the U2FHID transport protocol from the + FIDO U2F specs. This protocol manages fragmenting longer messages + over a short hid frame (usually 64 bytes). It exposes an APDU + channel through the MSG command as well as a series of other commands + for configuring and interacting with the device. + """ + + U2FHID_PING = 0x81 + U2FHID_MSG = 0x83 + U2FHID_WINK = 0x88 + U2FHID_PROMPT = 0x87 + U2FHID_INIT = 0x86 + U2FHID_LOCK = 0x84 + U2FHID_ERROR = 0xbf + U2FHID_SYNC = 0xbc + + CTAPHID_KEEPALIVE = 0xbb + + U2FHID_BROADCAST_CID = bytearray([0xff, 0xff, 0xff, 0xff]) + + ERR_CHANNEL_BUSY = bytearray([0x06]) + + + class InitPacket(object): + """Represent an initial U2FHID packet. + + Represent an initial U2FHID packet. This packet contains + metadata necessary to interpret the entire packet stream associated + with a particular exchange (read or write). + + Attributes: + packet_size: The size of the hid report (packet) used. Usually 64. + cid: The channel id for the connection to the device. + size: The size of the entire message to be sent (including + all continuation packets) + payload: The portion of the message to put into the init packet. + This must be smaller than packet_size - 7 (the overhead for + an init packet). + """ + + def __init__(self, packet_size, cid, cmd, size, payload): + self.packet_size = packet_size + if len(cid) != 4 or cmd > 255 or size >= 2**16: + raise errors.InvalidPacketError() + if len(payload) > self.packet_size - 7: + raise errors.InvalidPacketError() + + self.cid = cid # byte array + self.cmd = cmd # number + self.size = size # number (full size of message) + self.payload = payload # byte array (for first packet) + + def ToWireFormat(self): + """Serializes the packet.""" + ret = bytearray(64) + ret[0:4] = self.cid + ret[4] = self.cmd + struct.pack_into('>H', ret, 5, self.size) + ret[7:7 + len(self.payload)] = self.payload + return list(six.iterbytes(bytes(ret))) + + @staticmethod + def FromWireFormat(packet_size, data): + """Derializes the packet. + + Deserializes the packet from wire format. + + Args: + packet_size: The size of all packets (usually 64) + data: List of ints or bytearray containing the data from the wire. + + Returns: + InitPacket object for specified data + + Raises: + InvalidPacketError: if the data isn't a valid InitPacket + """ + ba = bytearray(data) + if len(ba) != packet_size: + raise errors.InvalidPacketError() + cid = ba[0:4] + cmd = ba[4] + size = struct.unpack('>H', bytes(ba[5:7]))[0] + payload = ba[7:7 + size] # might truncate at packet_size + return UsbHidTransport.InitPacket(packet_size, cid, cmd, size, payload) + + class ContPacket(object): + """Represents a continutation U2FHID packet. + + Represents a continutation U2FHID packet. These packets follow + the intial packet and contains the remaining data in a particular + message. + + Attributes: + packet_size: The size of the hid report (packet) used. Usually 64. + cid: The channel id for the connection to the device. + seq: The sequence number for this continuation packet. The first + continuation packet is 0 and it increases from there. + payload: The payload to put into this continuation packet. This + must be less than packet_size - 5 (the overhead of the + continuation packet is 5). + """ + + def __init__(self, packet_size, cid, seq, payload): + self.packet_size = packet_size + self.cid = cid + self.seq = seq + self.payload = payload + if len(payload) > self.packet_size - 5: + raise errors.InvalidPacketError() + if seq > 127: + raise errors.InvalidPacketError() + + def ToWireFormat(self): + """Serializes the packet.""" + ret = bytearray(self.packet_size) + ret[0:4] = self.cid + ret[4] = self.seq + ret[5:5 + len(self.payload)] = self.payload + return [int(x) for x in ret] + + @staticmethod + def FromWireFormat(packet_size, data): + """Derializes the packet. + + Deserializes the packet from wire format. + + Args: + packet_size: The size of all packets (usually 64) + data: List of ints or bytearray containing the data from the wire. + + Returns: + InitPacket object for specified data + + Raises: + InvalidPacketError: if the data isn't a valid ContPacket + """ + ba = bytearray(data) + if len(ba) != packet_size: + raise errors.InvalidPacketError() + cid = ba[0:4] + seq = ba[4] + # We don't know the size limit a priori here without seeing the init + # packet, so truncation needs to be done in the higher level protocol + # handling code, unlike the degenerate case of a 1 packet message in an + # init packet, where the size is known. + payload = ba[5:] + return UsbHidTransport.ContPacket(packet_size, cid, seq, payload) + + def __init__(self, hid_device, read_timeout_secs=3.0): + self.hid_device = hid_device + + in_size = hid_device.GetInReportDataLength() + out_size = hid_device.GetOutReportDataLength() + if in_size != out_size: + raise errors.HardwareError( + 'unsupported device with different in/out packet sizes.') + if in_size == 0: + raise errors.HardwareError('unable to determine packet size') + + self.packet_size = in_size + self.read_timeout_secs = read_timeout_secs + self.logger = logging.getLogger('pyu2f.hidtransport') + + self.InternalInit() + + def SendMsgBytes(self, msg): + r = self.InternalExchange(UsbHidTransport.U2FHID_MSG, msg) + return r + + def SendBlink(self, length): + return self.InternalExchange(UsbHidTransport.U2FHID_PROMPT, + bytearray([length])) + + def SendWink(self): + return self.InternalExchange(UsbHidTransport.U2FHID_WINK, bytearray([])) + + def SendPing(self, data): + return self.InternalExchange(UsbHidTransport.U2FHID_PING, data) + + def InternalInit(self): + """Initializes the device and obtains channel id.""" + self.cid = UsbHidTransport.U2FHID_BROADCAST_CID + nonce = bytearray(os.urandom(8)) + r = self.InternalExchange(UsbHidTransport.U2FHID_INIT, nonce) + if len(r) < 17: + raise errors.HidError('unexpected init reply len') + if r[0:8] != nonce: + raise errors.HidError('nonce mismatch') + self.cid = bytearray(r[8:12]) + + self.u2fhid_version = r[12] + self.device_version = tuple(r[13:16]) + self.capabilities = r[16] + + def InternalExchange(self, cmd, payload_in): + """Sends and receives a message from the device.""" + # make a copy because we destroy it below + self.logger.debug('payload: ' + str(list(payload_in))) + payload = bytearray() + payload[:] = payload_in + for _ in range(2): + self.InternalSend(cmd, payload) + ret_cmd, ret_payload = self.InternalRecv() + + if ret_cmd == UsbHidTransport.U2FHID_ERROR: + if ret_payload == UsbHidTransport.ERR_CHANNEL_BUSY: + time.sleep(0.5) + continue + raise errors.HidError('Device error: %d' % int(ret_payload[0])) + elif ret_cmd != cmd: + raise errors.HidError('Command mismatch!') + + return ret_payload + raise errors.HidError('Device Busy. Please retry') + + def InternalSend(self, cmd, payload): + """Sends a message to the device, including fragmenting it.""" + length_to_send = len(payload) + + max_payload = self.packet_size - 7 + first_frame = payload[0:max_payload] + first_packet = UsbHidTransport.InitPacket(self.packet_size, self.cid, cmd, + len(payload), first_frame) + del payload[0:max_payload] + length_to_send -= len(first_frame) + self.InternalSendPacket(first_packet) + + seq = 0 + while length_to_send > 0: + max_payload = self.packet_size - 5 + next_frame = payload[0:max_payload] + del payload[0:max_payload] + length_to_send -= len(next_frame) + next_packet = UsbHidTransport.ContPacket(self.packet_size, self.cid, seq, + next_frame) + self.InternalSendPacket(next_packet) + seq += 1 + + def InternalSendPacket(self, packet): + wire = packet.ToWireFormat() + self.logger.debug('sending packet: ' + str(wire)) + self.hid_device.Write(wire) + + def InternalReadFrame(self): + # TODO(gdasher): Figure out timeouts. Today, this implementation + # blocks forever at the HID level waiting for a response to a report. + # This may not be reasonable behavior (though in practice in seems to be + # OK on the set of devices and machines tested so far). + frame = self.hid_device.Read() + self.logger.debug('recv: ' + str(frame)) + return frame + + def InternalRecv(self): + """Receives a message from the device, including defragmenting it.""" + first_read = self.InternalReadFrame() + first_packet = UsbHidTransport.InitPacket.FromWireFormat(self.packet_size, + first_read) + + data = first_packet.payload + to_read = first_packet.size - len(first_packet.payload) + + seq = 0 + while to_read > 0: + next_read = self.InternalReadFrame() + next_packet = UsbHidTransport.ContPacket.FromWireFormat(self.packet_size, + next_read) + if self.cid != next_packet.cid: + # Skip over packets that are for communication with other clients. + # HID is broadcast, so we see potentially all communication from the + # device. For well-behaved devices, these should be BUSY messages + # sent to other clients of the device because at this point we're + # in mid-message transit. + continue + + if seq != next_packet.seq: + raise errors.HardwareError('Packets received out of order') + + # This packet for us at this point, so debit it against our + # balance of bytes to read. + to_read -= len(next_packet.payload) + + data.extend(next_packet.payload) + seq += 1 + + # truncate incomplete frames + data = data[0:first_packet.size] + return (first_packet.cmd, data) diff --git a/fido_host/pyu2f/linux.py b/fido_host/pyu2f/linux.py new file mode 100644 index 0000000..c6ddb4f --- /dev/null +++ b/fido_host/pyu2f/linux.py @@ -0,0 +1,228 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Implements raw HID interface on Linux using SysFS and device files.""" + +from __future__ import absolute_import + +import os +import struct +import six + +from . import base, errors + +REPORT_DESCRIPTOR_KEY_MASK = 0xfc +LONG_ITEM_ENCODING = 0xfe +OUTPUT_ITEM = 0x90 +INPUT_ITEM = 0x80 +COLLECTION_ITEM = 0xa0 +REPORT_COUNT = 0x94 +REPORT_SIZE = 0x74 +USAGE_PAGE = 0x04 +USAGE = 0x08 + + +def GetValueLength(rd, pos): + """Get value length for a key in rd. + + For a key at position pos in the Report Descriptor rd, return the length + of the associated value. This supports both short and long format + values. + + Args: + rd: Report Descriptor + pos: The position of the key in rd. + + Returns: + (key_size, data_len) where key_size is the number of bytes occupied by + the key and data_len is the length of the value associated by the key. + """ + key = six.indexbytes(rd, pos) + if key == LONG_ITEM_ENCODING: + # If the key is tagged as a long item (0xfe), then the format is + # [key (1 byte)] [data len (1 byte)] [item tag (1 byte)] [data (n # bytes)]. + # Thus, the entire key record is 3 bytes long. + if pos + 1 < len(rd): + return (3, rd[pos + 1]) + else: + raise errors.HidError('Malformed report descriptor') + + else: + # If the key is tagged as a short item, then the item tag and data len are + # packed into one byte. The format is thus: + # [tag (high 4 bits)] [type (2 bits)] [size code (2 bits)] [data (n bytes)]. + # The size code specifies 1,2, or 4 bytes (0x03 means 4 bytes). + code = key & 0x03 + if code <= 0x02: + return (1, code) + elif code == 0x03: + return (1, 4) + + raise errors.HidError('Cannot happen') + + +def ReadLsbBytes(rd, offset, value_size): + """Reads value_size bytes from rd at offset, least signifcant byte first.""" + + encoding = None + if value_size == 1: + encoding = '= pos + 1 + value_length: + report_count = ReadLsbBytes(rd, pos + 1, value_length) + elif key & REPORT_DESCRIPTOR_KEY_MASK == REPORT_SIZE: + if len(rd) >= pos + 1 + value_length: + report_size = ReadLsbBytes(rd, pos + 1, value_length) + elif key & REPORT_DESCRIPTOR_KEY_MASK == USAGE_PAGE: + if len(rd) >= pos + 1 + value_length: + usage_page = ReadLsbBytes(rd, pos + 1, value_length) + elif key & REPORT_DESCRIPTOR_KEY_MASK == USAGE: + if len(rd) >= pos + 1 + value_length: + usage = ReadLsbBytes(rd, pos + 1, value_length) + + pos += value_length + key_size + return desc + + +def ParseUevent(uevent, desc): + lines = uevent.split(b'\n') + for line in lines: + line = line.strip() + if not line: + continue + k, v = line.split(b'=') + if k == b'HID_NAME': + desc.product_string = v.decode('utf8') + elif k == b'HID_ID': + _, vid, pid = v.split(b':') + desc.vendor_id = int(vid, 16) + desc.product_id = int(pid, 16) + + +class LinuxHidDevice(base.HidDevice): + """Implementation of HID device for linux. + + Implementation of HID device interface for linux that uses block + devices to interact with the device and sysfs to enumerate/discover + device metadata. + """ + + @staticmethod + def Enumerate(): + for hidraw in os.listdir('/sys/class/hidraw'): + rd_path = ( + os.path.join( + '/sys/class/hidraw', hidraw, + 'device/report_descriptor')) + uevent_path = os.path.join('/sys/class/hidraw', hidraw, 'device/uevent') + rd_file = open(rd_path, 'rb') + uevent_file = open(uevent_path, 'rb') + desc = base.DeviceDescriptor() + desc.path = os.path.join('/dev/', hidraw) + ParseReportDescriptor(rd_file.read(), desc) + ParseUevent(uevent_file.read(), desc) + + rd_file.close() + uevent_file.close() + yield desc.ToPublicDict() + + def __init__(self, path): + base.HidDevice.__init__(self, path) + self.dev = os.open(path, os.O_RDWR) + self.desc = base.DeviceDescriptor() + self.desc.path = path + rd_file = open(os.path.join('/sys/class/hidraw', + os.path.basename(path), + 'device/report_descriptor'), 'rb') + ParseReportDescriptor(rd_file.read(), self.desc) + rd_file.close() + + def GetInReportDataLength(self): + """See base class.""" + return self.desc.internal_max_in_report_len + + def GetOutReportDataLength(self): + """See base class.""" + return self.desc.internal_max_out_report_len + + def Write(self, packet): + """See base class.""" + out = bytes(bytearray([0] + packet)) # Prepend the zero-byte (report ID) + os.write(self.dev, out) + + def Read(self): + """See base class.""" + raw_in = os.read(self.dev, self.GetInReportDataLength()) + decoded_in = list(six.iterbytes(raw_in)) + return decoded_in diff --git a/fido_host/pyu2f/macos.py b/fido_host/pyu2f/macos.py new file mode 100644 index 0000000..9cc05fc --- /dev/null +++ b/fido_host/pyu2f/macos.py @@ -0,0 +1,448 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Implements HID device interface on MacOS using IOKit and HIDManager.""" + +from __future__ import absolute_import + +import ctypes +import ctypes.util +import logging +from six.moves.queue import Queue +import sys +import threading + +from . import base, errors + +logger = logging.getLogger('pyu2f.macos') + +# Constants +DEVICE_PATH_BUFFER_SIZE = 512 +DEVICE_STRING_PROPERTY_BUFFER_SIZE = 512 + +HID_DEVICE_PROPERTY_VENDOR_ID = b'VendorID' +HID_DEVICE_PROPERTY_PRODUCT_ID = b'ProductID' +HID_DEVICE_PROPERTY_PRODUCT = b'Product' +HID_DEVICE_PROPERTY_PRIMARY_USAGE = b'PrimaryUsage' +HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE = b'PrimaryUsagePage' +HID_DEVICE_PROPERTY_MAX_INPUT_REPORT_SIZE = b'MaxInputReportSize' +HID_DEVICE_PROPERTY_MAX_OUTPUT_REPORT_SIZE = b'MaxOutputReportSize' +HID_DEVICE_PROPERTY_REPORT_ID = b'ReportID' + + +# Declare C types +class _CFType(ctypes.Structure): + pass + + +class _CFString(_CFType): + pass + + +class _CFSet(_CFType): + pass + + +class _IOHIDManager(_CFType): + pass + + +class _IOHIDDevice(_CFType): + pass + + +class _CFRunLoop(_CFType): + pass + + +class _CFAllocator(_CFType): + pass + + +# Linter isn't consistent about valid class names. Disabling some of the errors +CF_SET_REF = ctypes.POINTER(_CFSet) +CF_STRING_REF = ctypes.POINTER(_CFString) +CF_TYPE_REF = ctypes.POINTER(_CFType) +CF_RUN_LOOP_REF = ctypes.POINTER(_CFRunLoop) +CF_RUN_LOOP_RUN_RESULT = ctypes.c_int32 +CF_ALLOCATOR_REF = ctypes.POINTER(_CFAllocator) +CF_TYPE_ID = ctypes.c_ulong # pylint: disable=invalid-name +CF_INDEX = ctypes.c_long # pylint: disable=invalid-name +CF_TIME_INTERVAL = ctypes.c_double # pylint: disable=invalid-name +IO_RETURN = ctypes.c_uint +IO_HID_REPORT_TYPE = ctypes.c_uint +IO_OBJECT_T = ctypes.c_uint +MACH_PORT_T = ctypes.c_uint +IO_STRING_T = ctypes.c_char_p # pylint: disable=invalid-name +IO_SERVICE_T = IO_OBJECT_T +IO_REGISTRY_ENTRY_T = IO_OBJECT_T + +IO_HID_MANAGER_REF = ctypes.POINTER(_IOHIDManager) +IO_HID_DEVICE_REF = ctypes.POINTER(_IOHIDDevice) + +IO_HID_REPORT_CALLBACK = ctypes.CFUNCTYPE(None, ctypes.py_object, IO_RETURN, + ctypes.c_void_p, IO_HID_REPORT_TYPE, + ctypes.c_uint32, + ctypes.POINTER(ctypes.c_uint8), + CF_INDEX) + +# Define C constants +K_CF_NUMBER_SINT32_TYPE = 3 +K_CF_STRING_ENCODING_UTF8 = 0x08000100 +K_CF_ALLOCATOR_DEFAULT = None + +K_IO_SERVICE_PLANE = b'IOService' +K_IO_MASTER_PORT_DEFAULT = 0 +K_IO_HID_REPORT_TYPE_OUTPUT = 1 +K_IO_RETURN_SUCCESS = 0 + +K_CF_RUN_LOOP_RUN_STOPPED = 2 +K_CF_RUN_LOOP_RUN_TIMED_OUT = 3 +K_CF_RUN_LOOP_RUN_HANDLED_SOURCE = 4 + +# Load relevant libraries +iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit')) +cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) + +# Only use iokit and cf if we're on macos, this way we can still run tests +# on other platforms if we properly mock +if sys.platform.startswith('darwin'): + # Exported constants + K_CF_RUNLOOP_DEFAULT_MODE = CF_STRING_REF.in_dll(cf, 'kCFRunLoopDefaultMode') + + # Declare C function prototypes + cf.CFSetGetValues.restype = None + cf.CFSetGetValues.argtypes = [CF_SET_REF, ctypes.POINTER(ctypes.c_void_p)] + cf.CFStringCreateWithCString.restype = CF_STRING_REF + cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, + ctypes.c_uint32] + cf.CFStringGetCString.restype = ctypes.c_int + cf.CFStringGetCString.argtypes = [CF_STRING_REF, ctypes.c_char_p, CF_INDEX, + ctypes.c_uint32] + cf.CFStringGetLength.restype = CF_INDEX + cf.CFStringGetLength.argtypes = [CF_STRING_REF] + cf.CFGetTypeID.restype = CF_TYPE_ID + cf.CFGetTypeID.argtypes = [CF_TYPE_REF] + cf.CFNumberGetTypeID.restype = CF_TYPE_ID + cf.CFNumberGetValue.restype = ctypes.c_int + cf.CFRelease.restype = None + cf.CFRelease.argtypes = [CF_TYPE_REF] + cf.CFRunLoopGetCurrent.restype = CF_RUN_LOOP_REF + cf.CFRunLoopGetCurrent.argTypes = [] + cf.CFRunLoopRunInMode.restype = CF_RUN_LOOP_RUN_RESULT + cf.CFRunLoopRunInMode.argtypes = [CF_STRING_REF, CF_TIME_INTERVAL, + ctypes.c_bool] + + iokit.IOObjectRelease.argtypes = [IO_OBJECT_T] + iokit.IOHIDManagerCreate.restype = IO_HID_MANAGER_REF + iokit.IOHIDManagerCopyDevices.restype = CF_SET_REF + iokit.IOHIDManagerCopyDevices.argtypes = [IO_HID_MANAGER_REF] + iokit.IOHIDManagerSetDeviceMatching.restype = None + iokit.IOHIDManagerSetDeviceMatching.argtypes = [IO_HID_MANAGER_REF, + CF_TYPE_REF] + iokit.IOHIDDeviceGetProperty.restype = CF_TYPE_REF + iokit.IOHIDDeviceGetProperty.argtypes = [IO_HID_DEVICE_REF, CF_STRING_REF] + iokit.IOHIDDeviceRegisterInputReportCallback.restype = None + iokit.IOHIDDeviceRegisterInputReportCallback.argtypes = [ + IO_HID_DEVICE_REF, ctypes.POINTER(ctypes.c_uint8), CF_INDEX, + IO_HID_REPORT_CALLBACK, ctypes.py_object] + iokit.IORegistryEntryFromPath.restype = IO_REGISTRY_ENTRY_T + iokit.IORegistryEntryFromPath.argtypes = [MACH_PORT_T, IO_STRING_T] + iokit.IOHIDDeviceCreate.restype = IO_HID_DEVICE_REF + iokit.IOHIDDeviceCreate.argtypes = [CF_ALLOCATOR_REF, IO_SERVICE_T] + iokit.IOHIDDeviceScheduleWithRunLoop.restype = None + iokit.IOHIDDeviceScheduleWithRunLoop.argtypes = [IO_HID_DEVICE_REF, + CF_RUN_LOOP_REF, + CF_STRING_REF] + iokit.IOHIDDeviceUnscheduleFromRunLoop.restype = None + iokit.IOHIDDeviceUnscheduleFromRunLoop.argtypes = [IO_HID_DEVICE_REF, + CF_RUN_LOOP_REF, + CF_STRING_REF] + iokit.IOHIDDeviceSetReport.restype = IO_RETURN + iokit.IOHIDDeviceSetReport.argtypes = [IO_HID_DEVICE_REF, IO_HID_REPORT_TYPE, + CF_INDEX, + ctypes.POINTER(ctypes.c_uint8), + CF_INDEX] +else: + logger.warn('Not running on MacOS') + + +def CFStr(s): + """Builds a CFString from a python string. + + Args: + s: source string + + Returns: + CFStringRef representation of the source string + + Resulting CFString must be CFReleased when no longer needed. + """ + return cf.CFStringCreateWithCString(None, s, 0) + + +def GetDeviceIntProperty(dev_ref, key): + """Reads int property from the HID device.""" + cf_key = CFStr(key) + type_ref = iokit.IOHIDDeviceGetProperty(dev_ref, cf_key) + cf.CFRelease(cf_key) + if not type_ref: + return None + + if cf.CFGetTypeID(type_ref) != cf.CFNumberGetTypeID(): + raise errors.OsHidError('Expected number type, got {}'.format( + cf.CFGetTypeID(type_ref))) + + out = ctypes.c_int32() + ret = cf.CFNumberGetValue(type_ref, K_CF_NUMBER_SINT32_TYPE, + ctypes.byref(out)) + if not ret: + return None + + return out.value + + +def GetDeviceStringProperty(dev_ref, key): + """Reads string property from the HID device.""" + cf_key = CFStr(key) + type_ref = iokit.IOHIDDeviceGetProperty(dev_ref, cf_key) + cf.CFRelease(cf_key) + if not type_ref: + return None + + if cf.CFGetTypeID(type_ref) != cf.CFStringGetTypeID(): + raise errors.OsHidError('Expected string type, got {}'.format( + cf.CFGetTypeID(type_ref))) + + type_ref = ctypes.cast(type_ref, CF_STRING_REF) + out = ctypes.create_string_buffer(DEVICE_STRING_PROPERTY_BUFFER_SIZE) + ret = cf.CFStringGetCString(type_ref, out, DEVICE_STRING_PROPERTY_BUFFER_SIZE, + K_CF_STRING_ENCODING_UTF8) + if not ret: + return None + + return out.value.decode('utf8') + + +def GetDevicePath(device_handle): + """Obtains the unique path for the device. + + Args: + device_handle: reference to the device + + Returns: + A unique path for the device, obtained from the IO Registry + + """ + # Obtain device path from IO Registry + io_service_obj = iokit.IOHIDDeviceGetService(device_handle) + str_buffer = ctypes.create_string_buffer(DEVICE_PATH_BUFFER_SIZE) + iokit.IORegistryEntryGetPath(io_service_obj, K_IO_SERVICE_PLANE, str_buffer) + + return str_buffer.value + + +def HidReadCallback(read_queue, result, sender, report_type, report_id, report, + report_length): + """Handles incoming IN report from HID device.""" + del result, sender, report_type, report_id # Unused by the callback function + + incoming_bytes = [report[i] for i in range(report_length)] + read_queue.put(incoming_bytes) + +# C wrapper around ReadCallback() +# Declared in this scope so it doesn't get GC-ed +REGISTERED_READ_CALLBACK = IO_HID_REPORT_CALLBACK(HidReadCallback) + + +def DeviceReadThread(hid_device): + """Binds a device to the thread's run loop, then starts the run loop. + + Args: + hid_device: The MacOsHidDevice object + + The HID manager requires a run loop to handle Report reads. This thread + function serves that purpose. + """ + + # Schedule device events with run loop + hid_device.run_loop_ref = cf.CFRunLoopGetCurrent() + if not hid_device.run_loop_ref: + logger.error('Failed to get current run loop') + return + + iokit.IOHIDDeviceScheduleWithRunLoop(hid_device.device_handle, + hid_device.run_loop_ref, + K_CF_RUNLOOP_DEFAULT_MODE) + + # Run the run loop + run_loop_run_result = K_CF_RUN_LOOP_RUN_TIMED_OUT + while (run_loop_run_result == K_CF_RUN_LOOP_RUN_TIMED_OUT + or run_loop_run_result == K_CF_RUN_LOOP_RUN_HANDLED_SOURCE): + run_loop_run_result = cf.CFRunLoopRunInMode( + K_CF_RUNLOOP_DEFAULT_MODE, + 1000, # Timeout in seconds + False) # Return after source handled + + # log any unexpected run loop exit + if run_loop_run_result != K_CF_RUN_LOOP_RUN_STOPPED: + logger.error('Unexpected run loop exit code: %d', run_loop_run_result) + + # Unschedule from run loop + iokit.IOHIDDeviceUnscheduleFromRunLoop(hid_device.device_handle, + hid_device.run_loop_ref, + K_CF_RUNLOOP_DEFAULT_MODE) + + +class MacOsHidDevice(base.HidDevice): + """Implementation of HID device for MacOS. + + Uses IOKit HID Manager to interact with the device. + """ + + @staticmethod + def Enumerate(): + """See base class.""" + # Init a HID manager + hid_mgr = iokit.IOHIDManagerCreate(None, None) + if not hid_mgr: + raise errors.OsHidError('Unable to obtain HID manager reference') + iokit.IOHIDManagerSetDeviceMatching(hid_mgr, None) + + # Get devices from HID manager + device_set_ref = iokit.IOHIDManagerCopyDevices(hid_mgr) + if not device_set_ref: + raise errors.OsHidError('Failed to obtain devices from HID manager') + + num = iokit.CFSetGetCount(device_set_ref) + devices = (IO_HID_DEVICE_REF * num)() + iokit.CFSetGetValues(device_set_ref, devices) + + # Retrieve and build descriptor dictionaries for each device + descriptors = [] + for dev in devices: + d = base.DeviceDescriptor() + d.vendor_id = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_VENDOR_ID) + d.product_id = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_PRODUCT_ID) + d.product_string = GetDeviceStringProperty(dev, + HID_DEVICE_PROPERTY_PRODUCT) + d.usage = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_PRIMARY_USAGE) + d.usage_page = GetDeviceIntProperty( + dev, HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE) + d.report_id = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_REPORT_ID) + d.path = GetDevicePath(dev) + descriptors.append(d.ToPublicDict()) + + # Clean up CF objects + cf.CFRelease(device_set_ref) + cf.CFRelease(hid_mgr) + + return descriptors + + def __init__(self, path): + # Resolve the path to device handle + device_entry = iokit.IORegistryEntryFromPath(K_IO_MASTER_PORT_DEFAULT, path) + if not device_entry: + raise errors.OsHidError('Device path does not match any HID device on ' + 'the system') + + self.device_handle = iokit.IOHIDDeviceCreate(K_CF_ALLOCATOR_DEFAULT, + device_entry) + if not self.device_handle: + raise errors.OsHidError('Failed to obtain device handle from registry ' + 'entry') + iokit.IOObjectRelease(device_entry) + + self.device_path = path + + # Open device + result = iokit.IOHIDDeviceOpen(self.device_handle, 0) + if result != K_IO_RETURN_SUCCESS: + raise errors.OsHidError('Failed to open device for communication: {}' + .format(result)) + + # Create read queue + self.read_queue = Queue() + + # Create and start read thread + self.run_loop_ref = None + self.read_thread = threading.Thread(target=DeviceReadThread, + args=(self,)) + self.read_thread.daemon = True + self.read_thread.start() + + # Read max report sizes for in/out + self.internal_max_in_report_len = GetDeviceIntProperty( + self.device_handle, + HID_DEVICE_PROPERTY_MAX_INPUT_REPORT_SIZE) + if not self.internal_max_in_report_len: + raise errors.OsHidError('Unable to obtain max in report size') + + self.internal_max_out_report_len = GetDeviceIntProperty( + self.device_handle, + HID_DEVICE_PROPERTY_MAX_OUTPUT_REPORT_SIZE) + if not self.internal_max_out_report_len: + raise errors.OsHidError('Unable to obtain max out report size') + + # Register read callback + self.in_report_buffer = (ctypes.c_uint8 * self.internal_max_in_report_len)() + iokit.IOHIDDeviceRegisterInputReportCallback( + self.device_handle, + self.in_report_buffer, + self.internal_max_in_report_len, + REGISTERED_READ_CALLBACK, + ctypes.py_object(self.read_queue)) + + def GetInReportDataLength(self): + """See base class.""" + return self.internal_max_in_report_len + + def GetOutReportDataLength(self): + """See base class.""" + return self.internal_max_out_report_len + + def Write(self, packet): + """See base class.""" + report_id = 0 + out_report_buffer = (ctypes.c_uint8 * self.internal_max_out_report_len)() + out_report_buffer[:] = packet[:] + + result = iokit.IOHIDDeviceSetReport(self.device_handle, + K_IO_HID_REPORT_TYPE_OUTPUT, + report_id, + out_report_buffer, + self.internal_max_out_report_len) + + # Non-zero status indicates failure + if result != K_IO_RETURN_SUCCESS: + raise errors.OsHidError('Failed to write report to device') + + def Read(self): + """See base class.""" + return self.read_queue.get(timeout=0xffffffff) + + def __del__(self): + # Unregister the callback + iokit.IOHIDDeviceRegisterInputReportCallback( + self.device_handle, + self.in_report_buffer, + self.internal_max_in_report_len, + None, + None) + + # Stop the run loop + cf.CFRunLoopStop(self.run_loop_ref) + + # Wait for the read thread to exit + self.read_thread.join() diff --git a/fido_host/pyu2f/windows.py b/fido_host/pyu2f/windows.py new file mode 100644 index 0000000..77f6b70 --- /dev/null +++ b/fido_host/pyu2f/windows.py @@ -0,0 +1,369 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Implements raw HID device communication on Windows.""" + +from __future__ import absolute_import + +import ctypes +from ctypes import wintypes + +import platform + +from . import base, errors + + +# Load relevant DLLs +hid = ctypes.windll.Hid +setupapi = ctypes.windll.SetupAPI +kernel32 = ctypes.windll.Kernel32 + + +# Various structs that are used in the Windows APIs we call +class GUID(ctypes.Structure): + _fields_ = [('Data1', ctypes.c_ulong), + ('Data2', ctypes.c_ushort), + ('Data3', ctypes.c_ushort), + ('Data4', ctypes.c_ubyte * 8)] + +# On Windows, SetupAPI.h packs structures differently in 64bit and +# 32bit mode. In 64bit mode, thestructures are packed on 8 byte +# boundaries, while in 32bit mode, they are packed on 1 byte boundaries. +# This is important to get right for some API calls that fill out these +# structures. +if platform.architecture()[0] == '64bit': + SETUPAPI_PACK = 8 +elif platform.architecture()[0] == '32bit': + SETUPAPI_PACK = 1 +else: + raise errors.HidError('Unknown architecture: %s' % platform.architecture()[0]) + +class DeviceInterfaceData(ctypes.Structure): + _fields_ = [('cbSize', wintypes.DWORD), + ('InterfaceClassGuid', GUID), + ('Flags', wintypes.DWORD), + ('Reserved', ctypes.POINTER(ctypes.c_ulong))] + _pack_ = SETUPAPI_PACK + + +class DeviceInterfaceDetailData(ctypes.Structure): + _fields_ = [('cbSize', wintypes.DWORD), + ('DevicePath', ctypes.c_byte * 1)] + _pack_ = SETUPAPI_PACK + + +class HidAttributes(ctypes.Structure): + _fields_ = [('Size', ctypes.c_ulong), + ('VendorID', ctypes.c_ushort), + ('ProductID', ctypes.c_ushort), + ('VersionNumber', ctypes.c_ushort)] + + +class HidCapabilities(ctypes.Structure): + _fields_ = [('Usage', ctypes.c_ushort), + ('UsagePage', ctypes.c_ushort), + ('InputReportByteLength', ctypes.c_ushort), + ('OutputReportByteLength', ctypes.c_ushort), + ('FeatureReportByteLength', ctypes.c_ushort), + ('Reserved', ctypes.c_ushort * 17), + ('NotUsed', ctypes.c_ushort * 10)] + +# Various void* aliases for readability. +HDEVINFO = ctypes.c_void_p +HANDLE = ctypes.c_void_p +PHIDP_PREPARSED_DATA = ctypes.c_void_p # pylint: disable=invalid-name + +# This is a HANDLE. +INVALID_HANDLE_VALUE = 0xffffffff + +# Status codes +NTSTATUS = ctypes.c_long +HIDP_STATUS_SUCCESS = 0x00110000 +FILE_SHARE_READ = 0x00000001 +FILE_SHARE_WRITE = 0x00000002 +OPEN_EXISTING = 0x03 +ERROR_ACCESS_DENIED = 0x05 + +# CreateFile Flags +GENERIC_WRITE = 0x40000000 +GENERIC_READ = 0x80000000 + +# Function signatures +hid.HidD_GetHidGuid.restype = None +hid.HidD_GetHidGuid.argtypes = [ctypes.POINTER(GUID)] +hid.HidD_GetAttributes.restype = wintypes.BOOLEAN +hid.HidD_GetAttributes.argtypes = [HANDLE, ctypes.POINTER(HidAttributes)] +hid.HidD_GetPreparsedData.restype = wintypes.BOOLEAN +hid.HidD_GetPreparsedData.argtypes = [HANDLE, + ctypes.POINTER(PHIDP_PREPARSED_DATA)] +hid.HidD_FreePreparsedData.restype = wintypes.BOOLEAN +hid.HidD_FreePreparsedData.argtypes = [PHIDP_PREPARSED_DATA] +hid.HidD_GetProductString.restype = wintypes.BOOLEAN +hid.HidD_GetProductString.argtypes = [HANDLE, ctypes.c_void_p, ctypes.c_ulong] +hid.HidP_GetCaps.restype = NTSTATUS +hid.HidP_GetCaps.argtypes = [PHIDP_PREPARSED_DATA, + ctypes.POINTER(HidCapabilities)] + +setupapi.SetupDiGetClassDevsA.argtypes = [ctypes.POINTER(GUID), ctypes.c_char_p, + wintypes.HWND, wintypes.DWORD] +setupapi.SetupDiGetClassDevsA.restype = HDEVINFO +setupapi.SetupDiEnumDeviceInterfaces.restype = wintypes.BOOL +setupapi.SetupDiEnumDeviceInterfaces.argtypes = [ + HDEVINFO, ctypes.c_void_p, ctypes.POINTER(GUID), wintypes.DWORD, + ctypes.POINTER(DeviceInterfaceData)] +setupapi.SetupDiGetDeviceInterfaceDetailA.restype = wintypes.BOOL +setupapi.SetupDiGetDeviceInterfaceDetailA.argtypes = [ + HDEVINFO, ctypes.POINTER(DeviceInterfaceData), + ctypes.POINTER(DeviceInterfaceDetailData), wintypes.DWORD, + ctypes.POINTER(wintypes.DWORD), ctypes.c_void_p] + +kernel32.CreateFileA.restype = HANDLE +kernel32.CreateFileA.argtypes = [ + ctypes.c_char_p, wintypes.DWORD, wintypes.DWORD, ctypes.c_void_p, + wintypes.DWORD, wintypes.DWORD, HANDLE] +kernel32.CloseHandle.restype = wintypes.BOOL +kernel32.CloseHandle.argtypes = [HANDLE] +kernel32.ReadFile.restype = wintypes.BOOL +kernel32.ReadFile.argtypes = [ + HANDLE, ctypes.c_void_p, wintypes.DWORD, + ctypes.POINTER(wintypes.DWORD), ctypes.c_void_p] +kernel32.WriteFile.restype = wintypes.BOOL +kernel32.WriteFile.argtypes = [ + HANDLE, ctypes.c_void_p, wintypes.DWORD, + ctypes.POINTER(wintypes.DWORD), ctypes.c_void_p] + + +def FillDeviceAttributes(device, descriptor): + """Fill out the attributes of the device. + + Fills the devices HidAttributes and product string + into the descriptor. + + Args: + device: A handle to the open device + descriptor: The DeviceDescriptor to populate with the + attributes. + + Returns: + None + + Raises: + WindowsError when unable to obtain attributes or product + string. + """ + attributes = HidAttributes() + result = hid.HidD_GetAttributes(device, ctypes.byref(attributes)) + if not result: + raise ctypes.WinError() + + buf = ctypes.create_string_buffer(1024) + result = hid.HidD_GetProductString(device, buf, 1024) + + if not result: + raise ctypes.WinError() + + descriptor.vendor_id = attributes.VendorID + descriptor.product_id = attributes.ProductID + descriptor.product_string = ctypes.wstring_at(buf) + + +def FillDeviceCapabilities(device, descriptor): + """Fill out device capabilities. + + Fills the HidCapabilitites of the device into descriptor. + + Args: + device: A handle to the open device + descriptor: DeviceDescriptor to populate with the + capabilities + + Returns: + none + + Raises: + WindowsError when unable to obtain capabilitites. + """ + preparsed_data = PHIDP_PREPARSED_DATA(0) + ret = hid.HidD_GetPreparsedData(device, ctypes.byref(preparsed_data)) + if not ret: + raise ctypes.WinError() + + try: + caps = HidCapabilities() + ret = hid.HidP_GetCaps(preparsed_data, ctypes.byref(caps)) + + if ret != HIDP_STATUS_SUCCESS: + raise ctypes.WinError() + + descriptor.usage = caps.Usage + descriptor.usage_page = caps.UsagePage + descriptor.internal_max_in_report_len = caps.InputReportByteLength + descriptor.internal_max_out_report_len = caps.OutputReportByteLength + + finally: + hid.HidD_FreePreparsedData(preparsed_data) + + +# The python os.open() implementation uses the windows libc +# open() function, which writes CreateFile but does so in a way +# that doesn't let us open the device with the right set of permissions. +# Therefore, we have to directly use the Windows API calls. +# We could use PyWin32, which provides simple wrappers. However, to avoid +# requiring a PyWin32 dependency for clients, we simply also implement it +# using ctypes. +def OpenDevice(path, enum=False): + """Open the device and return a handle to it.""" + desired_access = GENERIC_WRITE | GENERIC_READ + share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE + if enum: + desired_access = 0 + + h = kernel32.CreateFileA(path, + desired_access, + share_mode, + None, OPEN_EXISTING, 0, None) + if h == INVALID_HANDLE_VALUE: + raise ctypes.WinError() + return h + + +class WindowsHidDevice(base.HidDevice): + """Implementation of raw HID interface on Windows.""" + + @staticmethod + def Enumerate(): + """See base class.""" + hid_guid = GUID() + hid.HidD_GetHidGuid(ctypes.byref(hid_guid)) + + devices = setupapi.SetupDiGetClassDevsA( + ctypes.byref(hid_guid), None, None, 0x12) + index = 0 + interface_info = DeviceInterfaceData() + interface_info.cbSize = ctypes.sizeof(DeviceInterfaceData) # pylint: disable=invalid-name + + out = [] + while True: + result = setupapi.SetupDiEnumDeviceInterfaces( + devices, 0, ctypes.byref(hid_guid), index, + ctypes.byref(interface_info)) + index += 1 + if not result: + break + + detail_len = wintypes.DWORD() + result = setupapi.SetupDiGetDeviceInterfaceDetailA( + devices, ctypes.byref(interface_info), None, 0, + ctypes.byref(detail_len), None) + + detail_len = detail_len.value + if detail_len == 0: + # skip this device, some kind of error + continue + + buf = ctypes.create_string_buffer(detail_len) + interface_detail = DeviceInterfaceDetailData.from_buffer(buf) + interface_detail.cbSize = ctypes.sizeof(DeviceInterfaceDetailData) + + result = setupapi.SetupDiGetDeviceInterfaceDetailA( + devices, ctypes.byref(interface_info), + ctypes.byref(interface_detail), detail_len, None, None) + + if not result: + raise ctypes.WinError() + + descriptor = base.DeviceDescriptor() + # This is a bit of a hack to work around a limitation of ctypes and + # "header" structures that are common in windows. DevicePath is a + # ctypes array of length 1, but it is backed with a buffer that is much + # longer and contains a null terminated string. So, we read the null + # terminated string off DevicePath here. Per the comment above, the + # alignment of this struct varies depending on architecture, but + # in all cases the path string starts 1 DWORD into the structure. + # + # The path length is: + # length of detail buffer - header length (1 DWORD) + path_len = detail_len - ctypes.sizeof(wintypes.DWORD) + descriptor.path = ctypes.string_at( + ctypes.addressof(interface_detail.DevicePath), path_len) + + device = None + try: + device = OpenDevice(descriptor.path, True) + except WindowsError as e: # pylint: disable=undefined-variable + if e.winerror == ERROR_ACCESS_DENIED: # Access Denied, e.g. a keyboard + continue + else: + raise e + + try: + FillDeviceAttributes(device, descriptor) + FillDeviceCapabilities(device, descriptor) + out.append(descriptor.ToPublicDict()) + except Exception: + continue # Try with next device + finally: + kernel32.CloseHandle(device) + + return out + + def __init__(self, path): + """See base class.""" + base.HidDevice.__init__(self, path) + self.dev = OpenDevice(path) + self.desc = base.DeviceDescriptor() + FillDeviceCapabilities(self.dev, self.desc) + + def GetInReportDataLength(self): + """See base class.""" + return self.desc.internal_max_in_report_len - 1 + + def GetOutReportDataLength(self): + """See base class.""" + return self.desc.internal_max_out_report_len - 1 + + def Write(self, packet): + """See base class.""" + if len(packet) != self.GetOutReportDataLength(): + raise errors.HidError('Packet length must match report data length.') + + out = bytes(bytearray([0] + packet)) # Prepend the zero-byte (report ID) + num_written = wintypes.DWORD() + ret = ( + kernel32.WriteFile( + self.dev, out, len(out), + ctypes.byref(num_written), None)) + if num_written.value != len(out): + raise errors.HidError( + 'Failed to write complete packet. ' + 'Expected %d, but got %d' % + (len(out), num_written.value)) + if not ret: + raise ctypes.WinError() + + def Read(self): + """See base class.""" + buf = ctypes.create_string_buffer(self.desc.internal_max_in_report_len) + num_read = wintypes.DWORD() + ret = kernel32.ReadFile( + self.dev, buf, len(buf), ctypes.byref(num_read), None) + + if num_read.value != self.desc.internal_max_in_report_len: + raise errors.HidError('Failed to read full length report from device.') + + if not ret: + raise ctypes.WinError() + + # Convert the string buffer to a list of numbers. Throw away the first + # byte, which is the report id (which we don't care about). + return b''.join(buf)[1:] diff --git a/fido_host/rpid.py b/fido_host/rpid.py new file mode 100644 index 0000000..2b248d6 --- /dev/null +++ b/fido_host/rpid.py @@ -0,0 +1,69 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +""" +These functions validate RP_ID and APP_ID according to simplified TLD+1 rules, +using a bundled copy of the public suffix list fetched from: + + https://publicsuffix.org/list/public_suffix_list.dat + +Advanced APP_ID values pointing to JSON files containing valid facets are not +supported by this implementation. +""" + +import os +import six +from six.moves.urllib.parse import urlparse + + +tld_fname = os.path.join(os.path.dirname(__file__), 'public_suffix_list.dat') +with open(tld_fname, 'rb') as f: + suffixes = [entry for entry in (line.decode('utf8').strip() + for line in f.readlines()) + if entry and not entry.startswith('//')] + + +def verify_rp_id(rp_id, origin): + if not isinstance(rp_id, six.string_types) or not rp_id: + return False + + url = urlparse(origin) + if url.scheme != 'https': + return False + host = url.hostname + if host == rp_id: + return True + if host.endswith('.' + rp_id) and rp_id not in suffixes: + return True + return False + + +def verify_app_id(app_id, origin): + url = urlparse(app_id) + if url.scheme != 'https': + return False + return verify_rp_id(url.hostname, origin) diff --git a/fido_host/u2f.py b/fido_host/u2f.py new file mode 100644 index 0000000..2bc6f8e --- /dev/null +++ b/fido_host/u2f.py @@ -0,0 +1,151 @@ +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from __future__ import absolute_import + +from .hid import CTAPHID +from .utils import websafe_encode +from enum import IntEnum, unique +from binascii import b2a_hex +import struct +import six + + +@unique +class APDU(IntEnum): + OK = 0x9000 + USE_NOT_SATISFIED = 0x6985 + WRONG_DATA = 0x6a80 + + +class ApduError(Exception): + + def __init__(self, code, data=b''): + self.code = code + self.data = data + + def __repr__(self): + return 'APDU error: 0x{:04X} {:d} bytes of data'.format( + self.code, len(self.data)) + + +class RegistrationData(bytes): + def __init__(self, _): + if six.indexbytes(self, 0) != 0x05: + raise ValueError('Reserved byte != 0x05') + + self.public_key = self[1:66] + kh_len = six.indexbytes(self, 66) + self.key_handle = self[67:67+kh_len] + + cert_offs = 67 + kh_len + cert_len = six.indexbytes(self, cert_offs + 1) + if cert_len > 0x80: + n_bytes = cert_len - 0x80 + cert_len = int(b2a_hex(self[cert_offs+2:cert_offs+2+n_bytes]), 16) \ + + n_bytes + cert_len += 2 + self.certificate = self[cert_offs:cert_offs+cert_len] + self.signature = self[cert_offs+cert_len:] + + @property + def b64(self): + return websafe_encode(self) + + def __repr__(self): + return ("RegistrationData(public_key: h'%s', key_handle: h'%s', " + "certificate: h'%s', signature: h'%s')") % ( + b2a_hex(x).decode() for x in ( + self.public_key, + self.key_handle, + self.certificate, + self.signature + ) + ) + + def __str__(self): + return '%r' % self + + +class SignatureData(bytes): + def __init__(self, _): + self.user_presence, self.counter = struct.unpack('>BI', self[:5]) + self.signature = self[5:] + + @property + def b64(self): + return websafe_encode(self) + + def __repr__(self): + return ('SignatureData(user_presence: 0x%02x, counter: %d, ' + "signature: h'%s'") % (self.user_presence, self.counter, + b2a_hex(self.signature)) + + def __str__(self): + return '%r' % self + + +class CTAP1(object): + + @unique + class INS(IntEnum): + REGISTER = 0x01 + AUTHENTICATE = 0x02 + VERSION = 0x03 + + def __init__(self, device): + self.device = device + + def send_apdu(self, cla=0, ins=0, p1=0, p2=0, data=b''): + size = len(data) + size_h = size >> 16 & 0xff + size_l = size & 0xffff + apdu = struct.pack('>BBBBBH', cla, ins, p1, p2, size_h, size_l) \ + + data + b'\0\0' + + response = self.device.call(CTAPHID.MSG, apdu) + status = struct.unpack('>H', response[-2:])[0] + data = response[:-2] + if status != APDU.OK: + raise ApduError(status, data) + return data + + def get_version(self): + return self.send_apdu(ins=CTAP1.INS.VERSION).decode() + + def register(self, client_param, app_param): + data = client_param + app_param + response = self.send_apdu(ins=CTAP1.INS.REGISTER, data=data) + return RegistrationData(response) + + def authenticate(self, client_param, app_param, key_handle, + check_only=False): + data = client_param + app_param \ + + struct.pack('>B', len(key_handle)) + key_handle + p1 = 0x07 if check_only else 0x03 + response = self.send_apdu(ins=CTAP1.INS.AUTHENTICATE, p1=p1, data=data) + return SignatureData(response) diff --git a/fido_host/utils.py b/fido_host/utils.py new file mode 100644 index 0000000..a571edc --- /dev/null +++ b/fido_host/utils.py @@ -0,0 +1,86 @@ +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from base64 import urlsafe_b64decode, urlsafe_b64encode +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hmac, hashes +from threading import Timer, Event +import six +import numbers + +__all__ = [ + 'Timeout', + 'websafe_encode', + 'websafe_decode', + 'sha256', + 'hmac_sha256' +] + + +def sha256(data): + h = hashes.Hash(hashes.SHA256(), default_backend()) + h.update(data) + return h.finalize() + + +def hmac_sha256(key, data): + h = hmac.HMAC(key, hashes.SHA256(), default_backend()) + h.update(data) + return h.finalize() + + +def websafe_decode(data): + if isinstance(data, six.text_type): + data = data.encode('ascii') + data += b'=' * (-len(data) % 4) + return urlsafe_b64decode(data) + + +def websafe_encode(data): + if isinstance(data, six.text_type): + data = data.encode('ascii') + return urlsafe_b64encode(data).replace(b'=', b'').decode('ascii') + + +class Timeout(object): + def __init__(self, time_or_event): + if isinstance(time_or_event, numbers.Number): + self.event = Event() + self.timer = Timer(time_or_event, self.event.set) + else: + self.event = time_or_event + self.timer = None + + def __enter__(self): + if self.timer: + self.timer.start() + return self.event + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.timer: + self.timer.cancel() + self.timer.join() diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..15fc7e3 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 80 diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..902f10c --- /dev/null +++ b/setup.py @@ -0,0 +1,79 @@ +# Copyright (c) 2018 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from setuptools import setup, find_packages +import re +import sys + + +VERSION_PATTERN = re.compile(r"(?m)^__version__\s*=\s*['\"](.+)['\"]$") + + +def get_version(): + with open('fido_host/__init__.py', 'r') as f: + match = VERSION_PATTERN.search(f.read()) + return match.group(1) + + +install_requires = ['six', 'cryptography>=1.0'] +if sys.version_info < (3, 4): + install_requires.append('enum34') + +setup( + name='fido-host', + version=get_version(), + packages=find_packages(), + include_package_data=True, + author='Dain Nilsson', + author_email='dain@yubico.com', + description='Python based FIDO host library', + url='https://github.com/Yubico/python-fido-host', + install_requires=install_requires, + test_suite='test', + tests_require=['mock>=1.0.1', 'pyfakefs>=2.4'], + classifiers=[ + 'License :: OSI Approved :: BSD License', + 'License :: OSI Approved :: Apache Software License', + 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', + 'Operating System :: MacOS', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Topic :: Internet', + 'Topic :: Security :: Cryptography', + 'Topic :: Software Development :: Libraries :: Python Modules', + ] +) diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/pyu2f/__init__.py b/test/pyu2f/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/pyu2f/hidtransport_test.py b/test/pyu2f/hidtransport_test.py new file mode 100644 index 0000000..17adca8 --- /dev/null +++ b/test/pyu2f/hidtransport_test.py @@ -0,0 +1,183 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Tests for pyu2f.hidtransport.""" + +from __future__ import absolute_import + +import six +import mock + +from fido_host.pyu2f import hidtransport, errors +from . import util + +import unittest + + +def MakeKeyboard(path, usage): + d = {} + d['vendor_id'] = 1133 # Logitech + d['product_id'] = 49948 + d['path'] = path + d['usage'] = usage + d['usage_page'] = 1 + return d + + +def MakeU2F(path): + d = {} + d['vendor_id'] = 4176 + d['product_id'] = 1031 + d['path'] = path + d['usage'] = 1 + d['usage_page'] = 0xf1d0 + return d + + +def RPad(collection, to_size): + while len(collection) < to_size: + collection.append(0) + return collection + + +class DiscoveryTest(unittest.TestCase): + + def testHidUsageSelector(self): + u2f_device = {'usage_page': 0xf1d0, 'usage': 0x01} + other_device = {'usage_page': 0x06, 'usage': 0x01} + self.assertTrue(hidtransport.HidUsageSelector(u2f_device)) + self.assertFalse(hidtransport.HidUsageSelector(other_device)) + + def testDiscoverLocalDevices(self): + + def FakeHidDevice(path): + mock_hid_dev = mock.MagicMock() + mock_hid_dev.GetInReportDataLength.return_value = 64 + mock_hid_dev.GetOutReportDataLength.return_value = 64 + mock_hid_dev.path = path + return mock_hid_dev + + with mock.patch.object(hidtransport, 'hid') as hid_mock: + # We mock out init so that it doesn't try to do the whole init + # handshake with the device, which isn't what we're trying to test + # here. + with mock.patch.object(hidtransport.UsbHidTransport, 'InternalInit') as _: + hid_mock.Enumerate.return_value = [ + MakeKeyboard('path1', 6), MakeKeyboard('path2', 2), + MakeU2F('path3'), MakeU2F('path4') + ] + mock_hid_dev = mock.MagicMock() + mock_hid_dev.GetInReportDataLength.return_value = 64 + mock_hid_dev.GetOutReportDataLength.return_value = 64 + hid_mock.Open.side_effect = FakeHidDevice + + # Force the iterator into a list + devs = list(hidtransport.DiscoverLocalHIDU2FDevices()) + + self.assertEqual(hid_mock.Enumerate.call_count, 1) + self.assertEqual(hid_mock.Open.call_count, 2) + self.assertEqual(len(devs), 2) + + self.assertEqual(devs[0].hid_device.path, 'path3') + self.assertEqual(devs[1].hid_device.path, 'path4') + + +class TransportTest(unittest.TestCase): + + def testInit(self): + fake_hid_dev = util.FakeHidDevice(bytearray([0x00, 0x00, 0x00, 0x01])) + t = hidtransport.UsbHidTransport(fake_hid_dev) + self.assertEqual(t.cid, bytearray([0x00, 0x00, 0x00, 0x01])) + self.assertEqual(t.u2fhid_version, 0x01) + + def testPing(self): + fake_hid_dev = util.FakeHidDevice(bytearray([0x00, 0x00, 0x00, 0x01])) + t = hidtransport.UsbHidTransport(fake_hid_dev) + + reply = t.SendPing(b'1234') + self.assertEqual(reply, b'1234') + + def testMsg(self): + fake_hid_dev = util.FakeHidDevice( + bytearray([0x00, 0x00, 0x00, 0x01]), bytearray([0x01, 0x90, 0x00])) + t = hidtransport.UsbHidTransport(fake_hid_dev) + + reply = t.SendMsgBytes([0x00, 0x01, 0x00, 0x00]) + self.assertEqual(reply, bytearray([0x01, 0x90, 0x00])) + + def testMsgBusy(self): + fake_hid_dev = util.FakeHidDevice( + bytearray([0x00, 0x00, 0x00, 0x01]), bytearray([0x01, 0x90, 0x00])) + t = hidtransport.UsbHidTransport(fake_hid_dev) + + # Each call will retry twice: the first attempt will fail after 2 retreis, + # the second will succeed on the second retry. + fake_hid_dev.SetChannelBusyCount(3) + with mock.patch.object(hidtransport, 'time') as _: + six.assertRaisesRegex(self, errors.HidError, '^Device Busy', t.SendMsgBytes, + [0x00, 0x01, 0x00, 0x00]) + + reply = t.SendMsgBytes([0x00, 0x01, 0x00, 0x00]) + self.assertEqual(reply, bytearray([0x01, 0x90, 0x00])) + + def testFragmentedResponseMsg(self): + body = bytearray([x % 256 for x in range(0, 1000)]) + fake_hid_dev = util.FakeHidDevice(bytearray([0x00, 0x00, 0x00, 0x01]), body) + t = hidtransport.UsbHidTransport(fake_hid_dev) + + reply = t.SendMsgBytes([0x00, 0x01, 0x00, 0x00]) + # Confirm we properly reassemble the message + self.assertEqual(reply, bytearray(x % 256 for x in range(0, 1000))) + + def testFragmentedSendApdu(self): + body = bytearray(x % 256 for x in range(0, 1000)) + fake_hid_dev = util.FakeHidDevice( + bytearray([0x00, 0x00, 0x00, 0x01]), [0x90, 0x00]) + t = hidtransport.UsbHidTransport(fake_hid_dev) + + reply = t.SendMsgBytes(body) + self.assertEqual(reply, bytearray([0x90, 0x00])) + # 1 init packet from creating transport, 18 packets to send + # the fragmented message + self.assertEqual(len(fake_hid_dev.received_packets), 18) + + def testInitPacketShape(self): + packet = hidtransport.UsbHidTransport.InitPacket( + 64, bytearray(b'\x00\x00\x00\x01'), 0x83, 2, bytearray(b'\x01\x02')) + + self.assertEqual(packet.ToWireFormat(), RPad( + [0, 0, 0, 1, 0x83, 0, 2, 1, 2], 64)) + + copy = hidtransport.UsbHidTransport.InitPacket.FromWireFormat( + 64, packet.ToWireFormat()) + self.assertEqual(copy.cid, bytearray(b'\x00\x00\x00\x01')) + self.assertEqual(copy.cmd, 0x83) + self.assertEqual(copy.size, 2) + self.assertEqual(copy.payload, bytearray(b'\x01\x02')) + + def testContPacketShape(self): + packet = hidtransport.UsbHidTransport.ContPacket( + 64, bytearray(b'\x00\x00\x00\x01'), 5, bytearray(b'\x01\x02')) + + self.assertEqual(packet.ToWireFormat(), RPad([0, 0, 0, 1, 5, 1, 2], 64)) + + copy = hidtransport.UsbHidTransport.ContPacket.FromWireFormat( + 64, packet.ToWireFormat()) + self.assertEqual(copy.cid, bytearray(b'\x00\x00\x00\x01')) + self.assertEqual(copy.seq, 5) + self.assertEqual(copy.payload, RPad(bytearray(b'\x01\x02'), 59)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/pyu2f/linux_test.py b/test/pyu2f/linux_test.py new file mode 100644 index 0000000..8aa33e3 --- /dev/null +++ b/test/pyu2f/linux_test.py @@ -0,0 +1,124 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Tests for pyu2f.hid.linux.""" + +import base64 +import os +import sys + +import mock + +import six +from six.moves import builtins +from fido_host.pyu2f import linux + +try: + from pyfakefs import fake_filesystem # pylint: disable=g-import-not-at-top +except ImportError: + from fakefs import fake_filesystem # pylint: disable=g-import-not-at-top + +if sys.version_info[:2] < (2, 7): + import unittest2 as unittest # pylint: disable=g-import-not-at-top +else: + import unittest # pylint: disable=g-import-not-at-top + + +# These are base64 encoded report descriptors of a Yubico token +# and a Logitech keyboard. +YUBICO_RD = 'BtDxCQGhAQkgFQAm/wB1CJVAgQIJIRUAJv8AdQiVQJECwA==' +KEYBOARD_RD = ( + 'BQEJAqEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVAXUDgQEFAQkwCTEJOBWBJX91CJUDgQbAwA==') + + +def AddDevice(fs, dev_name, product_name, + vendor_id, product_id, report_descriptor_b64): + uevent = fs.CreateFile('/sys/class/hidraw/%s/device/uevent' % dev_name) + rd = fs.CreateFile('/sys/class/hidraw/%s/device/report_descriptor' % dev_name) + report_descriptor = base64.b64decode(report_descriptor_b64) + rd.SetContents(report_descriptor) + + buf = 'HID_NAME=%s\n' % product_name.encode('utf8') + buf += 'HID_ID=0001:%08X:%08X\n' % (vendor_id, product_id) + uevent.SetContents(buf) + + +class FakeDeviceOsModule(object): + O_RDWR = os.O_RDWR + path = os.path + + data_written = None + data_to_return = None + + def open(self, unused_path, unused_opts): # pylint: disable=invalid-name + return 0 + + def write(self, unused_dev, data): # pylint: disable=invalid-name + self.data_written = data + + def read(self, unused_dev, unused_length): # pylint: disable=invalid-name + return self.data_to_return + + +class LinuxTest(unittest.TestCase): + def setUp(self): + self.fs = fake_filesystem.FakeFilesystem() + self.fs.CreateDirectory('/sys/class/hidraw') + + def tearDown(self): + self.fs.RemoveObject('/sys/class/hidraw') + + def testCallEnumerate(self): + AddDevice(self.fs, 'hidraw1', 'Logitech USB Keyboard', + 0x046d, 0xc31c, KEYBOARD_RD) + AddDevice(self.fs, 'hidraw2', 'Yubico U2F', 0x1050, 0x0407, YUBICO_RD) + with mock.patch.object(linux, 'os', fake_filesystem.FakeOsModule(self.fs)): + fake_open = fake_filesystem.FakeFileOpen(self.fs) + with mock.patch.object(builtins, 'open', fake_open): + devs = list(linux.LinuxHidDevice.Enumerate()) + devs = sorted(devs, key=lambda k: k['vendor_id']) + + self.assertEqual(len(devs), 2) + self.assertEqual(devs[0]['vendor_id'], 0x046d) + self.assertEqual(devs[0]['product_id'], 0x0c31c) + self.assertEqual(devs[1]['vendor_id'], 0x1050) + self.assertEqual(devs[1]['product_id'], 0x0407) + self.assertEqual(devs[1]['usage_page'], 0xf1d0) + self.assertEqual(devs[1]['usage'], 1) + + def testCallOpen(self): + AddDevice(self.fs, 'hidraw1', 'Yubico U2F', 0x1050, 0x0407, YUBICO_RD) + fake_open = fake_filesystem.FakeFileOpen(self.fs) + # The open() builtin is used to read from the fake sysfs + with mock.patch.object(builtins, 'open', fake_open): + # The os.open function is used to interact with the low + # level device. We don't want to use fakefs for that. + fake_dev_os = FakeDeviceOsModule() + with mock.patch.object(linux, 'os', fake_dev_os): + dev = linux.LinuxHidDevice('/dev/hidraw1') + self.assertEqual(dev.GetInReportDataLength(), 64) + self.assertEqual(dev.GetOutReportDataLength(), 64) + + dev.Write(list(range(0, 64))) + # The HidDevice implementation prepends a zero-byte representing the + # report ID + self.assertEqual(list(six.iterbytes(fake_dev_os.data_written)), + [0] + list(range(0, 64))) + + fake_dev_os.data_to_return = b'x' * 64 + self.assertEqual(dev.Read(), [120] * 64) # chr(120) = 'x' + + +if __name__ == '__main__': + unittest.main() diff --git a/test/pyu2f/macos_test.py b/test/pyu2f/macos_test.py new file mode 100644 index 0000000..ba59aab --- /dev/null +++ b/test/pyu2f/macos_test.py @@ -0,0 +1,142 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Tests for pyu2f.hid.macos.""" + +import ctypes +import sys +import mock + +from fido_host.pyu2f import macos, errors + + +if sys.version_info[:2] < (2, 7): + import unittest2 as unittest # pylint: disable=g-import-not-at-top +else: + import unittest # pylint: disable=g-import-not-at-top + + +def init_mock_iokit(mock_iokit): + # Device open should always return 0 (success) + mock_iokit.IOHIDDeviceOpen = mock.Mock(return_value=0) + mock_iokit.IOHIDDeviceSetReport = mock.Mock(return_value=0) + mock_iokit.IOHIDDeviceCreate = mock.Mock(return_value='handle') + + +def init_mock_cf(mock_cf): + mock_cf.CFGetTypeID = mock.Mock(return_value=123) + mock_cf.CFNumberGetTypeID = mock.Mock(return_value=123) + mock_cf.CFStringGetTypeID = mock.Mock(return_value=123) + + +def init_mock_get_int_property(mock_get_int_property): + mock_get_int_property.return_value = 64 + + +class MacOsTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + macos.MacOsHidDevice.__del__ = lambda x: None + + @mock.patch.object(macos.threading, 'Thread') + @mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT, + GetDeviceIntProperty=mock.DEFAULT) + def testInitHidDevice(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name + init_mock_iokit(iokit) + init_mock_cf(cf) + init_mock_get_int_property(GetDeviceIntProperty) + + device = macos.MacOsHidDevice('fakepath') + + self.assertEqual(64, device.GetInReportDataLength()) + self.assertEqual(64, device.GetOutReportDataLength()) + + @mock.patch.object(macos.threading, 'Thread') + @mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT, + GetDeviceIntProperty=mock.DEFAULT) + def testCallWriteSuccess(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name + init_mock_iokit(iokit) + init_mock_cf(cf) + init_mock_get_int_property(GetDeviceIntProperty) + + device = macos.MacOsHidDevice('fakepath') + + # Write 64 bytes to device + data = bytearray(range(64)) + + # Write to device + device.Write(data) + + # Validate that write calls into IOKit + set_report_call_args = iokit.IOHIDDeviceSetReport.call_args + self.assertIsNotNone(set_report_call_args) + + set_report_call_pos_args = iokit.IOHIDDeviceSetReport.call_args[0] + self.assertEqual(len(set_report_call_pos_args), 5) + self.assertEqual(set_report_call_pos_args[0], 'handle') + self.assertEqual(set_report_call_pos_args[1], 1) + self.assertEqual(set_report_call_pos_args[2], 0) + self.assertEqual(set_report_call_pos_args[4], 64) + + report_buffer = set_report_call_pos_args[3] + self.assertEqual(len(report_buffer), 64) + self.assertEqual(bytearray(report_buffer), data, 'Data sent to ' + 'IOHIDDeviceSetReport should match data sent to the ' + 'device') + + @mock.patch.object(macos.threading, 'Thread') + @mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT, + GetDeviceIntProperty=mock.DEFAULT) + def testCallWriteFailure(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name + init_mock_iokit(iokit) + init_mock_cf(cf) + init_mock_get_int_property(GetDeviceIntProperty) + + # Make set report call return failure (non-zero) + iokit.IOHIDDeviceSetReport.return_value = -1 + + device = macos.MacOsHidDevice('fakepath') + + # Write 64 bytes to device + data = bytearray(range(64)) + + # Write should throw an OsHidError exception + with self.assertRaises(errors.OsHidError): + device.Write(data) + + @mock.patch.object(macos.threading, 'Thread') + @mock.patch.multiple(macos, iokit=mock.DEFAULT, cf=mock.DEFAULT, + GetDeviceIntProperty=mock.DEFAULT) + def testCallReadSuccess(self, thread, iokit, cf, GetDeviceIntProperty): # pylint: disable=invalid-name + init_mock_iokit(iokit) + init_mock_cf(cf) + init_mock_get_int_property(GetDeviceIntProperty) + + device = macos.MacOsHidDevice('fakepath') + + # Call callback for IN report + report = (ctypes.c_uint8 * 64)() + report[:] = range(64)[:] + q = device.read_queue + macos.HidReadCallback(q, None, None, None, 0, report, 64) + + # Device read should return the callback data + read_result = device.Read() + self.assertEqual(read_result, list(range(64)), 'Read data should match data ' + 'passed into the callback') + + +if __name__ == '__main__': + unittest.main() diff --git a/test/pyu2f/util.py b/test/pyu2f/util.py new file mode 100644 index 0000000..2edc0c5 --- /dev/null +++ b/test/pyu2f/util.py @@ -0,0 +1,149 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Testing utilties for pyu2f. + +Testing utilities such as a fake implementation of the pyhidapi device object +that implements parts of the U2FHID frame protocol. This makes it easy to tests +of higher level abstractions without having to use mock to mock out low level +framing details. +""" +from fido_host.pyu2f import base, hidtransport + + +class UnsupportedCommandError(Exception): + pass + + +class FakeHidDevice(base.HidDevice): + """Implements a fake hiddevice per the pyhidapi interface. + + This class implemetns a fake hiddevice that can be patched into + code that uses pyhidapi to communicate with a hiddevice. This device + impelents part of U2FHID protocol and can be used to test interactions + with a security key. It supports arbitrary MSG replies as well as + channel allocation, and ping. + """ + + def __init__(self, cid_to_allocate, msg_reply=None): + self.cid_to_allocate = cid_to_allocate + self.msg_reply = msg_reply + self.transaction_active = False + self.full_packet_received = False + self.init_packet = None + self.packet_body = None + self.reply = None + self.seq = 0 + self.received_packets = [] + self.busy_count = 0 + + def GetInReportDataLength(self): + return 64 + + def GetOutReportDataLength(self): + return 64 + + def Write(self, data): + """Write to the device. + + Writes to the fake hid device. This function is stateful: if a transaction + is currently open with the client, it will continue to accumulate data + for the client->device messages until the expected size is reached. + + Args: + data: A list of integers to accept as data payload. It should be 64 bytes + in length: just the report data--NO report ID. + """ + + if len(data) < 64: + data = bytearray(data) + bytearray(0 for i in range(0, 64 - len(data))) + + if not self.transaction_active: + self.transaction_active = True + self.init_packet = hidtransport.UsbHidTransport.InitPacket.FromWireFormat( + 64, data) + self.packet_body = self.init_packet.payload + self.full_packet_received = False + self.received_packets.append(self.init_packet) + else: + cont_packet = hidtransport.UsbHidTransport.ContPacket.FromWireFormat( + 64, data) + self.packet_body += cont_packet.payload + self.received_packets.append(cont_packet) + + if len(self.packet_body) >= self.init_packet.size: + self.packet_body = self.packet_body[0:self.init_packet.size] + self.full_packet_received = True + + def Read(self): + """Read from the device. + + Reads from the fake hid device. This function only works if a transaction + is open and a complete write has taken place. If so, it will return the + next reply packet. It should be called repeatedly until all expected + data has been received. It always reads one report. + + Returns: + A list of ints containing the next packet. + + Raises: + UnsupportedCommandError: if the requested amount is not 64. + """ + if not self.transaction_active or not self.full_packet_received: + return None + + ret = None + if self.busy_count > 0: + ret = hidtransport.UsbHidTransport.InitPacket( + 64, self.init_packet.cid, hidtransport.UsbHidTransport.U2FHID_ERROR, + 1, hidtransport.UsbHidTransport.ERR_CHANNEL_BUSY) + self.busy_count -= 1 + elif self.reply: # reply in progress + next_frame = self.reply[0:59] + self.reply = self.reply[59:] + + ret = hidtransport.UsbHidTransport.ContPacket(64, self.init_packet.cid, + self.seq, next_frame) + self.seq += 1 + else: + self.InternalGenerateReply() + first_frame = self.reply[0:57] + + ret = hidtransport.UsbHidTransport.InitPacket( + 64, self.init_packet.cid, self.init_packet.cmd, len(self.reply), + first_frame) + self.reply = self.reply[57:] + + if not self.reply: # done after this packet + self.reply = None + self.transaction_active = False + self.seq = 0 + + return ret.ToWireFormat() + + def SetChannelBusyCount(self, busy_count): # pylint: disable=invalid-name + """Mark the channel busy for next busy_count read calls.""" + self.busy_count = busy_count + + def InternalGenerateReply(self): # pylint: disable=invalid-name + if self.init_packet.cmd == hidtransport.UsbHidTransport.U2FHID_INIT: + nonce = self.init_packet.payload[0:8] + self.reply = nonce + self.cid_to_allocate + bytearray( + b'\x01\x00\x00\x00\x00') + elif self.init_packet.cmd == hidtransport.UsbHidTransport.U2FHID_PING: + self.reply = self.init_packet.payload + elif self.init_packet.cmd == hidtransport.UsbHidTransport.U2FHID_MSG: + self.reply = self.msg_reply + else: + raise UnsupportedCommandError() diff --git a/test/pyu2f/util_test.py b/test/pyu2f/util_test.py new file mode 100644 index 0000000..93cc0cf --- /dev/null +++ b/test/pyu2f/util_test.py @@ -0,0 +1,65 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +"""Tests for pyu2f.tests.lib.util.""" + +from __future__ import absolute_import + +import sys + +from . import util + +if sys.version_info[:2] < (2, 7): + import unittest2 as unittest # pylint: disable=g-import-not-at-top +else: + import unittest # pylint: disable=g-import-not-at-top + + +class UtilTest(unittest.TestCase): + + def testSimplePing(self): + dev = util.FakeHidDevice(cid_to_allocate=None) + dev.Write([0, 0, 0, 1, 0x81, 0, 3, 1, 2, 3]) + self.assertEqual( + dev.Read(), [0, 0, 0, 1, 0x81, 0, 3, 1, 2, 3] + [0 + for _ in range(54)]) + + def testErrorBusy(self): + dev = util.FakeHidDevice(cid_to_allocate=None) + dev.SetChannelBusyCount(2) + dev.Write([0, 0, 0, 1, 0x81, 0, 3, 1, 2, 3]) + self.assertEqual( + dev.Read(), [0, 0, 0, 1, 0xbf, 0, 1, 6] + [0 for _ in range(56)]) + dev.Write([0, 0, 0, 1, 0x81, 0, 3, 1, 2, 3]) + self.assertEqual( + dev.Read(), [0, 0, 0, 1, 0xbf, 0, 1, 6] + [0 for _ in range(56)]) + dev.Write([0, 0, 0, 1, 0x81, 0, 3, 1, 2, 3]) + self.assertEqual( + dev.Read(), [0, 0, 0, 1, 0x81, 0, 3, 1, 2, 3] + [0 + for _ in range(54)]) + + def testFragmentedApdu(self): + dev = util.FakeHidDevice(cid_to_allocate=None, msg_reply=range(85, 0, -1)) + dev.Write([0, 0, 0, 1, 0x83, 0, 100] + [x for x in range(57)]) + dev.Write([0, 0, 0, 1, 0] + [x for x in range(57, 100)]) + self.assertEqual( + dev.Read(), [0, 0, 0, 1, 0x83, 0, 85] + [x for x in range(85, 28, -1)]) + self.assertEqual( + dev.Read(), + [0, 0, 0, 1, 0] + [x for x in range(28, 0, -1)] + [0 + for _ in range(31)]) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_cbor.py b/test/test_cbor.py new file mode 100644 index 0000000..ebbeecd --- /dev/null +++ b/test/test_cbor.py @@ -0,0 +1,200 @@ +# coding=utf-8 + +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +from __future__ import unicode_literals + +from fido_host import cbor +from binascii import a2b_hex, b2a_hex +import unittest + + +_TEST_VECTORS = [ + ('00', 0), + ('01', 1), + ('0a', 10), + ('17', 23), + ('1818', 24), + ('1819', 25), + ('1864', 100), + ('1903e8', 1000), + ('1a000f4240', 1000000), + ('1b000000e8d4a51000', 1000000000000), + ('1bffffffffffffffff', 18446744073709551615), + # ('c249010000000000000000', 18446744073709551616), + ('3bffffffffffffffff', -18446744073709551616), + # ('c349010000000000000000', -18446744073709551617), + ('20', -1), + ('29', -10), + ('3863', -100), + ('3903e7', -1000), + # ('f90000', 0.0), + # ('f98000', -0.0), + # ('f93c00', 1.0), + # ('fb3ff199999999999a', 1.1), + # ('f93e00', 1.5), + # ('f97bff', 65504.0), + # ('fa47c35000', 100000.0), + # ('fa7f7fffff', 3.4028234663852886e+38), + # ('fb7e37e43c8800759c', 1e+300), + # ('f90001', 5.960464477539063e-08), + # ('f90400', 6.103515625e-05), + # ('f9c400', -4.0), + # ('fbc010666666666666', -4.1), + # ('f97c00', None), + # ('f97e00', None), + # ('f9fc00', None), + # ('fa7f800000', None), + # ('fa7fc00000', None), + # ('faff800000', None), + # ('fb7ff0000000000000', None), + # ('fb7ff8000000000000', None), + # ('fbfff0000000000000', None), + ('f4', False), + ('f5', True), + # ('f6', None), + # ('f7', None), + # ('f0', None), + # ('f818', None), + # ('f8ff', None), + # ('c074323031332d30332d32315432303a30343a30305a', None), + # ('c11a514b67b0', None), + # ('c1fb41d452d9ec200000', None), + # ('d74401020304', None), + # ('d818456449455446', None), + # ('d82076687474703a2f2f7777772e6578616d706c652e636f6d', None), + ('40', b''), + ('4401020304', b'\1\2\3\4'), + ('60', ''), + ('6161', 'a'), + ('6449455446', 'IETF'), + ('62225c', '"\\'), + ('62c3bc', 'ü'), + ('63e6b0b4', '水'), + ('64f0908591', '𐅑'), + ('80', []), + ('83010203', [1, 2, 3]), + ('8301820203820405', [1, [2, 3], [4, 5]]), + ('98190102030405060708090a0b0c0d0e0f101112131415161718181819', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]), # noqa + ('a0', {}), + ('a201020304', {1: 2, 3: 4}), + ('a26161016162820203', {'a': 1, 'b': [2, 3]}), + ('826161a161626163', ['a', {'b': 'c'}]), + ('a56161614161626142616361436164614461656145', {'c': 'C', 'd': 'D', 'a': 'A', 'b': 'B', 'e': 'E'}), # noqa + # ('5f42010243030405ff', None), + # ('7f657374726561646d696e67ff', 'streaming'), + # ('9fff', []), + # ('9f018202039f0405ffff', [1, [2, 3], [4, 5]]), + # ('9f01820203820405ff', [1, [2, 3], [4, 5]]), + # ('83018202039f0405ff', [1, [2, 3], [4, 5]]), + # ('83019f0203ff820405', [1, [2, 3], [4, 5]]), + # ('9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]), # noqa + # ('bf61610161629f0203ffff', {'a': 1, 'b': [2, 3]}), + # ('826161bf61626163ff', ['a', {'b': 'c'}]), + # ('bf6346756ef563416d7421ff', {'Amt': -2, 'Fun': True}), +] + + +def cbor2hex(data): + return b2a_hex(cbor.dumps(data)).decode() + + +class TestCborTestVectors(unittest.TestCase): + """ + From https://github.com/cbor/test-vectors + Unsupported values are commented out. + """ + + def test_vectors(self): + for (data, value) in _TEST_VECTORS: + try: + self.assertEqual(cbor.loads(a2b_hex(data)), (value, b'')) + self.assertEqual(cbor2hex(value), data) + except Exception: + print('\nERROR in test vector, %s' % data) + raise + + +class TestFidoCanonical(unittest.TestCase): + """ + As defined in section 6 of: + https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html + """ + + def test_integers(self): + self.assertEqual(cbor2hex(0), '00') + self.assertEqual(cbor2hex(0), '00') + self.assertEqual(cbor2hex(23), '17') + self.assertEqual(cbor2hex(24), '1818') + self.assertEqual(cbor2hex(255), '18ff') + self.assertEqual(cbor2hex(256), '190100') + self.assertEqual(cbor2hex(65535), '19ffff') + self.assertEqual(cbor2hex(65536), '1a00010000') + self.assertEqual(cbor2hex(4294967295), '1affffffff') + self.assertEqual(cbor2hex(4294967296), '1b0000000100000000') + self.assertEqual(cbor2hex(-1), '20') + self.assertEqual(cbor2hex(-24), '37') + self.assertEqual(cbor2hex(-25), '3818') + + def test_key_order(self): + self.assertEqual(cbor2hex({ + '3': 0, + b'2': 0, + 1: 0 + }), 'a30100413200613300') + + self.assertEqual(cbor2hex({ + '3': 0, + b'': 0, + 256: 0 + }), 'a3190100004000613300') + + self.assertEqual(cbor2hex({ + 4294967296: 0, + 255: 0, + 256: 0, + 0: 0 + }), 'a4000018ff00190100001b000000010000000000') + + self.assertEqual(cbor2hex({ + b'22': 0, + b'3': 0, + b'111': 0 + }), 'a3413300423232004331313100') + + self.assertEqual(cbor2hex({ + b'001': 0, + b'003': 0, + b'002': 0 + }), 'a3433030310043303032004330303300') + + self.assertEqual(cbor2hex({ + True: 0, + False: 0 + }), 'a2f400f500') diff --git a/test/test_client.py b/test/test_client.py new file mode 100644 index 0000000..fec275f --- /dev/null +++ b/test/test_client.py @@ -0,0 +1,274 @@ +# coding=utf-8 + +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +import mock +import unittest +from threading import Event +from binascii import a2b_hex +from fido_host.utils import sha256, websafe_decode +from fido_host.u2f import ApduError, APDU, RegistrationData, SignatureData +from fido_host.client import ClientData, U2fClient, ClientError + + +class TestClientData(unittest.TestCase): + + def test_client_data(self): + client_data = ClientData(b'{"typ":"navigator.id.finishEnrollment","challenge":"vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}') # noqa + + self.assertEqual(client_data.hash, a2b_hex('4142d21c00d94ffb9d504ada8f99b721f4b191ae4e37ca0140f696b6983cfacb')) # noqa + self.assertEqual(client_data.origin, 'http://example.com') + + self.assertEqual(client_data, ClientData.from_b64(client_data.b64)) + + self.assertEqual(client_data.data, { + 'typ': 'navigator.id.finishEnrollment', + 'challenge': 'vqrS6WXDe1JUs5_c3i4-LkKIHRr-3XVb3azuA5TifHo', + 'cid_pubkey': { + 'kty': 'EC', + 'crv': 'P-256', + 'x': 'HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8', + 'y': 'XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4' + }, + 'origin': 'http://example.com' + }) + + +APP_ID = 'https://foo.example.com' +REG_DATA = RegistrationData(a2b_hex(b'0504b174bc49c7ca254b70d2e5c207cee9cf174820ebd77ea3c65508c26da51b657c1cc6b952f8621697936482da0a6d3d3826a59095daf6cd7c03e2e60385d2f6d9402a552dfdb7477ed65fd84133f86196010b2215b57da75d315b7b9e8fe2e3925a6019551bab61d16591659cbaf00b4950f7abfe6660e2e006f76868b772d70c253082013c3081e4a003020102020a47901280001155957352300a06082a8648ce3d0403023017311530130603550403130c476e756262792050696c6f74301e170d3132303831343138323933325a170d3133303831343138323933325a3031312f302d0603550403132650696c6f74476e756262792d302e342e312d34373930313238303030313135353935373335323059301306072a8648ce3d020106082a8648ce3d030107034200048d617e65c9508e64bcc5673ac82a6799da3c1446682c258c463fffdf58dfd2fa3e6c378b53d795c4a4dffb4199edd7862f23abaf0203b4b8911ba0569994e101300a06082a8648ce3d0403020347003044022060cdb6061e9c22262d1aac1d96d8c70829b2366531dda268832cb836bcd30dfa0220631b1459f09e6330055722c8d89b7f48883b9089b88d60d1d9795902b30410df304502201471899bcc3987e62e8202c9b39c33c19033f7340352dba80fcab017db9230e402210082677d673d891933ade6f617e5dbde2e247e70423fd5ad7804a6d3d3961ef871')) # noqa +SIG_DATA = SignatureData(a2b_hex(b'0100000001304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f')) # noqa + + +class TestU2fClient(unittest.TestCase): + + def test_register_unsupported_version(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_XXX' + + try: + client.register( + APP_ID, [{'version': 'U2F_V2', 'challenge': 'foobar'}], [], + timeout=1) + self.fail('register did not raise error') + except ClientError as e: + self.assertEqual(e.code, ClientError.ERR.DEVICE_INELIGIBLE) + + client.ctap.get_version.assert_called_with() + + def test_register_existing_key(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.side_effect = ApduError(APDU.USE_NOT_SATISFIED) + + try: + client.register( + APP_ID, [{'version': 'U2F_V2', 'challenge': 'foobar'}], + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}], + timeout=1) + self.fail('register did not raise error') + except ClientError as e: + self.assertEqual(e.code, ClientError.ERR.DEVICE_INELIGIBLE) + + client.ctap.get_version.assert_called_with() + client.ctap.authenticate.assert_called_once() + # Check keyHandle + self.assertEqual(client.ctap.authenticate.call_args[0][2], b'key') + # Ensure check-only was set + self.assertTrue(client.ctap.authenticate.call_args[0][3]) + + def test_register(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.side_effect = ApduError(APDU.WRONG_DATA) + client.ctap.register.return_value = REG_DATA + + resp = client.register( + APP_ID, [{'version': 'U2F_V2', 'challenge': 'foobar'}], + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}] + ) + + client.ctap.get_version.assert_called_with() + client.ctap.authenticate.assert_called_once() + client.ctap.register.assert_called_once() + + client_param, app_param = client.ctap.register.call_args[0] + self.assertEqual(sha256(websafe_decode(resp['clientData'])), + client_param) + self.assertEqual(websafe_decode(resp['registrationData']), + REG_DATA) + self.assertEqual(sha256(APP_ID.encode()), app_param) + + def test_register_await_timeout(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.side_effect = ApduError(APDU.WRONG_DATA) + client.ctap.register.side_effect = ApduError(APDU.USE_NOT_SATISFIED) + + client.poll_delay = 0.01 + try: + client.register( + APP_ID, [{'version': 'U2F_V2', 'challenge': 'foobar'}], + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}], + timeout=0.1 + ) + except ClientError as e: + self.assertEqual(e.code, ClientError.ERR.TIMEOUT) + + def test_register_await_touch(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.side_effect = ApduError(APDU.WRONG_DATA) + client.ctap.register.side_effect = [ + ApduError(APDU.USE_NOT_SATISFIED), + ApduError(APDU.USE_NOT_SATISFIED), + ApduError(APDU.USE_NOT_SATISFIED), + ApduError(APDU.USE_NOT_SATISFIED), + REG_DATA + ] + + event = Event() + event.wait = mock.MagicMock() + resp = client.register( + APP_ID, [{'version': 'U2F_V2', 'challenge': 'foobar'}], + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}], + timeout=event + ) + + event.wait.assert_called() + + client.ctap.get_version.assert_called_with() + client.ctap.authenticate.assert_called_once() + client.ctap.register.assert_called() + + client_param, app_param = client.ctap.register.call_args[0] + self.assertEqual(sha256(websafe_decode(resp['clientData'])), + client_param) + self.assertEqual(websafe_decode(resp['registrationData']), + REG_DATA) + self.assertEqual(sha256(APP_ID.encode()), app_param) + + def test_sign_unsupported_version(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_XXX' + + try: + client.sign( + APP_ID, 'challenge', + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}] + ) + self.fail('register did not raise error') + except ClientError as e: + self.assertEqual(e.code, ClientError.ERR.DEVICE_INELIGIBLE) + + client.ctap.get_version.assert_called_with() + + def test_sign_missing_key(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.side_effect = ApduError(APDU.WRONG_DATA) + + try: + client.sign( + APP_ID, 'challenge', + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}], + ) + self.fail('register did not raise error') + except ClientError as e: + self.assertEqual(e.code, ClientError.ERR.DEVICE_INELIGIBLE) + + client.ctap.get_version.assert_called_with() + client.ctap.authenticate.assert_called_once() + _, app_param, key_handle = client.ctap.authenticate.call_args[0] + self.assertEqual(app_param, sha256(APP_ID.encode())) + self.assertEqual(key_handle, b'key') + + def test_sign(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.return_value = SIG_DATA + + resp = client.sign( + APP_ID, 'challenge', + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}], + ) + + client.ctap.get_version.assert_called_with() + client.ctap.authenticate.assert_called_once() + client_param, app_param, key_handle = \ + client.ctap.authenticate.call_args[0] + + self.assertEqual(client_param, + sha256(websafe_decode(resp['clientData']))) + self.assertEqual(app_param, sha256(APP_ID.encode())) + self.assertEqual(key_handle, b'key') + self.assertEqual(websafe_decode(resp['signatureData']), + SIG_DATA) + + def test_sign_await_touch(self): + client = U2fClient(None, APP_ID) + client.ctap = mock.MagicMock() + client.ctap.get_version.return_value = 'U2F_V2' + client.ctap.authenticate.side_effect = [ + ApduError(APDU.USE_NOT_SATISFIED), + ApduError(APDU.USE_NOT_SATISFIED), + ApduError(APDU.USE_NOT_SATISFIED), + ApduError(APDU.USE_NOT_SATISFIED), + SIG_DATA + ] + + event = Event() + event.wait = mock.MagicMock() + + resp = client.sign( + APP_ID, 'challenge', + [{'version': 'U2F_V2', 'keyHandle': 'a2V5'}], + timeout=event + ) + + event.wait.assert_called() + + client.ctap.get_version.assert_called_with() + client.ctap.authenticate.assert_called() + client_param, app_param, key_handle = \ + client.ctap.authenticate.call_args[0] + + self.assertEqual(client_param, + sha256(websafe_decode(resp['clientData']))) + self.assertEqual(app_param, sha256(APP_ID.encode())) + self.assertEqual(key_handle, b'key') + self.assertEqual(websafe_decode(resp['signatureData']), + SIG_DATA) diff --git a/test/test_fido2.py b/test/test_fido2.py new file mode 100644 index 0000000..66e9230 --- /dev/null +++ b/test/test_fido2.py @@ -0,0 +1,255 @@ +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from fido_host.fido2 import (CTAP2, PinProtocolV1, Info, AttestedCredentialData, + AuthenticatorData, AttestationObject, + AssertionResponse) +from fido_host import cbor +from binascii import a2b_hex +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import ec + +import unittest +import mock + +_AAGUID = a2b_hex('F8A011F38C0A4D15800617111F9EDC7D') +_INFO = a2b_hex('a60182665532465f5632684649444f5f325f3002826375766d6b686d61632d7365637265740350f8a011f38c0a4d15800617111f9edc7d04a462726bf5627570f564706c6174f469636c69656e7450696ef4051904b0068101') # noqa + + +class TestInfo(unittest.TestCase): + def test_parse_bytes(self): + info = Info(_INFO) + + self.assertEqual(info.versions, ['U2F_V2', 'FIDO_2_0']) + self.assertEqual(info.extensions, ['uvm', 'hmac-secret']) + self.assertEqual(info.aaguid, _AAGUID) + self.assertEqual(info.options, { + 'rk': True, + 'up': True, + 'plat': False, + 'clientPin': False + }) + self.assertEqual(info.max_msg_size, 1200) + self.assertEqual(info.pin_protocols, [1]) + self.assertEqual(info.data, { + Info.KEY.VERSIONS: ['U2F_V2', 'FIDO_2_0'], + Info.KEY.EXTENSIONS: ['uvm', 'hmac-secret'], + Info.KEY.AAGUID: _AAGUID, + Info.KEY.OPTIONS: { + 'clientPin': False, + 'plat': False, + 'rk': True, + 'up': True + }, + Info.KEY.MAX_MSG_SIZE: 1200, + Info.KEY.PIN_PROTOCOLS: [1] + }) + + +_ATT_CRED_DATA = a2b_hex('f8a011f38c0a4d15800617111f9edc7d0040fe3aac036d14c1e1c65518b698dd1da8f596bc33e11072813466c6bf3845691509b80fb76d59309b8d39e0a93452688f6ca3a39a76f3fc52744fb73948b15783a5010203262001215820643566c206dd00227005fa5de69320616ca268043a38f08bde2e9dc45a5cafaf225820171353b2932434703726aae579fa6542432861fe591e481ea22d63997e1a5290') # noqa +_CRED_ID = a2b_hex('fe3aac036d14c1e1c65518b698dd1da8f596bc33e11072813466c6bf3845691509b80fb76d59309b8d39e0a93452688f6ca3a39a76f3fc52744fb73948b15783') # noqa +_PUB_KEY = {1: 2, 3: -7, -1: 1, -2: a2b_hex('643566c206dd00227005fa5de69320616ca268043a38f08bde2e9dc45a5cafaf'), -3: a2b_hex('171353b2932434703726aae579fa6542432861fe591e481ea22d63997e1a5290')} # noqa + + +class TestAttestedCredentialData(unittest.TestCase): + def test_parse_bytes(self): + data = AttestedCredentialData(_ATT_CRED_DATA) + self.assertEqual(data.aaguid, _AAGUID) + self.assertEqual(data.credential_id, _CRED_ID) + self.assertEqual(data.public_key, _PUB_KEY) + + def test_create_from_args(self): + data = AttestedCredentialData.create(_AAGUID, _CRED_ID, _PUB_KEY) + self.assertEqual(_ATT_CRED_DATA, data) + + +_AUTH_DATA_MC = a2b_hex('0021F5FC0B85CD22E60623BCD7D1CA48948909249B4776EB515154E57B66AE12410000001CF8A011F38C0A4D15800617111F9EDC7D0040FE3AAC036D14C1E1C65518B698DD1DA8F596BC33E11072813466C6BF3845691509B80FB76D59309B8D39E0A93452688F6CA3A39A76F3FC52744FB73948B15783A5010203262001215820643566C206DD00227005FA5DE69320616CA268043A38F08BDE2E9DC45A5CAFAF225820171353B2932434703726AAE579FA6542432861FE591E481EA22D63997E1A5290') # noqa +_AUTH_DATA_GA = a2b_hex('0021F5FC0B85CD22E60623BCD7D1CA48948909249B4776EB515154E57B66AE12010000001D') # noqa +_RP_ID_HASH = a2b_hex('0021F5FC0B85CD22E60623BCD7D1CA48948909249B4776EB515154E57B66AE12') # noqa + + +class TestAuthenticatorData(unittest.TestCase): + def test_parse_bytes_make_credential(self): + data = AuthenticatorData(_AUTH_DATA_MC) + self.assertEqual(data.rp_id_hash, _RP_ID_HASH) + self.assertEqual(data.flags, 0x41) + self.assertEqual(data.counter, 28) + self.assertEqual(data.credential_data, _ATT_CRED_DATA) + self.assertIsNone(data.extensions) + + def test_parse_bytes_get_assertion(self): + data = AuthenticatorData(_AUTH_DATA_GA) + self.assertEqual(data.rp_id_hash, _RP_ID_HASH) + self.assertEqual(data.flags, 0x01) + self.assertEqual(data.counter, 29) + self.assertIsNone(data.credential_data) + self.assertIsNone(data.extensions) + + +_MC_RESP = a2b_hex('a301667061636b6564025900c40021f5fc0b85cd22e60623bcd7d1ca48948909249b4776eb515154e57b66ae12410000001cf8a011f38c0a4d15800617111f9edc7d0040fe3aac036d14c1e1c65518b698dd1da8f596bc33e11072813466c6bf3845691509b80fb76d59309b8d39e0a93452688f6ca3a39a76f3fc52744fb73948b15783a5010203262001215820643566c206dd00227005fa5de69320616ca268043a38f08bde2e9dc45a5cafaf225820171353b2932434703726aae579fa6542432861fe591e481ea22d63997e1a529003a363616c67266373696758483046022100cc1ef43edf07de8f208c21619c78a565ddcf4150766ad58781193be8e0a742ed022100f1ed7c7243e45b7d8e5bda6b1abf10af7391789d1ef21b70bd69fed48dba4cb163783563815901973082019330820138a003020102020900859b726cb24b4c29300a06082a8648ce3d0403023047310b300906035504061302555331143012060355040a0c0b59756269636f205465737431223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e301e170d3136313230343131353530305a170d3236313230323131353530305a3047310b300906035504061302555331143012060355040a0c0b59756269636f205465737431223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3059301306072a8648ce3d020106082a8648ce3d03010703420004ad11eb0e8852e53ad5dfed86b41e6134a18ec4e1af8f221a3c7d6e636c80ea13c3d504ff2e76211bb44525b196c44cb4849979cf6f896ecd2bb860de1bf4376ba30d300b30090603551d1304023000300a06082a8648ce3d0403020349003046022100e9a39f1b03197525f7373e10ce77e78021731b94d0c03f3fda1fd22db3d030e7022100c4faec3445a820cf43129cdb00aabefd9ae2d874f9c5d343cb2f113da23723f3') # noqa +_GA_RESP = a2b_hex('a301a26269645840fe3aac036d14c1e1c65518b698dd1da8f596bc33e11072813466c6bf3845691509b80fb76d59309b8d39e0a93452688f6ca3a39a76f3fc52744fb73948b1578364747970656a7075626c69632d6b6579025900250021f5fc0b85cd22e60623bcd7d1ca48948909249b4776eb515154e57b66ae12010000001d035846304402206765cbf6e871d3af7f01ae96f06b13c90f26f54b905c5166a2c791274fc2397102200b143893586cc799fba4da83b119eaea1bd80ac3ce88fcedb3efbd596a1f4f63') # noqa +_CRED_ID = a2b_hex('FE3AAC036D14C1E1C65518B698DD1DA8F596BC33E11072813466C6BF3845691509B80FB76D59309B8D39E0A93452688F6CA3A39A76F3FC52744FB73948B15783') # noqa +_CRED = {'type': 'public-key', 'id': _CRED_ID} +_SIGNATURE = a2b_hex('304402206765CBF6E871D3AF7F01AE96F06B13C90F26F54B905C5166A2C791274FC2397102200B143893586CC799FBA4DA83B119EAEA1BD80AC3CE88FCEDB3EFBD596A1F4F63') # noqa + + +class TestCTAP2(unittest.TestCase): + def test_send_cbor_ok(self): + ctap = CTAP2(mock.MagicMock()) + ctap.device.call.return_value = b'\0' + cbor.dumps({1: b'response'}) + + self.assertEqual({1: b'response'}, ctap.send_cbor(2, b'foobar')) + ctap.device.call.assert_called_with(0x10, b'\2' + cbor.dumps(b'foobar'), + None) + + def test_get_info(self): + ctap = CTAP2(mock.MagicMock()) + ctap.device.call.return_value = b'\0' + _INFO + + info = ctap.get_info() + ctap.device.call.assert_called_with(0x10, b'\4', None) + self.assertIsInstance(info, Info) + + def test_make_credential(self): + ctap = CTAP2(mock.MagicMock()) + ctap.device.call.return_value = b'\0' + _MC_RESP + + resp = ctap.make_credential(1, 2, 3, 4) + ctap.device.call.assert_called_with( + 0x10, b'\1' + cbor.dumps({1: 1, 2: 2, 3: 3, 4: 4}), None) + + self.assertIsInstance(resp, AttestationObject) + self.assertEqual(resp, _MC_RESP) + self.assertEqual(resp.fmt, 'packed') + self.assertEqual(resp.auth_data, _AUTH_DATA_MC) + self.assertSetEqual(set(resp.att_statement.keys()), + {'alg', 'sig', 'x5c'}) + + def test_get_assertion(self): + ctap = CTAP2(mock.MagicMock()) + ctap.device.call.return_value = b'\0' + _GA_RESP + + resp = ctap.get_assertion(1, 2) + ctap.device.call.assert_called_with( + 0x10, b'\2' + cbor.dumps({1: 1, 2: 2}), None) + + self.assertIsInstance(resp, AssertionResponse) + self.assertEqual(resp, _GA_RESP) + self.assertEqual(resp.credential, _CRED) + self.assertEqual(resp.auth_data, _AUTH_DATA_GA) + self.assertEqual(resp.signature, _SIGNATURE) + self.assertIsNone(resp.user) + self.assertIsNone(resp.number_of_credentials) + + +EC_PRIV = 0x7452e599fee739d8a653f6a507343d12d382249108a651402520b72f24fe7684 +EC_PUB_X = a2b_hex('44D78D7989B97E62EA993496C9EF6E8FD58B8B00715F9A89153DDD9C4657E47F') # noqa +EC_PUB_Y = a2b_hex('EC802EE7D22BD4E100F12E48537EB4E7E96ED3A47A0A3BD5F5EEAB65001664F9') # noqa +DEV_PUB_X = a2b_hex('0501D5BC78DA9252560A26CB08FCC60CBE0B6D3B8E1D1FCEE514FAC0AF675168') # noqa +DEV_PUB_Y = a2b_hex('D551B3ED46F665731F95B4532939C25D91DB7EB844BD96D4ABD4083785F8DF47') # noqa +SHARED = a2b_hex('c42a039d548100dfba521e487debcbbb8b66bb7496f8b1862a7a395ed83e1a1c') # noqa +TOKEN_ENC = a2b_hex('7A9F98E31B77BE90F9C64D12E9635040') +TOKEN = a2b_hex('aff12c6dcfbf9df52f7a09211e8865cd') +PIN_HASH_ENC = a2b_hex('afe8327ce416da8ee3d057589c2ce1a9') + + +class TestPinProtocolV1(unittest.TestCase): + + @mock.patch('cryptography.hazmat.primitives.asymmetric.ec.generate_private_key') # noqa + def test_establish_shared_secret(self, patched_generate): + prot = PinProtocolV1(mock.MagicMock()) + + patched_generate.return_value = ec.derive_private_key( + EC_PRIV, + ec.SECP256R1(), + default_backend() + ) + + prot.ctap.client_pin.return_value = { + 1: { + 1: 2, + 3: -25, + -1: 1, + -2: DEV_PUB_X, + -3: DEV_PUB_Y + } + } + + key_agreement, shared = prot._init_shared_secret() + + self.assertEqual(shared, SHARED) + self.assertEqual(key_agreement[-2], EC_PUB_X) + self.assertEqual(key_agreement[-3], EC_PUB_Y) + + def test_get_pin_token(self): + prot = PinProtocolV1(mock.MagicMock()) + prot._init_shared_secret = mock.Mock(return_value=({}, SHARED)) + prot.ctap.client_pin.return_value = { + 2: TOKEN_ENC + } + + self.assertEqual(prot.get_pin_token('1234'), TOKEN) + prot.ctap.client_pin.assert_called_once() + self.assertEqual(prot.ctap.client_pin.call_args[1]['pin_hash_enc'], + PIN_HASH_ENC) + + def test_set_pin(self): + prot = PinProtocolV1(mock.MagicMock()) + prot._init_shared_secret = mock.Mock(return_value=({}, SHARED)) + + prot.set_pin('1234') + prot.ctap.client_pin.assert_called_with( + 1, + 3, + key_agreement={}, + new_pin_enc=a2b_hex('0222fc42c6dd76a274a7057858b9b29d98e8a722ec2dc6668476168c5320473cec9907b4cd76ce7943c96ba5683943211d84471e64d9c51e54763488cd66526a'), # noqa + pin_auth=a2b_hex('7b40c084ccc5794194189ab57836475f') + ) + + def test_change_pin(self): + prot = PinProtocolV1(mock.MagicMock()) + prot._init_shared_secret = mock.Mock(return_value=({}, SHARED)) + + prot.change_pin('1234', '4321') + prot.ctap.client_pin.assert_called_with( + 1, + 4, + key_agreement={}, + new_pin_enc=a2b_hex('4280e14aac4fcbf02dd079985f0c0ffc9ea7d5f9c173fd1a4c843826f7590cb3c2d080c6923e2fe6d7a52c31ea1309d3fcca3dedae8a2ef14b6330cafc79339e'), # noqa + pin_auth=a2b_hex('fb97e92f3724d7c85e001d7f93e6490a'), + pin_hash_enc=a2b_hex('afe8327ce416da8ee3d057589c2ce1a9') + ) + + def test_short_pin(self): + prot = PinProtocolV1(mock.MagicMock()) + with self.assertRaises(ValueError): + prot.set_pin('123') + + def test_long_pin(self): + prot = PinProtocolV1(mock.MagicMock()) + with self.assertRaises(ValueError): + prot.set_pin('1'*256) diff --git a/test/test_hid.py b/test/test_hid.py new file mode 100644 index 0000000..7a3637d --- /dev/null +++ b/test/test_hid.py @@ -0,0 +1,48 @@ +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from fido_host.hid import CtapHidDevice +import unittest + + +class HidTest(unittest.TestCase): + def get_device(self): + try: + devs = list(CtapHidDevice.list_devices()) + assert len(devs) == 1 + return devs[0] + except Exception: + self.skipTest('Tests require a single FIDO HID device') + + def test_ping(self): + msg1 = b'hello world!' + msg2 = b' ' + msg3 = b'' + dev = self.get_device() + self.assertEqual(dev.ping(0x40, 0, 0, msg1), msg1) + self.assertEqual(dev.ping(0x40, 0, 0, msg2), msg2) + self.assertEqual(dev.ping(0x40, 0, 0, msg3), msg3) diff --git a/test/test_rpid.py b/test/test_rpid.py new file mode 100644 index 0000000..16edd17 --- /dev/null +++ b/test/test_rpid.py @@ -0,0 +1,106 @@ +# coding=utf-8 + +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from fido_host.rpid import verify_app_id, verify_rp_id +import unittest + + +class TestAppId(unittest.TestCase): + + def test_valid_ids(self): + self.assertTrue(verify_app_id('https://example.com', + 'https://register.example.com')) + self.assertTrue(verify_app_id('https://example.com', + 'https://fido.example.com')) + self.assertTrue(verify_app_id('https://example.com', + 'https://www.example.com:444')) + + self.assertTrue(verify_app_id( + 'https://companyA.hosting.example.com', + 'https://fido.companyA.hosting.example.com' + )) + self.assertTrue(verify_app_id( + 'https://companyA.hosting.example.com', + 'https://xyz.companyA.hosting.example.com' + )) + + def test_invalid_ids(self): + self.assertFalse(verify_app_id('https://example.com', + 'http://example.com')) + self.assertFalse(verify_app_id('https://example.com', + 'http://www.example.com')) + self.assertFalse(verify_app_id('https://example.com', + 'https://example-test.com')) + + self.assertFalse(verify_app_id( + 'https://companyA.hosting.example.com', + 'https://register.example.com' + )) + self.assertFalse(verify_app_id( + 'https://companyA.hosting.example.com', + 'https://companyB.hosting.example.com' + )) + + def test_effective_tld_names(self): + self.assertFalse(verify_app_id( + 'https://appspot.com', + 'https://foo.appspot.com' + )) + self.assertFalse(verify_app_id( + 'https://co.uk', + 'https://example.co.uk' + )) + + +class TestRpId(unittest.TestCase): + + def test_valid_ids(self): + self.assertTrue(verify_rp_id('example.com', + 'https://register.example.com')) + self.assertTrue(verify_rp_id('example.com', + 'https://fido.example.com')) + self.assertTrue(verify_rp_id('example.com', + 'https://www.example.com:444')) + + def test_invalid_ids(self): + self.assertFalse(verify_rp_id('example.com', + 'http://example.com')) + self.assertFalse(verify_rp_id('example.com', + 'http://www.example.com')) + self.assertFalse(verify_rp_id('example.com', + 'https://example-test.com')) + + self.assertFalse(verify_rp_id( + 'companyA.hosting.example.com', + 'https://register.example.com' + )) + self.assertFalse(verify_rp_id( + 'companyA.hosting.example.com', + 'https://companyB.hosting.example.com' + )) diff --git a/test/test_u2f.py b/test/test_u2f.py new file mode 100644 index 0000000..a6fccd7 --- /dev/null +++ b/test/test_u2f.py @@ -0,0 +1,95 @@ +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from fido_host.u2f import CTAP1, ApduError +from binascii import a2b_hex +import unittest +import mock + + +class TestCTAP1(unittest.TestCase): + + def test_send_apdu_ok(self): + ctap = CTAP1(mock.MagicMock()) + ctap.device.call.return_value = b'response\x90\x00' + + self.assertEqual(b'response', ctap.send_apdu(1, 2, 3, 4, b'foobar')) + ctap.device.call.assert_called_with(0x03, b'\1\2\3\4\0\0\6foobar\0\0') + + def test_send_apdu_err(self): + ctap = CTAP1(mock.MagicMock()) + ctap.device.call.return_value = b'err\x6a\x80' + + try: + ctap.send_apdu(1, 2, 3, 4, b'foobar') + self.fail('send_apdu did not raise error') + except ApduError as e: + self.assertEqual(e.code, 0x6a80) + self.assertEqual(e.data, b'err') + ctap.device.call.assert_called_with(0x03, b'\1\2\3\4\0\0\6foobar\0\0') + + def test_get_version(self): + ctap = CTAP1(mock.MagicMock()) + ctap.device.call.return_value = b'U2F_V2\x90\x00' + + self.assertEqual('U2F_V2', ctap.get_version()) + ctap.device.call.assert_called_with(0x03, b'\0\3\0\0\0\0\0\0\0') + + def test_register(self): + ctap = CTAP1(mock.MagicMock()) + ctap.device.call.return_value = a2b_hex(b'0504b174bc49c7ca254b70d2e5c207cee9cf174820ebd77ea3c65508c26da51b657c1cc6b952f8621697936482da0a6d3d3826a59095daf6cd7c03e2e60385d2f6d9402a552dfdb7477ed65fd84133f86196010b2215b57da75d315b7b9e8fe2e3925a6019551bab61d16591659cbaf00b4950f7abfe6660e2e006f76868b772d70c253082013c3081e4a003020102020a47901280001155957352300a06082a8648ce3d0403023017311530130603550403130c476e756262792050696c6f74301e170d3132303831343138323933325a170d3133303831343138323933325a3031312f302d0603550403132650696c6f74476e756262792d302e342e312d34373930313238303030313135353935373335323059301306072a8648ce3d020106082a8648ce3d030107034200048d617e65c9508e64bcc5673ac82a6799da3c1446682c258c463fffdf58dfd2fa3e6c378b53d795c4a4dffb4199edd7862f23abaf0203b4b8911ba0569994e101300a06082a8648ce3d0403020347003044022060cdb6061e9c22262d1aac1d96d8c70829b2366531dda268832cb836bcd30dfa0220631b1459f09e6330055722c8d89b7f48883b9089b88d60d1d9795902b30410df304502201471899bcc3987e62e8202c9b39c33c19033f7340352dba80fcab017db9230e402210082677d673d891933ade6f617e5dbde2e247e70423fd5ad7804a6d3d3961ef871') + b'\x90\x00' # noqa + + resp = ctap.register(b'\1'*32, b'\2'*32) + ctap.device.call.assert_called_with(0x03, b'\0\1\0\0\0\0\x40' + + b'\1'*32 + b'\2'*32 + b'\0\0') + self.assertEqual(resp.public_key, a2b_hex(b'04b174bc49c7ca254b70d2e5c207cee9cf174820ebd77ea3c65508c26da51b657c1cc6b952f8621697936482da0a6d3d3826a59095daf6cd7c03e2e60385d2f6d9')) # noqa + self.assertEqual(resp.key_handle, a2b_hex(b'2a552dfdb7477ed65fd84133f86196010b2215b57da75d315b7b9e8fe2e3925a6019551bab61d16591659cbaf00b4950f7abfe6660e2e006f76868b772d70c25')) # noqa + self.assertEqual(resp.certificate, a2b_hex(b'3082013c3081e4a003020102020a47901280001155957352300a06082a8648ce3d0403023017311530130603550403130c476e756262792050696c6f74301e170d3132303831343138323933325a170d3133303831343138323933325a3031312f302d0603550403132650696c6f74476e756262792d302e342e312d34373930313238303030313135353935373335323059301306072a8648ce3d020106082a8648ce3d030107034200048d617e65c9508e64bcc5673ac82a6799da3c1446682c258c463fffdf58dfd2fa3e6c378b53d795c4a4dffb4199edd7862f23abaf0203b4b8911ba0569994e101300a06082a8648ce3d0403020347003044022060cdb6061e9c22262d1aac1d96d8c70829b2366531dda268832cb836bcd30dfa0220631b1459f09e6330055722c8d89b7f48883b9089b88d60d1d9795902b30410df')) # noqa + self.assertEqual(resp.signature, a2b_hex(b'304502201471899bcc3987e62e8202c9b39c33c19033f7340352dba80fcab017db9230e402210082677d673d891933ade6f617e5dbde2e247e70423fd5ad7804a6d3d3961ef871')) # noqa + + def test_authenticate(self): + ctap = CTAP1(mock.MagicMock()) + ctap.device.call.return_value = a2b_hex(b'0100000001304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f') + b'\x90\x00' # noqa + + resp = ctap.authenticate(b'\1'*32, b'\2'*32, b'\3'*64) + ctap.device.call.assert_called_with(0x03, b'\0\2\3\0\0\0\x81' + + b'\1'*32 + b'\2'*32 + b'\x40' + + b'\3'*64 + b'\0\0') + + self.assertEqual(resp.user_presence, 1) + self.assertEqual(resp.counter, 1) + self.assertEqual(resp.signature, a2b_hex(b'304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f')) # noqa + + ctap.authenticate(b'\1'*32, b'\2'*32, b'\3'*8) + ctap.device.call.assert_called_with(0x03, b'\0\2\3\0\0\0\x49' + + b'\1'*32 + b'\2'*32 + b'\x08' + + b'\3'*8 + b'\0\0') + + ctap.authenticate(b'\1'*32, b'\2'*32, b'\3'*8, True) + ctap.device.call.assert_called_with(0x03, b'\0\2\7\0\0\0\x49' + + b'\1'*32 + b'\2'*32 + b'\x08' + + b'\3'*8 + b'\0\0') diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 0000000..b8f0df0 --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,118 @@ +# coding=utf-8 + +# Copyright (c) 2013 Yubico AB +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +import unittest +from binascii import a2b_hex +from threading import Event + +from fido_host.utils import ( + Timeout, + hmac_sha256, + sha256, + websafe_encode, + websafe_decode +) + + +class TestSha256(unittest.TestCase): + + def test_sha256_vectors(self): + self.assertEqual(sha256(b'abc'), a2b_hex(b'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')) # noqa + self.assertEqual(sha256(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), a2b_hex(b'248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1')) # noqa + + +class TestHmacSha256(unittest.TestCase): + + def test_hmac_sha256_vectors(self): + self.assertEqual(hmac_sha256( + b'\x0b'*20, + b'Hi There' + ), a2b_hex(b'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7')) # noqa + + self.assertEqual(hmac_sha256( + b'Jefe', + b'what do ya want for nothing?' + ), a2b_hex(b'5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843')) # noqa + + +class TestWebSafe(unittest.TestCase): + # Base64 vectors adapted from https://tools.ietf.org/html/rfc4648#section-10 + + def test_websafe_decode(self): + self.assertEqual(websafe_decode(b''), b'') + self.assertEqual(websafe_decode(b'Zg'), b'f') + self.assertEqual(websafe_decode(b'Zm8'), b'fo') + self.assertEqual(websafe_decode(b'Zm9v'), b'foo') + self.assertEqual(websafe_decode(b'Zm9vYg'), b'foob') + self.assertEqual(websafe_decode(b'Zm9vYmE'), b'fooba') + self.assertEqual(websafe_decode(b'Zm9vYmFy'), b'foobar') + + def test_websafe_decode_unicode(self): + self.assertEqual(websafe_decode(u''), b'') + self.assertEqual(websafe_decode(u'Zm9vYmFy'), b'foobar') + + def test_websafe_encode(self): + self.assertEqual(websafe_encode(b''), u'') + self.assertEqual(websafe_encode(b'f'), u'Zg') + self.assertEqual(websafe_encode(b'fo'), u'Zm8') + self.assertEqual(websafe_encode(b'foo'), u'Zm9v') + self.assertEqual(websafe_encode(b'foob'), u'Zm9vYg') + self.assertEqual(websafe_encode(b'fooba'), u'Zm9vYmE') + self.assertEqual(websafe_encode(b'foobar'), u'Zm9vYmFy') + + def test_websafe_encode_unicode(self): + self.assertEqual(websafe_encode(u''), u'') + self.assertEqual(websafe_encode(u'foobar'), u'Zm9vYmFy') + + +class TestTimeout(unittest.TestCase): + + def test_event(self): + event = Event() + timeout = Timeout(event) + self.assertIsNone(timeout.timer) + with timeout as e: + self.assertIs(event, e) + self.assertFalse(e.is_set()) + self.assertFalse(event.is_set()) + + def test_timer_stops(self): + timeout = Timeout(10) + self.assertFalse(timeout.timer.is_alive()) + with timeout as e: + self.assertTrue(timeout.timer.is_alive()) + self.assertFalse(e.is_set()) + self.assertFalse(timeout.timer.is_alive()) + self.assertFalse(e.is_set()) + + def test_timer_triggers(self): + with Timeout(0.01) as e: + self.assertTrue(e.wait(0.02)) + self.assertTrue(e.is_set())