From 40caacefa8084e2b9e5ac1d3fffb6f137b150fc4 Mon Sep 17 00:00:00 2001 From: Manasij Sur Roy Date: Mon, 28 Dec 2015 17:44:57 +0530 Subject: [PATCH] Initial 3.0 public version Change-Id: I59f9eb2fc7e42440550b14b731fc4665db1aa397 Signed-off-by: Manasij Sur Roy --- .gitignore | 5 + CMakeLists.txt | 18 + LICENSE.Apache-2.0 | 202 ++ NOTICE | 3 + client/CMakeLists.txt | 61 + client/fido-client.pc.in | 13 + client/fido_uaf_authenticator.c | 235 ++ client/fido_uaf_client.c | 364 ++++ common/dbus_interfaces/dummyasm.xml | 10 + common/dbus_interfaces/fido.xml | 35 + common/fido_b64_util.c | 136 ++ common/fido_b64_util.h | 28 + common/fido_internal_types.h | 487 +++++ common/fido_json_handler.c | 2280 ++++++++++++++++++++ common/fido_json_handler.h | 65 + common/fido_keys.h | 83 + common/fido_logs.h | 39 + common/fido_tlv_util.c | 146 ++ common/fido_tlv_util.h | 30 + common/fido_uaf_types.h | 195 ++ common/fido_uaf_utils.c | 693 ++++++ doc/fido_doc.h | 57 + dummyasm.manifest | 5 + fido.manifest | 9 + fido_svc_ui/CMakeLists.txt | 69 + fido_svc_ui/fido_ui_server.c | 616 ++++++ fido_svc_ui/org.tizen.fidosvcui.png | Bin 0 -> 57662 bytes fido_svc_ui/org.tizen.fidosvcui.xml.in | 12 + include/fido.h | 45 + include/fido_uaf_authenticator.h | 288 +++ include/fido_uaf_client.h | 167 ++ org.tizen.FidoSample.manifest | 25 + org.tizen.fidosvcui.manifest | 5 + packaging/fido-client.spec | 218 ++ packaging/org.tizen.dummyasm.conf | 31 + packaging/org.tizen.dummyasm.service | 5 + packaging/org.tizen.fido.conf | 31 + packaging/org.tizen.fido.service | 8 + packaging/org.tizen.fidosvcui.service | 5 + server/CMakeLists.txt | 56 + server/fido_app_id_handler.c | 301 +++ server/fido_app_id_handler.h | 28 + server/fido_asm_plugin_manager.c | 464 ++++ server/fido_asm_plugin_manager.h | 39 + server/fido_privilege_checker.c | 180 ++ server/fido_privilege_checker.h | 28 + server/fido_selection_ui_adaptor.c | 514 +++++ server/fido_selection_ui_adaptor.h | 31 + server/fido_server.c | 1378 ++++++++++++ server/fido_uaf_policy_checker.c | 531 +++++ server/fido_uaf_policy_checker.h | 34 + test/Dummy_ASM_DBUS/CMakeLists.txt | 39 + test/Dummy_ASM_DBUS/dummy_asm.json | 8 + test/Dummy_ASM_DBUS/dummy_asm_server.c | 299 +++ test/FIDOSample/.cproject | 557 +++++ test/FIDOSample/.exportMap | 4 + test/FIDOSample/.project | 43 + test/FIDOSample/.rds_delta | 6 + test/FIDOSample/.sdk_delta.info | Bin 0 -> 3538 bytes test/FIDOSample/.sign/.manifest.tmp | 14 + test/FIDOSample/.sign/author-signature.xml | 106 + test/FIDOSample/.sign/signature1.xml | 108 + test/FIDOSample/.tproject | 11 + .../edje/images/00_controlbar_icon_artists.png | Bin 0 -> 3131 bytes .../edje/images/00_controlbar_icon_dialer.png | Bin 0 -> 2950 bytes .../edje/images/00_controlbar_icon_favorites.png | Bin 0 -> 3170 bytes .../edje/images/00_controlbar_icon_playlist.png | Bin 0 -> 2960 bytes .../edje/images/00_controlbar_icon_songs.png | Bin 0 -> 3143 bytes test/FIDOSample/edje/images/core_button_add.png | Bin 0 -> 1004 bytes test/FIDOSample/edje/images/core_button_delete.png | Bin 0 -> 978 bytes .../edje/images/core_color_picker_palette.png | Bin 0 -> 1041 bytes .../edje/images/core_icon_brightness.png | Bin 0 -> 1432 bytes test/FIDOSample/edje/images/grid_image/1_raw.jpg | Bin 0 -> 9594 bytes test/FIDOSample/edje/images/grid_image/2_raw.jpg | Bin 0 -> 6328 bytes test/FIDOSample/edje/images/horz_scrollbar.jpg | Bin 0 -> 719515 bytes test/FIDOSample/edje/images/iu.jpg | Bin 0 -> 4484 bytes test/FIDOSample/edje/images/logo.png | Bin 0 -> 19311 bytes test/FIDOSample/inc/main.h | 53 + test/FIDOSample/res/auth_req.json | 92 + test/FIDOSample/res/dereg_req.json | 1 + test/FIDOSample/res/images/grid_image/1_raw.png | Bin 0 -> 12563 bytes test/FIDOSample/res/images/grid_image/2_raw.png | Bin 0 -> 13344 bytes test/FIDOSample/res/images/horz_scrollbar.png | Bin 0 -> 46086 bytes test/FIDOSample/res/images/iu.png | Bin 0 -> 5764 bytes test/FIDOSample/res/reg_req.json | 1 + test/FIDOSample/shared/res/fidosample.png | Bin 0 -> 57662 bytes test/FIDOSample/src/main.c | 681 ++++++ test/FIDOSample/tizen-manifest.xml | 13 + test/Fido_Sample_RPM/.cproject | 240 +++ test/Fido_Sample_RPM/.project | 94 + test/Fido_Sample_RPM/CMakeLists.txt | 67 + test/Fido_Sample_RPM/include/main.h | 53 + test/Fido_Sample_RPM/org.tizen.FidoSample.png | Bin 0 -> 57662 bytes test/Fido_Sample_RPM/org.tizen.FidoSample.xml.in | 13 + test/Fido_Sample_RPM/po/CMakeLists.txt | 37 + test/Fido_Sample_RPM/po/POTFILES.in | 2 + test/Fido_Sample_RPM/po/de_DE.po | 22 + test/Fido_Sample_RPM/po/el_GR.po | 22 + test/Fido_Sample_RPM/po/en.po | 22 + test/Fido_Sample_RPM/po/es_ES.po | 22 + test/Fido_Sample_RPM/po/fr_FR.po | 22 + test/Fido_Sample_RPM/po/hello-efl.pot | 22 + test/Fido_Sample_RPM/po/it_IT.po | 22 + test/Fido_Sample_RPM/po/ja_JP.po | 22 + test/Fido_Sample_RPM/po/ko_KR.po | 22 + test/Fido_Sample_RPM/po/nl_NL.po | 22 + test/Fido_Sample_RPM/po/pt_PT.po | 22 + test/Fido_Sample_RPM/po/ru_RU.po | 22 + test/Fido_Sample_RPM/po/tr_TR.po | 22 + test/Fido_Sample_RPM/po/update-po.sh | 59 + test/Fido_Sample_RPM/po/zh_CN.po | 22 + test/Fido_Sample_RPM/po/zh_HK.po | 22 + test/Fido_Sample_RPM/po/zh_TW.po | 22 + test/Fido_Sample_RPM/res/auth_req.json | 50 + test/Fido_Sample_RPM/res/dereg_req.json | 18 + test/Fido_Sample_RPM/res/reg_req.json | 33 + test/Fido_Sample_RPM/src/main.c | 638 ++++++ test/shell_tc/CMakeLists.txt | 33 + test/shell_tc/fido_shell_tc.c | 421 ++++ test/shell_tc/fido_shell_tc_util.c | 256 +++ test/shell_tc/fido_shell_tc_util.h | 180 ++ 121 files changed, 14890 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE.Apache-2.0 create mode 100755 NOTICE create mode 100644 client/CMakeLists.txt create mode 100644 client/fido-client.pc.in create mode 100755 client/fido_uaf_authenticator.c create mode 100755 client/fido_uaf_client.c create mode 100644 common/dbus_interfaces/dummyasm.xml create mode 100644 common/dbus_interfaces/fido.xml create mode 100644 common/fido_b64_util.c create mode 100644 common/fido_b64_util.h create mode 100644 common/fido_internal_types.h create mode 100644 common/fido_json_handler.c create mode 100644 common/fido_json_handler.h create mode 100644 common/fido_keys.h create mode 100644 common/fido_logs.h create mode 100644 common/fido_tlv_util.c create mode 100644 common/fido_tlv_util.h create mode 100644 common/fido_uaf_types.h create mode 100644 common/fido_uaf_utils.c create mode 100755 doc/fido_doc.h create mode 100644 dummyasm.manifest create mode 100644 fido.manifest create mode 100644 fido_svc_ui/CMakeLists.txt create mode 100644 fido_svc_ui/fido_ui_server.c create mode 100644 fido_svc_ui/org.tizen.fidosvcui.png create mode 100644 fido_svc_ui/org.tizen.fidosvcui.xml.in create mode 100644 include/fido.h create mode 100755 include/fido_uaf_authenticator.h create mode 100755 include/fido_uaf_client.h create mode 100755 org.tizen.FidoSample.manifest create mode 100755 org.tizen.fidosvcui.manifest create mode 100644 packaging/fido-client.spec create mode 100644 packaging/org.tizen.dummyasm.conf create mode 100644 packaging/org.tizen.dummyasm.service create mode 100644 packaging/org.tizen.fido.conf create mode 100644 packaging/org.tizen.fido.service create mode 100644 packaging/org.tizen.fidosvcui.service create mode 100644 server/CMakeLists.txt create mode 100644 server/fido_app_id_handler.c create mode 100644 server/fido_app_id_handler.h create mode 100644 server/fido_asm_plugin_manager.c create mode 100644 server/fido_asm_plugin_manager.h create mode 100644 server/fido_privilege_checker.c create mode 100644 server/fido_privilege_checker.h create mode 100644 server/fido_selection_ui_adaptor.c create mode 100644 server/fido_selection_ui_adaptor.h create mode 100755 server/fido_server.c create mode 100644 server/fido_uaf_policy_checker.c create mode 100644 server/fido_uaf_policy_checker.h create mode 100644 test/Dummy_ASM_DBUS/CMakeLists.txt create mode 100644 test/Dummy_ASM_DBUS/dummy_asm.json create mode 100644 test/Dummy_ASM_DBUS/dummy_asm_server.c create mode 100644 test/FIDOSample/.cproject create mode 100644 test/FIDOSample/.exportMap create mode 100644 test/FIDOSample/.project create mode 100644 test/FIDOSample/.rds_delta create mode 100644 test/FIDOSample/.sdk_delta.info create mode 100644 test/FIDOSample/.sign/.manifest.tmp create mode 100644 test/FIDOSample/.sign/author-signature.xml create mode 100644 test/FIDOSample/.sign/signature1.xml create mode 100644 test/FIDOSample/.tproject create mode 100644 test/FIDOSample/edje/images/00_controlbar_icon_artists.png create mode 100644 test/FIDOSample/edje/images/00_controlbar_icon_dialer.png create mode 100644 test/FIDOSample/edje/images/00_controlbar_icon_favorites.png create mode 100644 test/FIDOSample/edje/images/00_controlbar_icon_playlist.png create mode 100644 test/FIDOSample/edje/images/00_controlbar_icon_songs.png create mode 100644 test/FIDOSample/edje/images/core_button_add.png create mode 100644 test/FIDOSample/edje/images/core_button_delete.png create mode 100644 test/FIDOSample/edje/images/core_color_picker_palette.png create mode 100644 test/FIDOSample/edje/images/core_icon_brightness.png create mode 100644 test/FIDOSample/edje/images/grid_image/1_raw.jpg create mode 100644 test/FIDOSample/edje/images/grid_image/2_raw.jpg create mode 100644 test/FIDOSample/edje/images/horz_scrollbar.jpg create mode 100644 test/FIDOSample/edje/images/iu.jpg create mode 100644 test/FIDOSample/edje/images/logo.png create mode 100644 test/FIDOSample/inc/main.h create mode 100644 test/FIDOSample/res/auth_req.json create mode 100644 test/FIDOSample/res/dereg_req.json create mode 100644 test/FIDOSample/res/images/grid_image/1_raw.png create mode 100644 test/FIDOSample/res/images/grid_image/2_raw.png create mode 100644 test/FIDOSample/res/images/horz_scrollbar.png create mode 100644 test/FIDOSample/res/images/iu.png create mode 100644 test/FIDOSample/res/reg_req.json create mode 100644 test/FIDOSample/shared/res/fidosample.png create mode 100755 test/FIDOSample/src/main.c create mode 100644 test/FIDOSample/tizen-manifest.xml create mode 100644 test/Fido_Sample_RPM/.cproject create mode 100644 test/Fido_Sample_RPM/.project create mode 100644 test/Fido_Sample_RPM/CMakeLists.txt create mode 100644 test/Fido_Sample_RPM/include/main.h create mode 100644 test/Fido_Sample_RPM/org.tizen.FidoSample.png create mode 100644 test/Fido_Sample_RPM/org.tizen.FidoSample.xml.in create mode 100644 test/Fido_Sample_RPM/po/CMakeLists.txt create mode 100644 test/Fido_Sample_RPM/po/POTFILES.in create mode 100644 test/Fido_Sample_RPM/po/de_DE.po create mode 100644 test/Fido_Sample_RPM/po/el_GR.po create mode 100644 test/Fido_Sample_RPM/po/en.po create mode 100644 test/Fido_Sample_RPM/po/es_ES.po create mode 100644 test/Fido_Sample_RPM/po/fr_FR.po create mode 100644 test/Fido_Sample_RPM/po/hello-efl.pot create mode 100644 test/Fido_Sample_RPM/po/it_IT.po create mode 100644 test/Fido_Sample_RPM/po/ja_JP.po create mode 100644 test/Fido_Sample_RPM/po/ko_KR.po create mode 100644 test/Fido_Sample_RPM/po/nl_NL.po create mode 100644 test/Fido_Sample_RPM/po/pt_PT.po create mode 100644 test/Fido_Sample_RPM/po/ru_RU.po create mode 100644 test/Fido_Sample_RPM/po/tr_TR.po create mode 100644 test/Fido_Sample_RPM/po/update-po.sh create mode 100644 test/Fido_Sample_RPM/po/zh_CN.po create mode 100644 test/Fido_Sample_RPM/po/zh_HK.po create mode 100644 test/Fido_Sample_RPM/po/zh_TW.po create mode 100644 test/Fido_Sample_RPM/res/auth_req.json create mode 100644 test/Fido_Sample_RPM/res/dereg_req.json create mode 100644 test/Fido_Sample_RPM/res/reg_req.json create mode 100755 test/Fido_Sample_RPM/src/main.c create mode 100644 test/shell_tc/CMakeLists.txt create mode 100644 test/shell_tc/fido_shell_tc.c create mode 100644 test/shell_tc/fido_shell_tc_util.c create mode 100644 test/shell_tc/fido_shell_tc_util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..080e5b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.config +*.creator +*.user +*.files +*.includes diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9ace45f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(fido-client C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "\${prefix}") +SET(LIBDIR "\${prefix}/lib") +SET(INCLUDEDIR "\${prefix}/include ") +SET(VERSION_MAJOR 0) +SET(VERSION "${VERSION_MAJOR}.0.1") + +ADD_SUBDIRECTORY(client) +ADD_SUBDIRECTORY(fido_svc_ui) +ADD_SUBDIRECTORY(server) +ADD_DEPENDENCIES(fido-service fido-ui-service) +#INSTALL(DIRECTORY lib/fido/asm/ DESTINATION lib/fido/asm/) +ADD_SUBDIRECTORY(test/Dummy_ASM_DBUS) +ADD_SUBDIRECTORY(test/Fido_Sample_RPM) +ADD_SUBDIRECTORY(test/shell_tc) diff --git a/LICENSE.Apache-2.0 b/LICENSE.Apache-2.0 new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE.Apache-2.0 @@ -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/NOTICE b/NOTICE new file mode 100755 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000..b8e4f66 --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,61 @@ + +SET(CLIENT_SRCS + fido_uaf_client.c + fido_uaf_authenticator.c + ../common/fido_json_handler.c + ../common/fido_b64_util.c + ../common/fido_tlv_util.c + ../common/fido_uaf_utils.c +) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/common) + +INCLUDE(FindPkgConfig) +pkg_check_modules(CLIENT_PKGS REQUIRED + dlog + glib-2.0 + gio-unix-2.0 + capi-base-common + json-glib-1.0 + openssl +) + +FOREACH(flag ${CLIENT_PKGS_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror") +SET(CMAKE_LDFLAGS "-Wl,-zdefs") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"") +ADD_DEFINITIONS("-DSLP_DEBUG") + +ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_SOURCE_DIR}/common/fido-stub.c ${CMAKE_SOURCE_DIR}/common/fido-stub.h +WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/common/ +COMMAND gdbus-codegen --interface-prefix org.tizen. --generate-c-code fido-stub ${CMAKE_SOURCE_DIR}/common/dbus_interfaces/fido.xml +COMMENT "Generating FIDO GDBus stubs........................") + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${CLIENT_SRCS} ${CMAKE_SOURCE_DIR}/common/fido-stub.c) +ADD_DEPENDENCIES(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/common/fido-stub.h) +ADD_DEPENDENCIES(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/common/fido-stub.c) + +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CLIENT_PKGS_LDFLAGS}) + +#CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) + +##INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib/fido) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib) +#INSTALL(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig) + +INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/fido.h DESTINATION include) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/fido_uaf_authenticator.h DESTINATION include) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/fido_uaf_client.h DESTINATION include) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/common/fido_uaf_types.h DESTINATION include) + +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/client/${PROJECT_NAME}.pc.in ${CMAKE_SOURCE_DIR}/client/${PROJECT_NAME}.pc @ONLY) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/client/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig) diff --git a/client/fido-client.pc.in b/client/fido-client.pc.in new file mode 100644 index 0000000..92ba8eb --- /dev/null +++ b/client/fido-client.pc.in @@ -0,0 +1,13 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: fido-client +Description: Tizen FIDO Client +Version: @VERSION@ +#Requires: capi-base-common +Libs: -L${libdir} -lfido-client +Cflags: -I${includedir} diff --git a/client/fido_uaf_authenticator.c b/client/fido_uaf_authenticator.c new file mode 100755 index 0000000..9d48020 --- /dev/null +++ b/client/fido_uaf_authenticator.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include "fido_internal_types.h" +#include "fido_uaf_authenticator.h" +#include "fido_logs.h" + +EXPORT_API int +fido_authenticator_get_title(const fido_authenticator_h auth, char **title) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + RET_IF_FAIL(title != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + RET_IF_FAIL(priv->title != NULL, FIDO_ERROR_INVALID_PARAMETER); + + *title = strdup(priv->title); + + RET_IF_FAIL(title == NULL, FIDO_ERROR_OUT_OF_MEMORY); + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_aaid(const fido_authenticator_h auth, char **aaid) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + RET_IF_FAIL(aaid != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + RET_IF_FAIL(priv->aaid != NULL, FIDO_ERROR_INVALID_PARAMETER); + + *aaid = strdup(priv->aaid); + + RET_IF_FAIL(aaid == NULL, FIDO_ERROR_OUT_OF_MEMORY); + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_description(const fido_authenticator_h auth, char **desc) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + RET_IF_FAIL(desc != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + RET_IF_FAIL(priv->description != NULL, FIDO_ERROR_INVALID_PARAMETER); + + *desc = strdup(priv->description); + + RET_IF_FAIL(desc == NULL, FIDO_ERROR_OUT_OF_MEMORY); + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_assertion_scheme(const fido_authenticator_h auth, char **scheme) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + RET_IF_FAIL(scheme != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + RET_IF_FAIL(priv->assertion_scheme != NULL, FIDO_ERROR_INVALID_PARAMETER); + + *scheme = strdup(priv->assertion_scheme); + + RET_IF_FAIL(scheme == NULL, FIDO_ERROR_OUT_OF_MEMORY); + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_algorithm(const fido_authenticator_h auth, fido_auth_algo_e *algo) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + *algo = priv->authentication_algorithm; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_foreach_attestation_type(const fido_authenticator_h auth, fido_attestation_type_cb cb, +void *user_data) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + if (priv->attestation_types == NULL + || g_list_length(priv->attestation_types) <= 0) + return FIDO_ERROR_NO_DATA; + + GList *list_iter = g_list_first(priv->attestation_types); + while (list_iter != NULL) { + int att_type = GPOINTER_TO_INT(list_iter->data); + + (cb)(att_type, user_data); + + list_iter = list_iter->next; + } + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_verification_method(const fido_authenticator_h auth, fido_auth_user_verify_type_e *user_verification) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + *user_verification = priv->user_verification; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_key_protection_method(const fido_authenticator_h auth, fido_auth_key_protection_type_e *key_protection) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + *key_protection = priv->key_protection; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_matcher_protection_method(const fido_authenticator_h auth, fido_auth_matcher_protection_type_e *matcher_protection) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + *matcher_protection = priv->matcher_protection; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_attachment_hint(const fido_authenticator_h auth, fido_auth_attachment_hint_e *attachment_hint) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + *attachment_hint = priv->attachment_hint; + + return FIDO_ERROR_NONE; +} + +EXPORT_API bool +fido_authenticator_get_is_second_factor_only(const fido_authenticator_h auth) +{ + RET_IF_FAIL(auth != NULL, false); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + return priv->is_second_factor_only; +} + +EXPORT_API int +fido_authenticator_get_tc_discplay(const fido_authenticator_h auth, fido_auth_tc_display_type_e *tc_display) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + *tc_display = priv->tc_display; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_tc_display_type(const fido_authenticator_h auth, char **tc_display_content_type) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + RET_IF_FAIL(tc_display_content_type != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + RET_IF_FAIL(priv->tc_display_content_type != NULL, FIDO_ERROR_INVALID_PARAMETER); + + *tc_display_content_type = strdup(priv->tc_display_content_type); + + RET_IF_FAIL(tc_display_content_type == NULL, FIDO_ERROR_OUT_OF_MEMORY); + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_authenticator_get_icon(const fido_authenticator_h auth, char **icon) +{ + RET_IF_FAIL(auth != NULL, FIDO_ERROR_INVALID_PARAMETER); + + RET_IF_FAIL(icon != NULL, FIDO_ERROR_INVALID_PARAMETER); + + fido_authenticator_s *priv = (fido_authenticator_s*)auth; + + RET_IF_FAIL(priv->icon != NULL, FIDO_ERROR_INVALID_PARAMETER); + + *icon = strdup(priv->icon); + + RET_IF_FAIL(icon == NULL, FIDO_ERROR_OUT_OF_MEMORY); + + return FIDO_ERROR_NONE; +} + diff --git a/client/fido_uaf_client.c b/client/fido_uaf_client.c new file mode 100755 index 0000000..8500b60 --- /dev/null +++ b/client/fido_uaf_client.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include + +#include "fido_uaf_client.h" +#include "fido_logs.h" +#include "fido_internal_types.h" +#include "fido_json_handler.h" +#include "fido-stub.h" +#include "fido_keys.h" +#include "fido_uaf_authenticator.h" + +static Fido *_fido_dbus_obj = NULL; + +typedef struct _fido_process_cb_data { + fido_uaf_response_message_cb cb; + void *user_data; +} _fido_process_cb_data_s; + + +static void +init_dbus(void) +{ + _INFO("init_dbus"); +#if !GLIB_CHECK_VERSION(2,35,0) + g_type_init(); +#endif + + GDBusConnection *connection = NULL; + GError *error = NULL; + + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + _INFO("after g_bus_get_sync"); + + + /* Create the object */ + _fido_dbus_obj = fido_proxy_new_sync(connection, + G_DBUS_PROXY_FLAGS_NONE, + _FIDO_DBUS_NAME, + _FIDO_DBUS_PATH, + NULL, + &error); +} + +Fido * +_dbus_proxy_get_instance(int time_out) +{ + _INFO("_dbus_proxy_get_instance singleton"); + + static pthread_once_t onceBlock = PTHREAD_ONCE_INIT; + if (_fido_dbus_obj == NULL) { + pthread_once(&onceBlock, init_dbus); + if (_fido_dbus_obj == NULL) { + _ERR("init_dbus failed"); + onceBlock = PTHREAD_ONCE_INIT; + } + } + _INFO("_dbus_proxy_get_instance end"); + + g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(_fido_dbus_obj), time_out); + + return _fido_dbus_obj; +} + +static void +_fido_uaf_process_operation_reply(GObject *object, GAsyncResult *res, gpointer user_data) +{ + _INFO("_fido_uaf_process_operation_reply"); + + GError *dbus_err = NULL; + + if (user_data == NULL) { + _ERR("Can not proceed since callback data is NULL"); + return; + } + + _fido_process_cb_data_s *cb_data = (_fido_process_cb_data_s *)user_data; + if (cb_data == NULL) { + _ERR("Can not proceed since callback data is NULL"); + return; + } + + if (cb_data->cb == NULL) { + _ERR("Can not proceed since callback data's cb part is NULL"); + SAFE_DELETE(cb_data); + return; + } + + int tizen_err = FIDO_ERROR_NONE; + + char *uaf_response_json = NULL; + + fido_call_fido_uaf_process_operation_finish(_fido_dbus_obj, &tizen_err, &uaf_response_json, + res, &dbus_err); + + if (dbus_err) { + _ERR("fido_foreach_authenticator failed [%s]", dbus_err->message); + if (tizen_err == FIDO_ERROR_NONE) + tizen_err = FIDO_ERROR_PERMISSION_DENIED; + /* Error is notified via tizen_err and/or fido_err, so no need to get dbus error*/ + } + + g_clear_error(&dbus_err); + + if (strcmp(uaf_response_json, _EMPTY_JSON_STRING) == 0) + (cb_data->cb)(tizen_err, NULL, cb_data->user_data); + else + (cb_data->cb)(tizen_err, uaf_response_json, cb_data->user_data); + + _INFO("After calling fido_uaf_response_message_cb"); + + SAFE_DELETE(cb_data); + SAFE_DELETE(uaf_response_json); +} + +EXPORT_API int +fido_foreach_authenticator(fido_authenticator_cb callback, void *user_data) +{ + if (callback == NULL) { + _ERR("callback can not be NULL [FIDO_ERROR_INVALID_PARAMETER]"); + return FIDO_ERROR_INVALID_PARAMETER; + } + + Fido *dbus_proxy = _dbus_proxy_get_instance(_DBUS_TIMEOUT_USE_DEFAULT); + if (dbus_proxy == NULL) { + _ERR("DBus proxy failed"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + gchar **discovery_data_json = NULL; + int discovery_data_json_list_len = 0; + int tz_err = 0; + GError *dbus_err = NULL; + fido_call_fido_uaf_discover_sync(dbus_proxy, &tz_err, &discovery_data_json, &discovery_data_json_list_len, + NULL, &dbus_err); + + + if (dbus_err != NULL) { + _ERR("fido_call_fido_uaf_discover_sync failed [%s]", dbus_err->message); + g_clear_error(&dbus_err); + + return FIDO_ERROR_PERMISSION_DENIED; + } + + if (discovery_data_json == NULL || discovery_data_json_list_len <= 0) { + _ERR("No Authenticators found"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + _INFO("ASM response len =[%d]", discovery_data_json_list_len); + + tz_err = FIDO_ERROR_NONE; + + int parser_err = 0; + GList *auth_list = _uaf_parser_parse_asm_response_discover_client(discovery_data_json, + discovery_data_json_list_len, &parser_err); + if (parser_err != FIDO_ERROR_NONE) { + tz_err = _convert_asm_status_code_to_uaf_error(parser_err); + } + else { + + if (g_list_length(auth_list) <= 0) { + tz_err = FIDO_ERROR_NOT_SUPPORTED; + } + else { + + GList *auth_list_iter = g_list_first(auth_list); + while (auth_list_iter != NULL) { + + fido_authenticator_s *auth_priv = (fido_authenticator_s *)(auth_list_iter->data); + (callback)((fido_authenticator_h)auth_priv, user_data); + auth_list_iter = auth_list_iter->next; + } + } + } + + int i = 0; + for (; i < discovery_data_json_list_len; i++) + SAFE_DELETE(discovery_data_json[i]); + + SAFE_DELETE(discovery_data_json); + + /*Items are deleted after callback is done for elements, so apps must make a local copy of elements if they + want to use them later*/ + g_list_free_full(auth_list, _free_asm_auth_list); + + return tz_err; +} + +EXPORT_API int +fido_get_client_vendor(char **vendor_name) +{ + if (vendor_name == NULL) + return FIDO_ERROR_INVALID_PARAMETER; + + char *vn_temp = (char*)calloc(1, _CLIENT_VENDOR_NAME_MAX_SIZE + 1); + strncpy(vn_temp, _CLIENT_VENDOR_NAME, _CLIENT_VENDOR_NAME_MAX_SIZE); + + *vendor_name = vn_temp; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_get_client_version(int *client_major_version, int *client_minor_version) +{ + if ((client_major_version == NULL) || (client_minor_version == NULL)) + return FIDO_ERROR_INVALID_PARAMETER; + + *client_major_version = _CLIENT_VERSION_MAJOR; + *client_minor_version = _CLIENT_VERSION_MINOR; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_uaf_is_supported(const char *uaf_message_json, bool *is_supported) +{ + if (uaf_message_json == NULL) { + _ERR("uaf_message_json can not be NULL [FIDO_ERROR_INVALID_PARAMETER]"); + return FIDO_ERROR_INVALID_PARAMETER; + } + + Fido *dbus_proxy = _dbus_proxy_get_instance(_DBUS_TIMEOUT_USE_DEFAULT); + if (dbus_proxy == NULL) { + _ERR("DBus proxy failed"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + int tz_err = FIDO_ERROR_NONE; + GError *dbus_err = NULL; + fido_call_fido_uaf_check_policy_sync(dbus_proxy, uaf_message_json, &tz_err, + NULL, &dbus_err); + + if (dbus_err != NULL) { + _ERR("fido_call_fido_uaf_check_policy_sync failed [%s]", dbus_err->message); + g_clear_error(&dbus_err); + return FIDO_ERROR_PERMISSION_DENIED; + } + + if (tz_err == FIDO_ERROR_NONE) + *is_supported = true; + else + *is_supported = false; + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_uaf_get_response_message(const char *uaf_request_json, const char *channel_binding_json, + fido_uaf_response_message_cb callback, void *user_data) +{ + if (callback == NULL) { + _ERR("callback can not be NULL [FIDO_ERROR_INVALID_PARAMETER]"); + return FIDO_ERROR_INVALID_PARAMETER; + } + if (uaf_request_json == NULL) { + _ERR("uaf_request_json can not be NULL [FIDO_ERROR_INVALID_PARAMETER]"); + return FIDO_ERROR_INVALID_PARAMETER; + } + + Fido *dbus_proxy = _dbus_proxy_get_instance(_DBUS_TIMEOUT_INFINITE); + if (dbus_proxy == NULL) { + _ERR("DBus proxy failed"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + _fido_process_cb_data_s *cb_data = (_fido_process_cb_data_s *) calloc(1, sizeof(_fido_process_cb_data_s)); + cb_data->cb = callback; + cb_data->user_data = user_data; + + if (channel_binding_json != NULL) { + fido_call_fido_uaf_process_operation(dbus_proxy, uaf_request_json, channel_binding_json, + NULL, _fido_uaf_process_operation_reply, cb_data); + } + else { + fido_call_fido_uaf_process_operation(dbus_proxy, uaf_request_json, + _FIDO_NO_CHANNEL_BINDING_DBUS_STRING, + NULL, _fido_uaf_process_operation_reply, cb_data); + } + + return FIDO_ERROR_NONE; +} + +EXPORT_API int +fido_uaf_set_server_result(int response_code, const char *uaf_response_json) +{ + if (uaf_response_json == NULL) { + _ERR("uaf_response_json can not be NULL [FIDO_ERROR_INVALID_PARAMETER]"); + return FIDO_ERROR_INVALID_PARAMETER; + } + + Fido *dbus_proxy = _dbus_proxy_get_instance(_DBUS_TIMEOUT_USE_DEFAULT); + if (dbus_proxy == NULL) { + _ERR("DBus proxy failed"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + GError *dbus_err = NULL; + + int tizen_error_code = FIDO_ERROR_NONE; + + _response_t *uaf_res_data = _uaf_parser_parse_uaf_response(uaf_response_json); + if (uaf_res_data == NULL) + return FIDO_ERROR_PROTOCOL_ERROR; + + if (response_code == FIDO_SERVER_STATUS_CODE_OK) { + _free_response(uaf_res_data); + return FIDO_ERROR_NONE; + } + + + _INFO("before checking operation name"); + if (strcmp(uaf_res_data->header->operation, _UAF_OPERATION_NAME_KEY_REG) != 0) { + _free_response(uaf_res_data); + return FIDO_ERROR_NONE; + } + + /*Only for reg response, if not success code, then delete the reg*/ + + _INFO("before calling _uaf_composer_compose_dereg_request"); + char *uaf_dereg_json = _uaf_composer_compose_dereg_request(uaf_res_data); + + _free_response(uaf_res_data); + + if (uaf_dereg_json == NULL) + return FIDO_ERROR_PROTOCOL_ERROR; + + int tz_err = FIDO_ERROR_NONE; + char *resp = 0; + + GError *err = NULL; + gboolean is_success = fido_call_fido_uaf_process_operation_sync(dbus_proxy, + uaf_dereg_json, + _FIDO_NO_CHANNEL_BINDING_DBUS_STRING, &tz_err, + &resp, NULL, &err); + + if (is_success == FALSE) { + _ERR("fido_call_fido_uaf_notify_result_sync failed [%d]", tizen_error_code); + if (dbus_err) { + _ERR("GError = [%s]", dbus_err->message); + } + return FIDO_ERROR_PROTOCOL_ERROR; + } + + return tz_err; +} diff --git a/common/dbus_interfaces/dummyasm.xml b/common/dbus_interfaces/dummyasm.xml new file mode 100644 index 0000000..a54a108 --- /dev/null +++ b/common/dbus_interfaces/dummyasm.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/common/dbus_interfaces/fido.xml b/common/dbus_interfaces/fido.xml new file mode 100644 index 0000000..912ad15 --- /dev/null +++ b/common/dbus_interfaces/fido.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/fido_b64_util.c b/common/fido_b64_util.c new file mode 100644 index 0000000..914e66e --- /dev/null +++ b/common/fido_b64_util.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include + #include + +#include "fido_logs.h" +#include "fido_internal_types.h" +#include "fido_b64_util.h" + +int +_fido_b64url_encode(const unsigned char *input, int inlen, unsigned char *output, int *outlen) +{ + _INFO("_fido_b64url_encode start"); + + BIO * bmem = NULL; + BIO * b64 = NULL; + BUF_MEM * bptr = NULL; + b64 = BIO_new(BIO_f_base64()); + if(b64 == NULL) { + _ERR("BIO_new with BIO_f_base64 failed "); + return -1; + } + + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + bmem = BIO_new(BIO_s_mem()); + b64 = BIO_push(b64, bmem); + BIO_write(b64, input, inlen); + BIO_flush(b64); + BIO_get_mem_ptr(b64, &bptr); + + memcpy(output, bptr->data, bptr->length); + output[bptr->length] = 0; + *outlen = bptr->length; + + int i; + for(i =0; i < *outlen ; i++) { + if(output[i] == '+') + output[i] = '-'; + + else if(output[i] == '/') + output[i] = '_'; + + else if(output[i] == '=') { + *outlen = i ; + output[i] = '\0'; + break; + } + } + + BIO_free_all(b64); + + _INFO("%s", output); + _INFO("_fido_b64url_encode end"); + + return 0; +} + +int +_fido_b64url_decode(const unsigned char *in, int inlen, + unsigned char *out, int *outlen) +{ + _INFO("_fido_b64url_decode start"); + + int npadChars = (inlen %4) == 0 ? 0 : (4 - (inlen%4)); + unsigned char *base64 = (unsigned char *) malloc(inlen + npadChars); + if(base64 == NULL) { + _ERR("malloc failed"); + return -1; + } + + memcpy(base64, in, inlen); + + int i; + for(i =0; i < inlen ; i++) { + if(base64[i] == '-') + base64[i] = '+'; + + else if(base64[i] == '_') + base64[i] = '/'; + + } + + if(npadChars != 0) + memset(base64 + inlen, '=', npadChars); + + BIO * b64 = NULL; + BIO * bmem = NULL; + b64 = BIO_new(BIO_f_base64()); + if(b64 == NULL) { + _ERR("BIO_new with BIO_f_base64 failed"); + + SAFE_DELETE(base64); + return -1; + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bmem = BIO_new_mem_buf(base64, inlen); + if(bmem == NULL) { + _ERR("BIO_new_mem_buf failed"); + + SAFE_DELETE(base64); + return -1; + } + + bmem = BIO_push(b64, bmem); + *outlen = BIO_read(bmem, out, inlen); + if(*outlen <= 0) { + _ERR("BIO_read failed"); + + SAFE_DELETE(base64); + return -1; + } + + if(bmem) + BIO_free_all(bmem); + + _INFO("_fido_b64url_decode end"); + + return 0; +} diff --git a/common/fido_b64_util.h b/common/fido_b64_util.h new file mode 100644 index 0000000..c5ffbc4 --- /dev/null +++ b/common/fido_b64_util.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef _FIDO_B64_UTIL_H +#define _FIDO_B64_UTIL_H + +#include +#include + +int _fido_b64url_encode(const unsigned char *input, int inlen, unsigned char *output, int *outlen); + +int _fido_b64url_decode(const unsigned char *in, int inlen, unsigned char *out, int *outlen); + +#endif diff --git a/common/fido_internal_types.h b/common/fido_internal_types.h new file mode 100644 index 0000000..90dac32 --- /dev/null +++ b/common/fido_internal_types.h @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_INTERNAL_TYPES_H +#define FIDO_INTERNAL_TYPES_H + +#include +#include +#include +#include +#include +#include "fido_uaf_types.h" + +#define RET_IF_FAIL_VOID(cond) do {\ + if (!(cond)){\ + return;\ + }\ +} while(0) + +#define RET_IF_FAIL(cond, err) do {\ + if (!(cond)){\ + return err;\ + }\ +} while(0) + +#define CATCH_IF_FAIL(cond) do {\ + if (!(cond)){\ + goto CATCH;\ + }\ +} while(0) + +#define CATCH_IF_FAIL_X(cond, expr) do {\ + if (!(cond)){\ + expr;\ + goto CATCH;\ + }\ +} while(0) + +#define GOTO_IF_FAIL(cond, catch_block) do {\ + if (!(cond)){\ + goto catch_block;\ + }\ +} while(0) + +#define SAFE_DELETE(x) do {\ + if (x != NULL) {\ + free(x); \ + x = NULL;\ + }\ +} while(0) + +#define _SAFE_DUP(x) ((x) ? strdup(x) : NULL) + +/* UAF API structures start */ +/** + * @brief UAF version structure. + * @since_tizen 3.0 + */ +typedef struct _fido_version_s { + int major;/** Major version **/ + int minor;/** Minor version **/ +} fido_version_s; + +typedef struct _fido_rgb_pallette_entry_s { + unsigned short r;/** Red component**/ + unsigned short g;/** Green component**/ + unsigned short b;/** Blue component**/ +} fido_rgb_pallette_entry_s; + +typedef struct _fido_display_png_characteristics_descriptor_s { + unsigned long width;/** Width**/ + unsigned long height;/** Height**/ + uint8_t bit_depth;/** Bit depth**/ + uint8_t color_type;/** Color type**/ + uint8_t compression;/** Compression**/ + uint8_t filter;/** Filter**/ + uint8_t interlace;/** Interlace**/ + GList *plte;/** Pallete entry list of type @c List of @c fido_rgb_pallette_entry_t elements **/ +} fido_display_png_characteristics_descriptor_s; + +void _free_display_png_characteristics_descriptor(fido_display_png_characteristics_descriptor_s *data); + + +/* UAF API structures end */ + + +typedef struct _version { + int major; + int minor; +} _version_t; + +typedef struct _extension { + char *id; + char *data; + bool fail_if_unknown; +} _extension_t; + +void _free_extension(_extension_t *data); + +typedef struct _match_criteria { + GList *aaid_list; + GList *vendor_list; + GList *key_id_list; + long long int user_verification; + int key_protection; + int matcher_protection; + long long int attachement_hint; + int tc_display; + GList *auth_algo_list; + GList *assertion_scheme_list; + GList *attestation_type_list; + int auth_version; + GList *extension_list; + +} _match_criteria_t; + +void _free_match_criteria(_match_criteria_t *data); + +typedef struct _policy { + GList *accepted_list;//2d array + GList *disallowed_list; + bool is_keyid_present; /*Only call GetRegistrations ASM call if atleast one match criteria contains keyIDs*/ +} _policy_t; + +void _free_policy(_policy_t *data); + +typedef struct _op_header { + _version_t *version; + char *operation; + char *app_id; + char *server_data; + GList *ext_list; +}_op_header_t; + +void _free_op_header(_op_header_t *data); + +typedef enum { + _MESSAGE_TYPE_MIN = -1, + _MESSAGE_TYPE_REG, + _MESSAGE_TYPE_AUTH, + _MESSAGE_TYPE_DEREG, + _MESSAGE_TYPE_MAX +}_message_type_e; + +typedef struct _message { + char *facet_id; + _op_header_t *header; + char *channel_binding; + _message_type_e type; + void *data;/* type can be _reg_request_t / _auth_request_t / _dereg_request_t depending on header->operation */ +} _message_t; + +void _free_message(_message_t *data); + +typedef struct _reg_request { + char *challenge; + char *user_name; + _policy_t *policy; +} _reg_request_t; + +void _free_reg_request(_reg_request_t *data); + +typedef struct _auth_transaction { + char *content_type; + char *content; + fido_display_png_characteristics_descriptor_s *display_charac; +}_auth_transaction_t; + +void _free_auth_transaction(_auth_transaction_t *data); + +typedef struct _auth_request { + char *challenge; + GList *transaction_list; + _policy_t *policy; +} _auth_request_t; + +void _free_auth_request(_auth_request_t *data); + +typedef struct _dereg_auth_info { + char *aaid; + char *key_id; +} _dereg_auth_info_t; + +void _free_dereg_auth_info(_dereg_auth_info_t *data); + +typedef struct _dereg_request { + GList *auth_info_list; +} _dereg_request_t; + +void _free_dereg_request(_dereg_request_t *data); + +typedef struct _fido_asm_version { + int major; + int minor; +} _fido_asm_version_t; + + +typedef struct _fido_asm_rgb_pallette_entry { + unsigned short r; + unsigned short g; + unsigned short b; +} _fido_asm_rgb_pallette_entry_t; + + +typedef struct _fido_asm_display_png_characteristics_descriptor { + unsigned long width; + unsigned long height; + int bit_depth; + int color_type; + int compression; + int filter; + int interlace; + GList *plte; +} _fido_asm_display_png_characteristics_descriptor_t; + +void _free_asm_display_png_characteristics_descriptor_t(_fido_asm_display_png_characteristics_descriptor_t *data); + +typedef struct _fido_asm_proxy { + char *asm_id; + char *vendor; + char *bin_path; + char *dbus_info; + char *dbus_obj_path; + char *dbus_interface_name; + char *dbus_method_name; + GDBusProxy *dbus_proxy; +} _fido_asm_proxy_t; + +void _free_fido_asm_proxy(void *data); + +typedef struct _asm_discover_response { + int error_code; + char *asm_id; + char *asm_response_json; +} _asm_discover_response_t; + +void _free_asm_discover_response(_asm_discover_response_t *data); + +typedef struct _fido_asm_authenticator { + GList *supported_versions; + char *asm_id; + char *auth_index; + GList *key_ids;//filled up from GetRegistrations request to ASM + GList *asm_versions; + bool is_user_enrolled; + bool has_settings; + char *aaid; + char *assertion_scheme; + int authentication_algorithm; + GList *attestation_types; + unsigned long user_verification; + int key_protection; + int matcher_protection; + unsigned long attachment_hint; + bool is_second_factor_only; + bool is_roaming; + GList *supported_extension_IDs; + int tc_display; + char *tc_display_content_type; + GList *tc_display_png_characteristics; + char *title; + char *description; + char *icon; +} fido_authenticator_s; + +void _free_fido_asm_authenticator(fido_authenticator_s *data); +void _free_fido_asm_authenticator_list_item(gpointer data); + +typedef struct _fido_asm_reg_in { + char *app_id; + char *user_name; + char *final_challenge; + int attestation_type; +}_fido_asm_reg_in_t; + +void _free_fido_asm_reg_in(_fido_asm_reg_in_t *data); + +typedef struct _fido_asm_transaction { + char *content_type; + char *content; + _fido_asm_display_png_characteristics_descriptor_t *display_charac; +}_fido_asm_transaction_t; + +void _free_fido_asm_transaction(_fido_asm_transaction_t *data); + +typedef struct _fido_asm_auth_in { + char *app_id; + GList *key_ids; + char *final_challenge; + GList *trans_list;//_fido_asm_transaction_t list +}_fido_asm_auth_in_t; + +void _free_fido_asm_auth_in(_fido_asm_auth_in_t *data); + +typedef struct _fido_asm_dereg_in { + char *app_id; + char *key_id; +}_fido_asm_dereg_in_t; + +void _free_fido_asm_dereg_in(_fido_asm_dereg_in_t *data); + +/* client sends list of this type to ui adaptor*/ +typedef struct _ui_auth_data { + char *asm_id; + char *auth_index; + char *label; + int att_type; +} _ui_auth_data_t; + +void _free_ui_auth_data(_ui_auth_data_t *data); + +typedef struct _auth_reg_assertion { + char *assertion_schm; + char *assertion; + //GList *tc_disp_char_list; + //GList *ext_list; +} _auth_reg_assertion_t; + +void _free_auth_reg_assertion(_auth_reg_assertion_t *data); +void _free_auth_reg_assertion_list_item(gpointer data); + +typedef enum { + _ASM_OUT_TYPE_MIN = -1, + _ASM_OUT_TYPE_REG, + _ASM_OUT_TYPE_AUTH, + _ASM_OUT_TYPE_MAX +}_asm_out_type_e; + +typedef struct _asm_out { + int status_code; + _asm_out_type_e type; + void *response_data;/*type can be : _asm_reg_out_t, _asm_auth_out_t*/ + GList *ext_list; +}_asm_out_t; + +void _free_asm_out(_asm_out_t *data); + +typedef struct _asm_reg_out { + char *assertion; + char *assertion_schm; +} _asm_reg_out_t; + +void _free_asm_reg_out(_asm_reg_out_t *data); + +typedef struct _asm_auth_out { + char *assertion; + char *assertion_scheme; +} _asm_auth_out_t; + +void _free_asm_auth_out(_asm_auth_out_t *data); + +typedef struct _matched_auth_data { + char *asm_id; + char *auth_index; + int att_type; + char *label; + GList *key_ids; +} _matched_auth_data_t; + +void _free_matched_auth_data(gpointer data); + +typedef struct _matched_auth_dereg { + char *asm_id; + char *auth_index; + char *app_id; + char *key_id; +} _matched_auth_dereg_t; + +void _free_matched_auth_dereg(_matched_auth_dereg_t *data); + +typedef struct _asm_dereg_out { + int status_code; /* 0 signifies success.*/ +} _asm_dereg_out_t; + +typedef struct _asm_app_reg { + char *app_id; + GList *key_id_list; +} _asm_app_reg_t; + +void _free_asm_app_reg(_asm_app_reg_t *data); + +typedef struct _asm_get_reg_out { + int status_code; + GList *app_reg_list;/*_asm_app_reg_t list*/ +} _asm_get_reg_out_t; + +void _free_asm_get_reg_out(_asm_get_reg_out_t *data); + +typedef struct _dereg_q { + GQueue *dereg_asm_in_q; + void *cb_data; +} _dereg_q_t; + +typedef void (*_fido_discover_asm_cb) (int tz_error_code, int fido_error_code, GList *asm_auth_info_list, void *user_data); + +typedef struct __attribute__((packed)) _tlv { + uint16_t type; + uint16_t len; + uint8_t *val; +} _tlv_t; + +void _free_tlv(_tlv_t *data); + +typedef struct _auth_reg_assertion_tlv { + char *aaid; + unsigned char *key_id; + int key_id_len; +}_auth_reg_assertion_tlv_t; + +void _free_auth_reg_assertion_tlv(_auth_reg_assertion_tlv_t *data); + +typedef struct _response_ { + _op_header_t *header; + char *fcp; + GList *assertion_list; +}_response_t; + +void _free_response(_response_t *data); + +typedef enum { + _DBUS_OP_TYPE_INIT, + _DBUS_OP_TYPE_DE_INIT, + _DBUS_OP_TYPE_DISCOVER, + _DBUS_OP_TYPE_CHECK_POLICY, + _DBUS_OP_TYPE_PROCESS, + _DBUS_OP_TYPE_NOTIFY +} _dbus_op_type_e; + +typedef enum { + _ASM_STATUS_OK = 0x00, + _ASM_STATUS_ERROR = 0x01, + _ASM_STATUS_ACCESS_DENIED = 0x02, + _ASM_STATUS_USER_CANCELLED = 0x03 +} _asm_status_e; + +void _free_tc_disp_png_char(gpointer data); + +void _free_asm_auth_list(gpointer data); + +#define _CLIENT_VENDOR_NAME_MAX_SIZE 127 +#define _CLIENT_VENDOR_NAME "samsung" +#define _CLIENT_VERSION_MAJOR 1 +#define _CLIENT_VERSION_MINOR 0 + +#define _VERSION_MAJOR 1 +#define _VERSION_MINOR 0 + +#define _INVALID_INT -1 + +#define _GET_INFO_ASM_REQUEST_JSON "{\"asmVersion\":{\"major\":1,\"minor\":0},\"requestType\":\"GetInfo\"}" + +#define UI_DATA_ASM_ID "asm_id" +#define UI_DATA_AUTH_INDEX "auth" +#define UI_DATA_LABEL "label" +#define UI_DATA_ATT_TYPE "att" + +#define _FIDO_DBUS_NAME "org.tizen.fido" +#define _FIDO_DBUS_PATH "/org/tizen/fido" + +#define _FIDO_NO_CHANNEL_BINDING_DBUS_STRING "empty_channel_binding" +#define _FIDO_CID_KEY_UNUSED "unused" + +#define _DBUS_TIMEOUT_INFINITE G_MAXINT +#define _DBUS_TIMEOUT_USE_DEFAULT -1 + +#define _EMPTY_JSON_STRING "{}" + +#define _UI_IPC_KEY_REQ "ui_rq" + +#define _UI_SVC_PACKAGE "org.tizen.fidosvcui" +#define _UI_SVC_BIN_PATH "/usr/apps/org.tizen.fidosvcui/bin/org.tizen.fidosvcui" + +#endif // FIDO_INTERNAL_TYPES_H diff --git a/common/fido_json_handler.c b/common/fido_json_handler.c new file mode 100644 index 0000000..dfedb05 --- /dev/null +++ b/common/fido_json_handler.c @@ -0,0 +1,2280 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + + +#include +#include +#include +#include +#include +#if !GLIB_CHECK_VERSION (2, 31, 0) +#include +#endif +#include +#include "fido_internal_types.h" +#include "fido_json_handler.h" +#include "fido_keys.h" +#include "fido_logs.h" +#include "fido_uaf_types.h" +#include "fido_b64_util.h" +#include "fido_tlv_util.h" + +/*JSON keys start*/ +#define _JSON_KEY_ID "id" +#define _JSON_KEY_DATA "data" +#define _JSON_KEY_FAIL_IF_UNKNOWN "fail_if_unknown" +#define _JSON_KEY_EXTS "exts" +#define _JSON_KEY_UPV "upv" +#define _JSON_KEY_MAJOR "major" +#define _JSON_KEY_MINOR "minor" +#define _JSON_KEY_OP "op" +#define _JSON_KEY_APPID "appID" +#define _JSON_KEY_SERVER_DATA "serverData" +#define _JSON_KEY_AAID "aaid" +#define _JSON_KEY_VENDOR_ID "vendorID" +#define _JSON_KEY_KEY_IDS "keyIDs" +#define _JSON_KEY_USER_VERIFICATION "userVerification" +#define _JSON_KEY_KEY_PROTECTION "keyProtection" +#define _JSON_KEY_MATCHER_PROTECTION "matcherProtection" +#define _JSON_KEY_ATTACHMENT_HINT "attachmentHint" +#define _JSON_KEY_TC_DISPLAY "tcDisplay" +#define _JSON_KEY_AUTH_ALGOS "authenticationAlgorithms" +#define _JSON_KEY_AUTH_ALGO "authenticationAlgorithm" +#define _JSON_KEY_ASSERT_SCHEMES "assertionSchemes" +#define _JSON_KEY_ATT_TYPES "attestationTypes" +#define _JSON_KEY_ATT_TYPE "attestationType" +#define _JSON_KEY_AUTH_VERSION "authenticatorVersion" +#define _JSON_KEY_PLTE "plte" +#define _JSON_KEY_R "r" +#define _JSON_KEY_G "g" +#define _JSON_KEY_B "b" +#define _JSON_KEY_WIDTH "width" +#define _JSON_KEY_HEIGHT "height" +#define _JSON_KEY_BIT_DEPTH "bitDepth" +#define _JSON_KEY_COLOR_TYPE "colorType" +#define _JSON_KEY_COMPRESSION "compression" +#define _JSON_KEY_FILTER "filter" +#define _JSON_KEY_INTERLACE "interlace" +#define _JSON_KEY_TC_DISP_PNG_CHARS "tcDisplayPNGCharacteristics" +#define _JSON_KEY_RESP_DATA "responseData" +#define _JSON_KEY_AUTHENTICATORS "Authenticators" +#define _JSON_KEY_AUTHENTICATORS_SMALL "authenticators" +#define _JSON_KEY_AUTH_INDEX "authenticatorIndex" +#define _JSON_KEY_IS_USER_ENROLLED "isUserEnrolled" +#define _JSON_KEY_HAS_SETTINGS "hasSettings" +#define _JSON_KEY_AAID "aaid" +#define _JSON_KEY_IS_2_FACTOR_ONLY "isSecondFactorOnly" +#define _JSON_KEY_IS_ROAMING_AUTH "isRoamingAuthenticator" +#define _JSON_KEY_SUPPORTED_EXT_IDS "supportedExtensionIDs" +#define _JSON_KEY_TC_DISP_CONTENT_TYPE "tcDisplayContentType" +#define _JSON_KEY_TITLE "title" +#define _JSON_KEY_DESC "description" +#define _JSON_KEY_ICON "icon" +#define _JSON_KEY_STATUS_CODE "statusCode" +#define _JSON_KEY_ASSERTION "assertion" +#define _JSON_KEY_ASSERT_SCHEME "assertionScheme" +#define _JSON_KEY_CHALLENGE "challenge" +#define _JSON_KEY_CH_BINDING "channelBinding" +#define _JSON_KEY_SERVER_END_POINT "serverEndPoint" +#define _JSON_KEY_TLS_SERVER_CERT "tlsServerCertificate" +#define _JSON_KEY_TLS_UNIQUE "tlsUnique" +#define _JSON_KEY_CID_PUB_KEY "cid_pubkey" +#define _JSON_KEY_FACET_ID "facetID" +#define _JSON_KEY_HEADER "header" +#define _JSON_KEY_FC_PARAMS "fcParams" +#define _JSON_KEY_FINAL_CHALLENGE "finalChallenge" +#define _JSON_KEY_ASSERTIONS "assertions" +#define _JSON_KEY_POLICY "policy" +#define _JSON_KEY_ACCEPTED "accepted" +#define _JSON_KEY_DISALLOWED "disallowed" +#define _JSON_KEY_USER_NAME "username" +#define _JSON_KEY_TRUSTED_FACETS "trustedFacets" +#define _JSON_KEY_VERSION "version" +#define _JSON_KEY_IDS "ids" +#define _JSON_KEY_APP_REGS "appRegs" +#define _JSON_KEY_REQ_TYPE "requestType" +#define _JSON_KEY_KEY_ID "keyID" +#define _JSON_KEY_TRANSACTION "transaction" +#define _JSON_KEY_CONTENT_TYPE "contentType" +#define _JSON_KEY_CONTENT "content" +#define _JSON_KEY_REGISTER "Register" +#define _JSON_KEY_AUTHENTICATE "Authenticate" +#define _JSON_KEY_DEREGISTER "Deregister" +#define _JSON_KEY_ASM_VERSION "asmVersion" +#define _JSON_KEY_GET_REGS "GetRegistrations" +#define _JSON_KEY_KTY "kty" +#define _JSON_KEY_CRV "crv" +#define _JSON_KEY_X "x" +#define _JSON_KEY_Y "y" +#define _JSON_KEY_ARGS "args" + +#define _JSON_KEY_VENDOR "vendor" +#define _JSON_KEY_BIN_PATH "bin_path" +#define _JSON_KEY_DBUS_INFO "dbus_info" +#define _JSON_KEY_DBUS_OBJ_PATH "dbus_obj_path" +#define _JSON_KEY_DBUS_INTF_NAME "dbus_interface_name" +#define _JSON_KEY_DBUS_METHOD_NAME "dbus_method_name" +/*JSON keys end*/ + +static void +__add_string_to_json_object(JsonBuilder *json_obj, const char *key, const char *val) +{ + if (key == NULL || val == NULL) + return; + + json_builder_set_member_name(json_obj, key); + json_builder_add_string_value(json_obj, val); +} + +static void +__add_int_to_json_object(JsonBuilder *json_obj, const char *key, int val) +{ + if (key == NULL || val == _INVALID_INT) + return; + + json_builder_set_member_name(json_obj, key); + json_builder_add_int_value(json_obj, val); +} + +static char* +__get_string_from_json_object(JsonObject *obj, const char *key) +{ + _INFO("__get_string_from_json_object [%s]", key); + + if (json_object_has_member(obj, key) == false) + return NULL; + + const char *str = json_object_get_string_member(obj, key); + _INFO("[%s] = [%s]", key, str); + + return strdup(str); +} + +static int +__get_int_from_json_object(JsonObject *obj, const char *key) +{ + if (obj == NULL) + return _INVALID_INT; + + if (json_object_has_member(obj, key) == false) + return _INVALID_INT; + + int int_val = json_object_get_int_member(obj, key); + dlog_print(DLOG_INFO, "FIDO", "[%s] = [%d]", key, int_val); + + return int_val; +} + +static _extension_t * +__get_extension(JsonObject *ext_json_obj) +{ + RET_IF_FAIL(ext_json_obj != NULL, NULL); + + _extension_t *ext = (_extension_t*) calloc(1, sizeof(_extension_t)); + RET_IF_FAIL(ext != NULL, NULL); + + ext->id = __get_string_from_json_object(ext_json_obj, _JSON_KEY_ID); + ext->data = __get_string_from_json_object(ext_json_obj, _JSON_KEY_DATA); + ext->fail_if_unknown = json_object_get_boolean_member(ext_json_obj, _JSON_KEY_FAIL_IF_UNKNOWN); + + return ext; + +} + +static GList * +__get_extension_list(JsonObject *root_obj) +{ + RET_IF_FAIL(root_obj != NULL, NULL); + + JsonArray *ext_json_arr = json_object_get_array_member(root_obj, _JSON_KEY_EXTS); + RET_IF_FAIL(ext_json_arr != NULL, NULL); + + int ext_arr_len = json_array_get_length(ext_json_arr); + RET_IF_FAIL(ext_arr_len > 0, NULL); + + GList *ext_list = NULL; + + int i = 0; + for (; i < ext_arr_len; i++) { + JsonObject *ext_json_obj = json_array_get_object_element(ext_json_arr, i); + if (ext_json_obj != NULL) { + _extension_t *ext = __get_extension(ext_json_obj); + if (ext != NULL) + ext_list = g_list_append(ext_list, ext); + } + } + + return ext_list; +} + +static _op_header_t* +__parse_uaf_header(JsonObject *header_obj) +{ + _INFO("__parse_uaf_header"); + + _op_header_t *header = (_op_header_t *)calloc(1, sizeof(_op_header_t)); + + header->version = (_version_t *)calloc(1, sizeof(_version_t)); + + JsonObject *ver_obj = json_object_get_object_member(header_obj, _JSON_KEY_UPV); + if (ver_obj == NULL) { + _free_op_header(header); + return NULL; + } + + int major = __get_int_from_json_object(ver_obj, _JSON_KEY_MAJOR); + int minor = __get_int_from_json_object(ver_obj, _JSON_KEY_MINOR); + + if (major == _INVALID_INT || minor == _INVALID_INT) { + + _free_op_header(header); + return NULL; + } + + _INFO("found valid version"); + + header->version->major = major; + header->version->minor = minor; + + header->operation = __get_string_from_json_object(header_obj, _JSON_KEY_OP); + + header->app_id = __get_string_from_json_object(header_obj, _JSON_KEY_APPID); + + header->server_data = __get_string_from_json_object(header_obj, _JSON_KEY_SERVER_DATA); + + header->ext_list = __get_extension_list(header_obj); + + return header; +} + +static GList * +__get_string_list_from_json_array(JsonArray *json_arr) +{ + if (json_arr == NULL) + return NULL; + + GList *list = NULL; + + int arr_len = json_array_get_length(json_arr); + int i = 0; + for (; i < arr_len; i++) { + const char *str = json_array_get_string_element(json_arr, i); + if (str != NULL) + list = g_list_append(list, strdup(str)); + + } + + return list; +} + +static GList * +__get_int_list_from_json_array(JsonArray *json_arr) +{ + if (json_arr == NULL) + return NULL; + + GList *list = NULL; + + int arr_len = json_array_get_length(json_arr); + int i = 0; + for (; i < arr_len; i++) { + int val = json_array_get_int_element(json_arr, i); + list = g_list_append(list, GINT_TO_POINTER(val)); + + } + + return list; +} + +static _match_criteria_t* +_uaf_parser_parse_match(JsonObject *match_obj) +{ + _INFO("_uaf_parser_parse_match"); + + if (match_obj != NULL) { + + _match_criteria_t *match_criteria = (_match_criteria_t*)calloc(1, sizeof(_match_criteria_t)); + + JsonArray *aaid_arr = json_object_get_array_member(match_obj, _JSON_KEY_AAID); + if (aaid_arr != NULL) { + match_criteria->aaid_list = __get_string_list_from_json_array(aaid_arr); + } + + JsonArray *vendor_arr = json_object_get_array_member(match_obj, _JSON_KEY_VENDOR_ID); + if (vendor_arr != NULL) { + match_criteria->vendor_list = __get_string_list_from_json_array(vendor_arr); + } + + JsonArray *key_id_arr = json_object_get_array_member(match_obj, _JSON_KEY_KEY_IDS); + if (key_id_arr != NULL) { + match_criteria->key_id_list = __get_string_list_from_json_array(key_id_arr); + } + + match_criteria->user_verification = __get_int_from_json_object(match_obj, _JSON_KEY_USER_VERIFICATION); + + match_criteria->key_protection = __get_int_from_json_object(match_obj, _JSON_KEY_KEY_PROTECTION); + + match_criteria->matcher_protection = __get_int_from_json_object(match_obj, _JSON_KEY_MATCHER_PROTECTION); + + match_criteria->attachement_hint = __get_int_from_json_object(match_obj, _JSON_KEY_ATTACHMENT_HINT); + + match_criteria->tc_display = __get_int_from_json_object(match_obj, _JSON_KEY_TC_DISPLAY); + + + JsonArray *auth_algo_arr = json_object_get_array_member(match_obj, _JSON_KEY_AUTH_ALGOS); + if (auth_algo_arr) { + match_criteria->auth_algo_list = __get_int_list_from_json_array(auth_algo_arr); + } + + JsonArray *assertion_schm_arr = json_object_get_array_member(match_obj, _JSON_KEY_ASSERT_SCHEMES); + if (assertion_schm_arr) { + match_criteria->assertion_scheme_list = __get_string_list_from_json_array(assertion_schm_arr); + } + + JsonArray *att_type_arr = json_object_get_array_member(match_obj, _JSON_KEY_ATT_TYPES); + if (att_type_arr) { + match_criteria->attestation_type_list = __get_string_list_from_json_array(att_type_arr); + } + + match_criteria->auth_version = __get_int_from_json_object(match_obj, _JSON_KEY_AUTH_VERSION); + + _INFO("_uaf_parser_parse_match is returning match_criteria"); + + return match_criteria; + } + + _INFO("_uaf_parser_parse_match is returning NULL"); + return NULL; +} + +static GList* +__get_plte_list(JsonObject *png_json_obj) +{ + + _INFO(""); + + GList *plte_list_priv = NULL; + + JsonArray *plte_json_arr = json_object_get_array_member(png_json_obj, "plte"); + RET_IF_FAIL(plte_json_arr != NULL, NULL); + + int plte_arr_len = json_array_get_length(plte_json_arr); + RET_IF_FAIL(plte_arr_len > 0, NULL); + + int i = 0; + for (; i < plte_arr_len; i++) { + JsonObject *plte_json_obj = json_array_get_object_element(plte_json_arr, i); + if (plte_json_obj != NULL) { + fido_rgb_pallette_entry_s *pallete = + (fido_rgb_pallette_entry_s *) calloc(1, sizeof(fido_rgb_pallette_entry_s)); + + if (pallete != NULL) { + pallete->r = __get_int_from_json_object(plte_json_obj, _JSON_KEY_R); + pallete->g = __get_int_from_json_object(plte_json_obj, _JSON_KEY_G); + pallete->b = __get_int_from_json_object(plte_json_obj, _JSON_KEY_B); + + plte_list_priv = g_list_append(plte_list_priv, pallete); + } + + } + } + + if (plte_list_priv == NULL) + return NULL; + + plte_list_priv = g_list_first(plte_list_priv); + + _INFO(""); + + return plte_list_priv; +} + +static fido_display_png_characteristics_descriptor_s * +__get_png_data(JsonObject *png_json_obj) +{ + RET_IF_FAIL(png_json_obj != NULL, NULL); + + _INFO(""); + + fido_display_png_characteristics_descriptor_s *png_data = (fido_display_png_characteristics_descriptor_s*) + calloc(1, sizeof(fido_display_png_characteristics_descriptor_s)); + + png_data->width = __get_int_from_json_object(png_json_obj, _JSON_KEY_WIDTH); + png_data->height = __get_int_from_json_object(png_json_obj, _JSON_KEY_HEIGHT); + png_data->bit_depth = __get_int_from_json_object(png_json_obj, _JSON_KEY_BIT_DEPTH); + png_data->color_type = __get_int_from_json_object(png_json_obj, _JSON_KEY_COLOR_TYPE); + png_data->compression = __get_int_from_json_object(png_json_obj, _JSON_KEY_COMPRESSION); + png_data->filter = __get_int_from_json_object(png_json_obj, _JSON_KEY_FILTER); + png_data->interlace = __get_int_from_json_object(png_json_obj, _JSON_KEY_INTERLACE); + + png_data->plte = __get_plte_list(png_json_obj); + + _INFO(""); + return png_data; +} + +static GList * +__get_tc_disp_png_array(JsonObject *auth_obj) +{ + RET_IF_FAIL(auth_obj != NULL, NULL); + + JsonArray *png_arr_json = json_object_get_array_member(auth_obj, _JSON_KEY_TC_DISP_PNG_CHARS); + RET_IF_FAIL(png_arr_json != NULL, NULL); + + int arr_len = json_array_get_length(png_arr_json); + RET_IF_FAIL(arr_len > 0, NULL); + + GList *png_list = NULL; + int i = 0; + for (; i < arr_len; i++) { + JsonObject *png_json_obj = json_array_get_object_element(png_arr_json, i); + if (png_json_obj != NULL) { + + fido_display_png_characteristics_descriptor_s *png = __get_png_data(png_json_obj); + if (png != NULL) + png_list = g_list_append(png_list, png); + } + } + + + return png_list; +} + +GList* +_uaf_parser_parse_asm_response_discover_client(char **asm_response_list, int len, int *error_code) +{ + _INFO("_uaf_parser_parse_asm_response_discover start"); + + RET_IF_FAIL(asm_response_list != NULL, NULL); + + GList *available_authenticators = NULL; + + int i = 0; + for (; i < len; i++) { + + JsonParser *parser = json_parser_new(); + CATCH_IF_FAIL(parser != NULL); + + GError *parse_err = NULL; + json_parser_load_from_data(parser, asm_response_list[i], -1, &parse_err); + CATCH_IF_FAIL(parse_err == NULL); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + int err_temp = 0; + err_temp = json_object_get_int_member(root_obj, _JSON_KEY_STATUS_CODE); + + *error_code = err_temp; + CATCH_IF_FAIL(*error_code == 0); + + JsonObject *response_obj = json_object_get_object_member(root_obj, _JSON_KEY_RESP_DATA); + CATCH_IF_FAIL(response_obj != NULL); + + JsonArray *auth_arr = json_object_get_array_member(response_obj, _JSON_KEY_AUTHENTICATORS); + CATCH_IF_FAIL(auth_arr != NULL); + + int auth_arr_len = json_array_get_length(auth_arr); + + int auth_arr_index = 0; + for (auth_arr_index = 0; auth_arr_index < auth_arr_len; auth_arr_index++) { + JsonObject *auth_obj = json_array_get_object_element(auth_arr, auth_arr_index); + if (auth_obj != NULL) { + fido_authenticator_s *auth_info = (fido_authenticator_s *)calloc(1, sizeof(fido_authenticator_s)); + + + int auth_index = json_object_get_int_member(auth_obj, _JSON_KEY_AUTH_INDEX); + char *auth_idx_str = (char*)calloc(1, 128); + snprintf(auth_idx_str, 127, "%d", auth_index); + + auth_info->auth_index = auth_idx_str; + _INFO("auth_info->auth_index = [%s]", auth_info->auth_index); + + + /* FIXME : ASM version list */ + + bool is_enrolled = json_object_get_boolean_member(auth_obj, _JSON_KEY_IS_USER_ENROLLED); + auth_info->is_user_enrolled = is_enrolled; + + bool has_settings = json_object_get_boolean_member(auth_obj, _JSON_KEY_HAS_SETTINGS); + auth_info->has_settings = has_settings; + + + const char *aaid = json_object_get_string_member(auth_obj, _JSON_KEY_AAID); + if (aaid != NULL) { + auth_info->aaid = strdup(aaid); + _INFO("auth_info->aaid = [%s]", auth_info->aaid); + } + + + const char *assertion_schm = json_object_get_string_member(auth_obj, _JSON_KEY_ASSERT_SCHEME); + if (assertion_schm != NULL) + auth_info->assertion_scheme = strdup(assertion_schm); + + int auth_algo = json_object_get_int_member(auth_obj, _JSON_KEY_AUTH_ALGO); + auth_info->authentication_algorithm = auth_algo; + + GList *att_list = NULL; + JsonArray *att_arr = json_object_get_array_member(auth_obj, _JSON_KEY_ATT_TYPES); + if (att_arr != NULL) { + int att_arr_len = json_array_get_length(att_arr); + int att_arr_idx = 0; + for (att_arr_idx = 0; att_arr_idx < att_arr_len; att_arr_idx++) { + int att = json_array_get_int_element(att_arr, att_arr_idx); + att_list = g_list_append(att_list, GINT_TO_POINTER(att)); + } + } + + if (att_list != NULL) + auth_info->attestation_types = g_list_first(att_list); + + int user_verification = json_object_get_int_member(auth_obj, _JSON_KEY_USER_VERIFICATION); + auth_info->user_verification = user_verification; + + int key_prot = json_object_get_int_member(auth_obj, _JSON_KEY_KEY_PROTECTION); + auth_info->key_protection = key_prot; + + + int matcher_prot = json_object_get_int_member(auth_obj, _JSON_KEY_MATCHER_PROTECTION); + auth_info->matcher_protection = matcher_prot; + + int attch_hint = json_object_get_int_member(auth_obj, _JSON_KEY_ATTACHMENT_HINT); + auth_info->attachment_hint = attch_hint; + + + bool is_sec_only = json_object_get_boolean_member(auth_obj, _JSON_KEY_IS_2_FACTOR_ONLY); + auth_info->is_second_factor_only = is_sec_only; + + + bool is_roaming = json_object_get_boolean_member(auth_obj, _JSON_KEY_IS_ROAMING_AUTH); + auth_info->is_roaming = is_roaming; + + + JsonArray *ext_id_json_arr = json_object_get_array_member(auth_obj, _JSON_KEY_SUPPORTED_EXT_IDS); + if (ext_id_json_arr != NULL) + auth_info->supported_extension_IDs = __get_string_list_from_json_array(ext_id_json_arr); + + + int tc_disp = json_object_get_int_member(auth_obj, _JSON_KEY_TC_DISPLAY); + auth_info->tc_display = tc_disp; + + const char *tc_dis_type = json_object_get_string_member(auth_obj, _JSON_KEY_TC_DISP_CONTENT_TYPE); + if (tc_dis_type != NULL) + auth_info->tc_display_content_type = strdup(tc_dis_type); + + + auth_info->tc_display_png_characteristics = __get_tc_disp_png_array(auth_obj); + + const char *title = json_object_get_string_member(auth_obj, _JSON_KEY_TITLE); + if (title != NULL) + auth_info->title = strdup(title); + + + const char *desc = json_object_get_string_member(auth_obj, _JSON_KEY_DESC); + if (desc != NULL) + auth_info->description = strdup(desc); + + + const char *icon = json_object_get_string_member(auth_obj, _JSON_KEY_ICON); + if (icon != NULL) + auth_info->icon = strdup(icon); + + /* Supported UAF versions is fixed to 1.0*/ + fido_version_s *version = calloc(1, sizeof(fido_version_s)); + version->major = _VERSION_MAJOR; + version->minor = _VERSION_MINOR; + + auth_info->supported_versions = g_list_append(auth_info->supported_versions, version); + + available_authenticators = g_list_append(available_authenticators, auth_info); + } + } + + if (parser != NULL) + g_object_unref(parser); + + } + + + available_authenticators = g_list_first(available_authenticators); + + _INFO("available_authenticators count = [%d]", g_list_length(available_authenticators)); + + return available_authenticators; + +CATCH: + return NULL; +} + +GList* +_uaf_parser_parse_asm_response_discover(GList *asm_response_list, int *error_code) +{ + _INFO("_uaf_parser_parse_asm_response_discover start"); + + RET_IF_FAIL(asm_response_list != NULL, NULL); + + GList *available_authenticators = NULL; + + GList *asm_response_list_iter = g_list_first(asm_response_list); + while (asm_response_list_iter != NULL) { + + _asm_discover_response_t *asm_resp = (_asm_discover_response_t*)(asm_response_list_iter->data); + if (asm_resp->error_code == FIDO_ERROR_NONE + && + asm_resp->asm_response_json != NULL) { + + JsonParser *parser = json_parser_new(); + CATCH_IF_FAIL(parser != NULL); + + GError *parse_err = NULL; + json_parser_load_from_data(parser, asm_resp->asm_response_json, -1, &parse_err); + CATCH_IF_FAIL(parse_err == NULL); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + int err_temp = 0; + err_temp = json_object_get_int_member(root_obj, _JSON_KEY_STATUS_CODE); + + *error_code = err_temp; + CATCH_IF_FAIL(*error_code == 0); + + JsonObject *response_obj = json_object_get_object_member(root_obj, _JSON_KEY_RESP_DATA); + CATCH_IF_FAIL(response_obj != NULL); + + JsonArray *auth_arr = json_object_get_array_member(response_obj, _JSON_KEY_AUTHENTICATORS); + CATCH_IF_FAIL(auth_arr != NULL); + + int auth_arr_len = json_array_get_length(auth_arr); + + int auth_arr_index = 0; + for (auth_arr_index = 0; auth_arr_index < auth_arr_len; auth_arr_index++) { + JsonObject *auth_obj = json_array_get_object_element(auth_arr, auth_arr_index); + if (auth_obj != NULL) { + fido_authenticator_s *auth_info = (fido_authenticator_s *)calloc(1, sizeof(fido_authenticator_s)); + + + int auth_index = json_object_get_int_member(auth_obj, _JSON_KEY_AUTH_INDEX); + char *auth_idx_str = (char*)calloc(1, 128); + snprintf(auth_idx_str, 127, "%d", auth_index); + + auth_info->auth_index = auth_idx_str; + _INFO("auth_info->auth_index = [%s]", auth_info->auth_index); + + + /* FIXME : ASM version list */ + + bool is_enrolled = json_object_get_boolean_member(auth_obj, _JSON_KEY_IS_USER_ENROLLED); + auth_info->is_user_enrolled = is_enrolled; + + bool has_settings = json_object_get_boolean_member(auth_obj, _JSON_KEY_HAS_SETTINGS); + auth_info->has_settings = has_settings; + + + const char *aaid = json_object_get_string_member(auth_obj, _JSON_KEY_AAID); + if (aaid != NULL) + auth_info->aaid = strdup(aaid); + + + const char *assertion_schm = json_object_get_string_member(auth_obj, _JSON_KEY_ASSERT_SCHEME); + if (assertion_schm != NULL) + auth_info->assertion_scheme = strdup(assertion_schm); + + int auth_algo = json_object_get_int_member(auth_obj, _JSON_KEY_AUTH_ALGO); + auth_info->authentication_algorithm = auth_algo; + + GList *att_list = NULL; + JsonArray *att_arr = json_object_get_array_member(auth_obj, _JSON_KEY_ATT_TYPES); + if (att_arr != NULL) { + int att_arr_len = json_array_get_length(att_arr); + int att_arr_idx = 0; + for (att_arr_idx = 0; att_arr_idx < att_arr_len; att_arr_idx++) { + int att = json_array_get_int_element(att_arr, att_arr_idx); + att_list = g_list_append(att_list, GINT_TO_POINTER(att)); + } + } + + if (att_list != NULL) + auth_info->attestation_types = g_list_first(att_list); + + int user_verification = json_object_get_int_member(auth_obj, _JSON_KEY_USER_VERIFICATION); + auth_info->user_verification = user_verification; + + int key_prot = json_object_get_int_member(auth_obj, _JSON_KEY_KEY_PROTECTION); + auth_info->key_protection = key_prot; + + + int matcher_prot = json_object_get_int_member(auth_obj, _JSON_KEY_MATCHER_PROTECTION); + auth_info->matcher_protection = matcher_prot; + + int attch_hint = json_object_get_int_member(auth_obj, _JSON_KEY_ATTACHMENT_HINT); + auth_info->attachment_hint = attch_hint; + + + bool is_sec_only = json_object_get_boolean_member(auth_obj, _JSON_KEY_IS_2_FACTOR_ONLY); + auth_info->is_second_factor_only = is_sec_only; + + + bool is_roaming = json_object_get_boolean_member(auth_obj, _JSON_KEY_IS_ROAMING_AUTH); + auth_info->is_roaming = is_roaming; + + + JsonArray *ext_id_json_arr = json_object_get_array_member(auth_obj, _JSON_KEY_SUPPORTED_EXT_IDS); + if (ext_id_json_arr != NULL) + auth_info->supported_extension_IDs = __get_string_list_from_json_array(ext_id_json_arr); + + + int tc_disp = json_object_get_int_member(auth_obj, _JSON_KEY_TC_DISPLAY); + auth_info->tc_display = tc_disp; + + const char *tc_dis_type = json_object_get_string_member(auth_obj, _JSON_KEY_TC_DISP_CONTENT_TYPE); + if (tc_dis_type != NULL) + auth_info->tc_display_content_type = strdup(tc_dis_type); + + + auth_info->tc_display_png_characteristics = __get_tc_disp_png_array(auth_obj); + + const char *title = json_object_get_string_member(auth_obj, _JSON_KEY_TITLE); + if (title != NULL) + auth_info->title = strdup(title); + + + const char *desc = json_object_get_string_member(auth_obj, _JSON_KEY_DESC); + if (desc != NULL) + auth_info->description = strdup(desc); + + + const char *icon = json_object_get_string_member(auth_obj, _JSON_KEY_ICON); + if (icon != NULL) + auth_info->icon = strdup(icon); + + + if (asm_resp->asm_id != NULL) + auth_info->asm_id = strdup(asm_resp->asm_id); + else + _ERR("Authenticator does not have ASM ID!!"); + + available_authenticators = g_list_append(available_authenticators, auth_info); + } + } + + if (parser != NULL) + g_object_unref(parser); + + } + + asm_response_list_iter = g_list_next(asm_response_list_iter); + + } + + + available_authenticators = g_list_first(available_authenticators); + + _INFO("available_authenticators count = [%d]", g_list_length(available_authenticators)); + + return available_authenticators; + +CATCH: + return NULL; +} + +_asm_out_t* +_uaf_parser_parse_asm_response_reg(const char *asm_response_json, int *error_code) +{ + _asm_out_t *asm_out = NULL; + int status = 0; + GError *parser_err = NULL; + + JsonParser *parser = json_parser_new(); + bool is_success = json_parser_load_from_data(parser, asm_response_json, -1, &parser_err); + + CATCH_IF_FAIL(is_success == true); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + status = json_object_get_int_member(root_obj, _JSON_KEY_STATUS_CODE); + CATCH_IF_FAIL(status == 0); + + JsonObject *resp_obj = json_object_get_object_member(root_obj, _JSON_KEY_RESP_DATA); + CATCH_IF_FAIL(resp_obj != NULL); + + const char *assertion = json_object_get_string_member(resp_obj, _JSON_KEY_ASSERTION); + CATCH_IF_FAIL(assertion != NULL); + + const char *assertion_scheme = json_object_get_string_member(resp_obj, _JSON_KEY_ASSERT_SCHEME); + CATCH_IF_FAIL(assertion_scheme != NULL); + + _asm_reg_out_t *reg_out = (_asm_reg_out_t*)calloc(1, sizeof(_asm_reg_out_t)); + reg_out->assertion = strdup(assertion); + reg_out->assertion_schm = strdup(assertion_scheme); + + asm_out = (_asm_out_t*)calloc(1, sizeof(_asm_out_t)); + asm_out->type = _ASM_OUT_TYPE_REG; + + asm_out->status_code = status; + asm_out->response_data = reg_out; + + asm_out->ext_list = __get_extension_list(root_obj); + + if (parser != NULL) + g_object_unref(parser); + + *error_code = 0; + return asm_out; + +CATCH: + _free_asm_out(asm_out); + if (parser != NULL) + g_object_unref(parser); + + *error_code = status; + return NULL; +} + +_asm_out_t* +_uaf_parser_parse_asm_response_auth(const char *asm_response_json, int *error_code) +{ + _asm_out_t *asm_out = NULL; + int status = 0; + GError *parser_err = NULL; + + JsonParser *parser = json_parser_new(); + bool is_success = json_parser_load_from_data(parser, asm_response_json, -1, &parser_err); + + CATCH_IF_FAIL(is_success == true); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + status = json_object_get_int_member(root_obj, _JSON_KEY_STATUS_CODE); + CATCH_IF_FAIL(status == 0); + + JsonObject *resp_obj = json_object_get_object_member(root_obj, _JSON_KEY_RESP_DATA); + CATCH_IF_FAIL(resp_obj != NULL); + + const char *assertion = json_object_get_string_member(resp_obj, _JSON_KEY_ASSERTION); + CATCH_IF_FAIL(assertion != NULL); + + const char *assertion_scheme = json_object_get_string_member(resp_obj, _JSON_KEY_ASSERT_SCHEME); + CATCH_IF_FAIL(assertion_scheme != NULL); + + _asm_auth_out_t *auth_out = (_asm_auth_out_t*)calloc(1, sizeof(_asm_auth_out_t)); + auth_out->assertion = strdup(assertion); + auth_out->assertion_scheme = strdup(assertion_scheme); + + asm_out = (_asm_out_t*)calloc(1, sizeof(_asm_out_t)); + asm_out->type = _ASM_OUT_TYPE_AUTH; + + asm_out->status_code = status; + asm_out->response_data = auth_out; + + asm_out->ext_list = __get_extension_list(root_obj); + + if (parser != NULL) + g_object_unref(parser); + + *error_code = 0; + return asm_out; + +CATCH: + _free_asm_out(asm_out); + if (parser != NULL) + g_object_unref(parser); + + *error_code = status; + return NULL; +} + +_asm_dereg_out_t* +_uaf_parser_parse_asm_response_dereg(const char *asm_response_json, int *error_code) +{ + _asm_dereg_out_t *asm_out = NULL; + int status = 0; + GError *parser_err = NULL; + + JsonParser *parser = json_parser_new(); + bool is_success = json_parser_load_from_data(parser, asm_response_json, -1, &parser_err); + + CATCH_IF_FAIL(is_success == true); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + asm_out = (_asm_dereg_out_t*)calloc(1, sizeof(_asm_dereg_out_t)); + + asm_out->status_code = json_object_get_int_member(root_obj, _JSON_KEY_STATUS_CODE); + + if (parser != NULL) + g_object_unref(parser); + + *error_code = 0; + return asm_out; + +CATCH: + free(asm_out); + if (parser != NULL) + g_object_unref(parser); + + *error_code = status; + return NULL; +} + +int +_uaf_composer_compose_asm_reg_request(_version_t *version, int auth_index, _fido_asm_reg_in_t *reg_in, char **asm_reg_json) +{ + _INFO("_uaf_composer_compose_asm_reg_request start"); + + /*Builder start*/ + JsonBuilder *builder = json_builder_new(); + json_builder_begin_object(builder); + + /*requestType*/ + __add_string_to_json_object(builder, _JSON_KEY_REQ_TYPE, _JSON_KEY_REGISTER); + + /*authIndex*/ + json_builder_set_member_name(builder, _JSON_KEY_AUTH_INDEX); + json_builder_add_int_value(builder, auth_index); + + /*version*/ + json_builder_set_member_name(builder, _JSON_KEY_ASM_VERSION); + json_builder_begin_object(builder); + json_builder_set_member_name(builder, _JSON_KEY_MAJOR); + json_builder_add_int_value(builder, version->major); + + json_builder_set_member_name(builder, _JSON_KEY_MINOR); + json_builder_add_int_value(builder, version->minor); + + json_builder_end_object(builder); + /*version*/ + + /*args*/ + json_builder_set_member_name(builder, _JSON_KEY_ARGS); + json_builder_begin_object(builder); + + __add_string_to_json_object(builder, _JSON_KEY_APPID, reg_in->app_id); + __add_string_to_json_object(builder, _JSON_KEY_USER_NAME, reg_in->user_name); + __add_string_to_json_object(builder, _JSON_KEY_FINAL_CHALLENGE, reg_in->final_challenge); + + if (reg_in->attestation_type != _INVALID_INT) { + json_builder_set_member_name(builder, _JSON_KEY_ATT_TYPE); + + json_builder_add_int_value(builder, reg_in->attestation_type); + } + + + json_builder_end_object(builder); + /*args*/ + + + json_builder_end_object(builder); + /*Builder end*/ + + JsonGenerator *gen = json_generator_new(); + JsonNode *root_builder = json_builder_get_root(builder); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *json = json_generator_to_data(gen, &len); + if (json != NULL) { + *asm_reg_json = json; + + if (gen != NULL) + g_object_unref(gen); + + _INFO("%s", json); + + _INFO("_uaf_composer_compose_asm_reg_request end"); + + return 0; + } + + g_object_unref(gen); + + _INFO("_uaf_composer_compose_asm_reg_request fail"); + return -1; +} + +int +_uaf_composer_compose_asm_auth_request(_version_t *version, int auth_index, _fido_asm_auth_in_t *auth_in, + char **asm_auth_json) +{ + _INFO("_uaf_composer_compose_asm_auth_request start"); + + /*Builder start*/ + JsonBuilder *builder = json_builder_new(); + json_builder_begin_object(builder); + + /*requestType*/ + __add_string_to_json_object(builder, _JSON_KEY_REQ_TYPE, _JSON_KEY_AUTHENTICATE); + + /*authIndex*/ + json_builder_set_member_name(builder, _JSON_KEY_AUTH_INDEX); + json_builder_add_int_value(builder, auth_index); + + /*version*/ + json_builder_set_member_name(builder, _JSON_KEY_ASM_VERSION); + json_builder_begin_object(builder); + json_builder_set_member_name(builder, _JSON_KEY_MAJOR); + json_builder_add_int_value(builder, version->major); + + json_builder_set_member_name(builder, _JSON_KEY_MINOR); + json_builder_add_int_value(builder, version->minor); + + json_builder_end_object(builder); + /*version*/ + + /*args*/ + json_builder_set_member_name(builder, _JSON_KEY_ARGS); + json_builder_begin_object(builder); + + __add_string_to_json_object(builder, _JSON_KEY_APPID, auth_in->app_id); + __add_string_to_json_object(builder, _JSON_KEY_FINAL_CHALLENGE, auth_in->final_challenge); + + if (auth_in->key_ids != NULL) { + _INFO("keyID to be sent in ASM req"); + /*keyIDs*/ + json_builder_set_member_name(builder, _JSON_KEY_KEY_IDS); + json_builder_begin_array(builder); + + GList *iter = g_list_first(auth_in->key_ids); + while (iter != NULL) { + + char *val = (char*)(iter->data); + json_builder_add_string_value(builder, val); + iter = iter->next; + } + json_builder_end_array(builder); + /*keyIDs*/ + } + + /*Transaction list composing*/ + if (auth_in->trans_list != NULL) { + /*transaction*/ + json_builder_set_member_name(builder, _JSON_KEY_TRANSACTION); + json_builder_begin_array(builder); + + GList *iter = g_list_first(auth_in->trans_list); + while (iter != NULL) { + + _fido_asm_transaction_t *val = (_fido_asm_transaction_t*)(iter->data); + /*transaction array element*/ + json_builder_begin_object(builder); + + /*contentType*/ + __add_string_to_json_object(builder, _JSON_KEY_CONTENT_TYPE, val->content_type); + /*content*/ + __add_string_to_json_object(builder, _JSON_KEY_CONTENT, val->content); + /*tcDisplayPNGCharacteristics*/ + if (val->display_charac != NULL) { + + __add_int_to_json_object(builder, _JSON_KEY_WIDTH, val->display_charac->width); + __add_int_to_json_object(builder, _JSON_KEY_HEIGHT, val->display_charac->height); + __add_int_to_json_object(builder, _JSON_KEY_BIT_DEPTH, val->display_charac->bit_depth); + __add_int_to_json_object(builder, _JSON_KEY_COLOR_TYPE, val->display_charac->color_type); + __add_int_to_json_object(builder, _JSON_KEY_COMPRESSION, val->display_charac->compression); + __add_int_to_json_object(builder, _JSON_KEY_FILTER, val->display_charac->filter); + __add_int_to_json_object(builder, _JSON_KEY_INTERLACE, val->display_charac->interlace); + __add_int_to_json_object(builder, _JSON_KEY_WIDTH, val->display_charac->width); + + /*plte*/ + if (val->display_charac->plte != NULL) { + + json_builder_begin_array(builder); + + GList *plte_iter = g_list_first(val->display_charac->plte); + while (plte_iter != NULL) { + _fido_asm_rgb_pallette_entry_t *plte = (_fido_asm_rgb_pallette_entry_t*)(plte_iter->data); + + __add_int_to_json_object(builder, _JSON_KEY_R, plte->r); + __add_int_to_json_object(builder, _JSON_KEY_G, plte->g); + __add_int_to_json_object(builder, _JSON_KEY_B, plte->b); + + plte_iter = plte_iter->next; + } + + json_builder_end_array(builder); + } + } + + json_builder_end_object(builder); + + iter = iter->next; + } + json_builder_end_array(builder); + /*transaction*/ + } + + json_builder_end_object(builder); + /*args*/ + + + json_builder_end_object(builder); + /*Builder end*/ + + JsonGenerator *gen = json_generator_new(); + JsonNode *root_builder = json_builder_get_root(builder); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *json = json_generator_to_data(gen, &len); + if (json != NULL) { + *asm_auth_json = json; + + if (gen != NULL) + g_object_unref(gen); + + _INFO("%s", json); + + _INFO("_uaf_composer_compose_asm_auth_request end"); + + return 0; + } + + g_object_unref(gen); + + _INFO("_uaf_composer_compose_asm_auth_request fail"); + return -1; +} + +int +_uaf_composer_compose_asm_dereg_request(_version_t *version, int auth_index, _matched_auth_dereg_t *dereg_in, + char **asm_dereg_json) +{ + _INFO("_uaf_composer_compose_asm_dereg_request start"); + + /*Builder start*/ + JsonBuilder *builder = json_builder_new(); + JsonBuilder *root = json_builder_begin_object(builder); + + /*requestType*/ + __add_string_to_json_object(root, _JSON_KEY_REQ_TYPE, _JSON_KEY_DEREGISTER); + + /*authIndex*/ + json_builder_set_member_name(root, _JSON_KEY_AUTH_INDEX); + json_builder_add_int_value(root, auth_index); + + /*version*/ + json_builder_set_member_name(root, _JSON_KEY_ASM_VERSION); + JsonBuilder *ver_root = json_builder_begin_object(root); + json_builder_set_member_name(ver_root, _JSON_KEY_MAJOR); + json_builder_add_int_value(ver_root, version->major); + + json_builder_set_member_name(ver_root, _JSON_KEY_MINOR); + json_builder_add_int_value(ver_root, version->minor); + + json_builder_end_object(ver_root); + + + /*args*/ + json_builder_set_member_name(root, _JSON_KEY_ARGS); + JsonBuilder *args_root = json_builder_begin_object(root); + + __add_string_to_json_object(args_root, _JSON_KEY_APPID, dereg_in->app_id); + __add_string_to_json_object(args_root, _JSON_KEY_KEY_ID, dereg_in->key_id); + + json_builder_end_object(args_root); + + json_builder_end_object(root); + /*Builder end*/ + + JsonGenerator *gen = json_generator_new(); + JsonNode *root_builder = json_builder_get_root(builder); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *json = json_generator_to_data(gen, &len); + if (json != NULL) { + *asm_dereg_json = json; + _INFO("_uaf_composer_compose_uaf_process_response_reg return success"); + + if (gen != NULL) + g_object_unref(gen); + + _INFO("%s", json); + + _INFO("_uaf_composer_compose_asm_dereg_request end"); + + return 0; + } + + g_object_unref(gen); + + _INFO("_uaf_composer_compose_asm_dereg_request fail"); + return -1; + +} + +//{"appID":"https://qa-egypt.noknoktest.com:443/UAFSampleProxy/uaf/facets.uaf","challenge":"uYBuGQf7r-LND16Q0GUpPRi112UjCtcym3awjm-MmmI","channelBinding":{},"facetID":"com.noknok.android.sampleapp"} +char * +_uaf_composer_compose_final_challenge(const char *app_id, const char *challenge, const char *facet_id, const char *ch_bin) +{ + _INFO("_uaf_composer_compose_final_challenge"); + + JsonBuilder *builder = json_builder_new(); + json_builder_begin_object(builder); + + __add_string_to_json_object(builder, _JSON_KEY_APPID, app_id); + + __add_string_to_json_object(builder, _JSON_KEY_CHALLENGE, challenge); + + json_builder_set_member_name(builder, _JSON_KEY_CH_BINDING); + json_builder_begin_object(builder); + if (ch_bin != NULL) { + + JsonParser *chb_parser = json_parser_new(); + + GError *chb_err = NULL; + bool chb_parsed = json_parser_load_from_data(chb_parser, ch_bin, -1, &chb_err); + if (chb_parsed == FALSE) { + return NULL; + } + + JsonNode *chb_root = json_parser_get_root(chb_parser); + RET_IF_FAIL(chb_root != NULL, NULL); + + JsonObject *chb_root_obj = json_node_get_object(chb_root); + RET_IF_FAIL(chb_root_obj != NULL, NULL); + + char *end_pt = __get_string_from_json_object(chb_root_obj, _JSON_KEY_SERVER_END_POINT); + char *cert = __get_string_from_json_object(chb_root_obj, _JSON_KEY_TLS_SERVER_CERT); + char *uni = __get_string_from_json_object(chb_root_obj, _JSON_KEY_TLS_UNIQUE); + char *cid = __get_string_from_json_object(chb_root_obj, _JSON_KEY_CID_PUB_KEY); + + __add_string_to_json_object(builder, _JSON_KEY_SERVER_END_POINT, end_pt); + __add_string_to_json_object(builder, _JSON_KEY_TLS_SERVER_CERT, cert); + __add_string_to_json_object(builder, _JSON_KEY_TLS_UNIQUE, uni); + __add_string_to_json_object(builder, _JSON_KEY_CID_PUB_KEY, cid); + + SAFE_DELETE(end_pt); + SAFE_DELETE(cert); + SAFE_DELETE(uni); + SAFE_DELETE(cid); + + g_object_unref(chb_parser); + + } + + /*If no channledbinding to add, putting empty */ + json_builder_end_object(builder); + + __add_string_to_json_object(builder, _JSON_KEY_FACET_ID, facet_id); + + json_builder_end_object(builder); + + JsonNode *root_node = json_builder_get_root(builder); + + JsonGenerator *generator = json_generator_new(); + json_generator_set_root(generator, root_node); + + json_node_free(root_node); + g_object_unref(builder); + + char *json_str = NULL; + gsize len = 0; + json_str = json_generator_to_data(generator, &len); + + if (json_str == NULL) + return NULL; + + int inlen = strlen(json_str); + int fc_enc_len = (4 * ((inlen + 2) / 3)) + 1; + + unsigned char *fc_enc = calloc(1, fc_enc_len); + + int r = _fido_b64url_encode((unsigned char*)json_str, inlen, fc_enc, &fc_enc_len); + + _INFO("_fido_b64url_encode len=[%d]", fc_enc_len); + + SAFE_DELETE(json_str); + g_object_unref(generator); + + if (r != 0) + return NULL; + + _INFO("_fido_b64url_encoded string=%s", fc_enc); + + return ((char*)fc_enc); + +} + +int +_uaf_composer_compose_uaf_process_response_reg(_op_header_t *header, char *final_ch, GList *assertions, char **uaf_response) +{ + _INFO("_uaf_composer_compose_uaf_process_response_reg"); + + RET_IF_FAIL(header != NULL, FIDO_ERROR_PROTOCOL_ERROR); + + /*Only 1.0 protocol support*/ + + JsonBuilder *builder = json_builder_new(); + + json_builder_begin_array(builder); + + json_builder_begin_object(builder); + + /* header*/ + json_builder_set_member_name(builder, _JSON_KEY_HEADER); + json_builder_begin_object(builder); + + json_builder_set_member_name(builder, _JSON_KEY_APPID); + json_builder_add_string_value(builder, header->app_id); + + json_builder_set_member_name(builder, _JSON_KEY_OP); + json_builder_add_string_value(builder, header->operation); + + json_builder_set_member_name(builder, _JSON_KEY_SERVER_DATA); + json_builder_add_string_value(builder, header->server_data); + + json_builder_set_member_name(builder, _JSON_KEY_UPV); + json_builder_begin_object(builder); + + json_builder_set_member_name(builder, _JSON_KEY_MAJOR); + json_builder_add_int_value(builder, header->version->major); + + json_builder_set_member_name(builder, _JSON_KEY_MINOR); + json_builder_add_int_value(builder, header->version->minor); + + json_builder_end_object(builder); + + json_builder_end_object(builder); + + /* fcparams*/ + if (final_ch != NULL) { + json_builder_set_member_name(builder, _JSON_KEY_FC_PARAMS); + json_builder_add_string_value(builder, final_ch); + } + + /* assertions*/ + json_builder_set_member_name(builder, _JSON_KEY_ASSERTIONS); + json_builder_begin_array(builder); + GList *assertions_iter = g_list_first(assertions); + while (assertions_iter != NULL) { + _auth_reg_assertion_t *ass_data = (_auth_reg_assertion_t*)(assertions_iter->data); + json_builder_begin_object(builder); + json_builder_set_member_name(builder, _JSON_KEY_ASSERTION); + json_builder_add_string_value(builder, ass_data->assertion); + + json_builder_set_member_name(builder, _JSON_KEY_ASSERT_SCHEME); + json_builder_add_string_value(builder, ass_data->assertion_schm); + + json_builder_end_object(builder); + + assertions_iter = assertions_iter->next; + + } + + json_builder_end_array(builder); + + json_builder_end_object(builder); + + + json_builder_end_array(builder); + + + JsonNode *root_builder = json_builder_get_root(builder); + + JsonGenerator *gen = json_generator_new(); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *json = json_generator_to_data(gen, &len); + if (json != NULL) { + *uaf_response = json; + _INFO("_uaf_composer_compose_uaf_process_response_reg return success"); + + if (gen != NULL) + g_object_unref(gen); + + return FIDO_ERROR_NONE; + } + + _INFO("_uaf_composer_compose_uaf_process_response_reg return fail"); + g_object_unref(gen); + return FIDO_ERROR_PROTOCOL_ERROR; +} + +int +_uaf_composer_compose_uaf_process_response_auth(_op_header_t *header, char *final_ch, GList *assertions, char **uaf_response) +{ + return _uaf_composer_compose_uaf_process_response_reg(header, final_ch, assertions, uaf_response); +} + +char * +_uaf_composer_compose_dereg_request(_response_t *uaf_res) +{ + _INFO("_uaf_composer_compose_dereg_request"); + + /*Only 1.0 protocol support*/ + + JsonBuilder *builder = json_builder_new(); + + JsonBuilder *root_array = json_builder_begin_array(builder); + + JsonBuilder *uaf_1_root = json_builder_begin_object(root_array); + + /* header*/ + json_builder_set_member_name(uaf_1_root, _JSON_KEY_HEADER); + JsonBuilder *header_root = json_builder_begin_object(uaf_1_root); + + json_builder_set_member_name(header_root, _JSON_KEY_APPID); + json_builder_add_string_value(header_root, uaf_res->header->app_id); + + json_builder_set_member_name(header_root, _JSON_KEY_OP); + json_builder_add_string_value(header_root, strdup(_UAF_OPERATION_NAME_KEY_DE_REG)); + + json_builder_set_member_name(header_root, _JSON_KEY_SERVER_DATA); + json_builder_add_string_value(header_root, uaf_res->header->server_data); + + json_builder_set_member_name(header_root, _JSON_KEY_UPV); + JsonBuilder *upv_root = json_builder_begin_object(header_root); + + json_builder_set_member_name(upv_root, _JSON_KEY_MAJOR); + json_builder_add_int_value(upv_root, uaf_res->header->version->major); + + json_builder_set_member_name(upv_root, _JSON_KEY_MINOR); + json_builder_add_int_value(upv_root,uaf_res->header->version->minor); + + json_builder_end_object(upv_root); + + json_builder_end_object(header_root); + /* header*/ + + _INFO("after header"); + + + /*appID*/ + if (uaf_res->header->app_id == NULL) { + _ERR("appID is missing"); + + g_object_unref(builder); + return NULL; + } + + json_builder_set_member_name(uaf_1_root, _JSON_KEY_APPID); + json_builder_add_string_value(uaf_1_root, uaf_res->header->app_id); + /*appID*/ + + + /*authenticators*/ + json_builder_set_member_name(uaf_1_root, _JSON_KEY_AUTHENTICATORS_SMALL); + JsonBuilder *auth_root = json_builder_begin_array(uaf_1_root); + GList *assertions_iter = g_list_first(uaf_res->assertion_list); + while (assertions_iter != NULL) { + + _auth_reg_assertion_t *ass_data = (_auth_reg_assertion_t*)(assertions_iter->data); + + char *assrt = ass_data->assertion; + + _INFO("%s", assrt); + + _auth_reg_assertion_tlv_t *assrt_tlv = _tlv_util_decode_reg_assertion(assrt); + if (assrt_tlv == NULL) { + _ERR("Invalid assertion format"); + + g_object_unref(builder); + return NULL; + } + + char *aaid = strdup(assrt_tlv->aaid); + + JsonBuilder *obj = json_builder_begin_object(auth_root); + + if (aaid != NULL) { + json_builder_set_member_name(obj, _JSON_KEY_AAID); + json_builder_add_string_value(obj, aaid); + _INFO("aaid=[%s]", aaid); + } + + if (assrt_tlv->key_id != NULL) { + int inlen = assrt_tlv->key_id_len; + int enc_len = (4 * ((inlen + 2) / 3)) + 1; + + unsigned char *key_id_enc = calloc(1, enc_len); + + int r = _fido_b64url_encode(assrt_tlv->key_id, inlen, key_id_enc, &enc_len); + + _INFO("_fido_b64url_encode len=[%d]", enc_len); + + if ((key_id_enc != NULL) && (r == 0)) { + _INFO("_fido_b64url_encoded string=%s", key_id_enc); + json_builder_set_member_name(obj, _JSON_KEY_KEY_ID); + json_builder_add_string_value(obj, (char *)key_id_enc); + _INFO("keyid=[%s]", key_id_enc); + } + + } + + _INFO("after assertions"); + + _free_auth_reg_assertion_tlv(assrt_tlv); + + json_builder_end_object(obj); + + + assertions_iter = assertions_iter->next; + + } + + json_builder_end_array(auth_root); + /*authenticators*/ + + + json_builder_end_object(uaf_1_root); + + + json_builder_end_array(root_array); + + + JsonNode *root_builder = json_builder_get_root(builder); + JsonGenerator *gen = json_generator_new(); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *dereg_json = json_generator_to_data(gen, &len); + g_object_unref(gen); + + if (dereg_json != NULL) { + _INFO("_uaf_composer_compose_dereg_request return success"); + _INFO("%s", dereg_json); + return dereg_json; + } + + _INFO("_uaf_composer_compose_dereg_request return fail"); + return NULL; +} + +static _policy_t* +__get_policy(JsonObject *uaf_object) +{ + /*TODO : Check in spec whether accepted array can be NULL, i.e allow all?*/ + + JsonObject *policy_obj = json_object_get_object_member(uaf_object, _JSON_KEY_POLICY); + RET_IF_FAIL(policy_obj != NULL, NULL); + + JsonArray *accepted_array = json_object_get_array_member(policy_obj, _JSON_KEY_ACCEPTED); + RET_IF_FAIL(accepted_array != NULL, NULL); + + int accepted_len = json_array_get_length(accepted_array); + _INFO("Parser accepted list count [%d]", accepted_len); + + _policy_t *policy_info = (_policy_t *)calloc(1, sizeof(_policy_t)); + policy_info->is_keyid_present = false; + + GList *allowed_list = NULL; + + int i = 0; + for (i = 0; i < accepted_len; i++) { + + JsonArray *accepted_arr_inner = json_array_get_array_element(accepted_array, i); + if (accepted_arr_inner) { + int accepted_len_inner = json_array_get_length(accepted_arr_inner); + _INFO("Parser accepted list inner count [%d]", accepted_len_inner); + + int j = 0; + for (j = 0; j < accepted_len_inner; j++) { + GList *allowed_list_inner = NULL; + + JsonObject *match_obj = json_array_get_object_element(accepted_arr_inner, j); + if (match_obj) { + _match_criteria_t *match_info = _uaf_parser_parse_match(match_obj); + if (match_info) { + _INFO("Appending match_info"); + if (policy_info->is_keyid_present == false) { + if (match_info->key_id_list != NULL) + policy_info->is_keyid_present = true; + } + allowed_list_inner = g_list_append(allowed_list_inner, match_info); + } + } + if (j == (accepted_len_inner - 1)) { + if (allowed_list_inner) { + _INFO("Appending accepted list"); + allowed_list = g_list_append(allowed_list, allowed_list_inner); + } + } + } + } + } + + if (allowed_list != NULL) + policy_info->accepted_list = g_list_first(allowed_list); + + GList *disallowed_list = NULL; + + JsonArray *disallowed_array = json_object_get_array_member(policy_obj, _JSON_KEY_DISALLOWED); + if (disallowed_array != NULL) { + int disallowed_len = json_array_get_length(disallowed_array); + + for (i = 0; i < disallowed_len; i++) { + JsonObject *match_obj = json_array_get_object_element(disallowed_array, i); + if (match_obj) { + + _match_criteria_t *match_info = _uaf_parser_parse_match(match_obj); + if (match_info) { + if (policy_info->is_keyid_present == false) { + if (match_info->key_id_list != NULL) + policy_info->is_keyid_present = true; + } + disallowed_list = g_list_append(disallowed_list, match_info); + } + } + } + + if (disallowed_list != NULL) + policy_info->disallowed_list = g_list_first(disallowed_list); + } + + _INFO("returning policy [%p]", policy_info); + return policy_info; +} + +static _reg_request_t* +__parse_uaf_reg_message(JsonObject *uaf_object) +{ + _reg_request_t *reg_req_temp = (_reg_request_t *)calloc(1, sizeof(_reg_request_t)); + + reg_req_temp->challenge = __get_string_from_json_object(uaf_object, _JSON_KEY_CHALLENGE); + + reg_req_temp->user_name = __get_string_from_json_object(uaf_object, _JSON_KEY_USER_NAME); + + reg_req_temp->policy = __get_policy(uaf_object); + if (reg_req_temp->policy != NULL) + _INFO("parsed policy [%p]", reg_req_temp->policy); + else + _INFO("parsed policy [NULL]"); + + return reg_req_temp; +} + +static GList* +__get_transaction_list(JsonObject *uaf_obj) +{ + RET_IF_FAIL(uaf_obj != NULL, NULL); + + JsonArray *tr_arr = json_object_get_array_member(uaf_obj, _JSON_KEY_TRANSACTION); + RET_IF_FAIL(tr_arr != NULL, NULL); + + _INFO(""); + + GList *trans_list = NULL; + + int tr_arr_len = json_array_get_length(tr_arr); + int i = 0; + for (; i< tr_arr_len; i++) { + JsonObject *tr_obj = json_array_get_object_element(tr_arr, i); + if (tr_obj != NULL) { + + _auth_transaction_t *trans = calloc(1, sizeof(_auth_transaction_t)); + + trans->content_type = __get_string_from_json_object(tr_obj, _JSON_KEY_CONTENT_TYPE); + trans->content = __get_string_from_json_object(tr_obj, _JSON_KEY_CONTENT); + + /*tcDisplayPNGCharacteristics*/ + JsonObject *tc_disp_obj = json_object_get_object_member(tr_obj, _JSON_KEY_TC_DISP_PNG_CHARS); + if (tc_disp_obj != NULL) { + trans->display_charac = __get_png_data(tr_obj); + } + + trans_list = g_list_append(trans_list, trans); + } + } + + if (trans_list != NULL) { + trans_list = g_list_first(trans_list); + _INFO("Transaction list count = [%d]", g_list_length(trans_list)); + } + + _INFO(""); + return trans_list; +} + +static _auth_request_t* +__parse_uaf_auth_message(JsonObject *uaf_object) +{ + _auth_request_t *auth_req_temp = (_auth_request_t *)calloc(1, sizeof(_auth_request_t)); + + auth_req_temp->challenge = __get_string_from_json_object(uaf_object, _JSON_KEY_CHALLENGE); + + auth_req_temp->transaction_list = __get_transaction_list(uaf_object); + + auth_req_temp->policy = __get_policy(uaf_object); + + if (auth_req_temp->policy != NULL) + _INFO("parsed policy [%p]", auth_req_temp->policy); + else + _INFO("parsed policy [NULL]"); + + return auth_req_temp; +} + +static void +__dereg_auth_parser(JsonArray *array, guint index_, JsonNode *element_node, gpointer user_data) +{ + _dereg_request_t *dereg_req_temp = (_dereg_request_t *)user_data; + + JsonObject *auth_obj = json_node_get_object(element_node); + if (auth_obj != NULL) { + _dereg_auth_info_t *dereg_auth = (_dereg_auth_info_t*)calloc(1, sizeof(_dereg_auth_info_t)); + + dereg_auth->aaid = __get_string_from_json_object(auth_obj, _JSON_KEY_AAID); + dereg_auth->key_id = __get_string_from_json_object(auth_obj, _JSON_KEY_KEY_ID); + + dereg_req_temp->auth_info_list = g_list_append(dereg_req_temp->auth_info_list, dereg_auth); + } +} + +static _dereg_request_t* +__parse_uaf_dereg_message(JsonObject *uaf_object) +{ + _dereg_request_t *dereg_req_temp = (_dereg_request_t *)calloc(1, sizeof(_dereg_request_t)); + + JsonArray *auth_arr = json_object_get_array_member(uaf_object, _JSON_KEY_AUTHENTICATORS_SMALL); + if (auth_arr != NULL) { + json_array_foreach_element(auth_arr, __dereg_auth_parser, dereg_req_temp); + } + + return dereg_req_temp; +} + +_message_t * +_uaf_parser_parse_message(const char *uaf_json, const gchar *channel_binding) +{ + _INFO("_uaf_parser_parse_message"); + + RET_IF_FAIL(uaf_json != NULL, NULL); + + _message_t *uaf_message_temp = (_message_t*) calloc(1, sizeof(_message_t)); + uaf_message_temp->type = _MESSAGE_TYPE_MIN; + + if (channel_binding != NULL) { + if (strcmp(channel_binding, _FIDO_NO_CHANNEL_BINDING_DBUS_STRING) != 0) + uaf_message_temp->channel_binding = strdup(channel_binding); + } + + JsonParser *parser = json_parser_new(); + CATCH_IF_FAIL(parser != NULL); + + GError *parse_err = NULL; + json_parser_load_from_data(parser, uaf_json, -1, &parse_err); + CATCH_IF_FAIL(parse_err == NULL); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonArray *uaf_array = json_node_get_array(root); + CATCH_IF_FAIL(uaf_array != NULL); + + /* Parse all and accept only 1.0 version */ + + int uaf_arr_len = json_array_get_length(uaf_array); + if (uaf_arr_len <= 0) { + _ERR("No UAF message found"); + + _free_message(uaf_message_temp); + g_object_unref(parser); + return NULL; + } + + int i = 0; + for (; i < uaf_arr_len ; i++) { + JsonObject *uaf_object = json_array_get_object_element(uaf_array, i); + CATCH_IF_FAIL(uaf_object != NULL); + + JsonObject *header_obj = json_object_get_object_member(uaf_object, _JSON_KEY_HEADER); + CATCH_IF_FAIL(header_obj != NULL); + + uaf_message_temp->header = __parse_uaf_header(header_obj); + + /* NULL signifies the header version is not 1.0 */ + if (uaf_message_temp->header == NULL) + continue; + + if (strcmp(uaf_message_temp->header->operation, _UAF_OPERATION_NAME_KEY_REG) == 0){ + uaf_message_temp->data = (void *)__parse_uaf_reg_message(uaf_object); + if (uaf_message_temp->data == NULL) { + + _free_message(uaf_message_temp); + g_object_unref(parser); + + return NULL; + } + else { + uaf_message_temp->type = _MESSAGE_TYPE_REG; + + g_object_unref(parser); + + return uaf_message_temp; + } + } + + if (strcmp(uaf_message_temp->header->operation, _UAF_OPERATION_NAME_KEY_AUTH) == 0){ + uaf_message_temp->data = (void *)__parse_uaf_auth_message(uaf_object); + if (uaf_message_temp->data == NULL) { + + _free_message(uaf_message_temp); + g_object_unref(parser); + + return NULL; + } + else { + uaf_message_temp->type = _MESSAGE_TYPE_AUTH; + + g_object_unref(parser); + return uaf_message_temp; + + } + } + + if (strcmp(uaf_message_temp->header->operation, _UAF_OPERATION_NAME_KEY_DE_REG) == 0){ + uaf_message_temp->data = (void *)__parse_uaf_dereg_message(uaf_object); + if (uaf_message_temp->data == NULL) { + + _free_message(uaf_message_temp); + g_object_unref(parser); + + return NULL; + } + else { + uaf_message_temp->type = _MESSAGE_TYPE_DEREG; + + g_object_unref(parser); + return uaf_message_temp; + } + } + + } + +CATCH: + _free_message(uaf_message_temp); + if (parser != NULL) + g_object_unref(parser); + + return NULL; +} + +GList * +_uaf_parser_parse_trusted_facets(const char *json) +{ + JsonParser *parser = json_parser_new(); + + gsize len = -1; + GError *err = NULL; + + GList *app_id_list = NULL; + + bool is_parsed = json_parser_load_from_data(parser, json, len, &err); + CATCH_IF_FAIL(is_parsed == TRUE); + + + JsonNode *root = json_parser_get_root(parser); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + JsonArray *facet_arr = json_object_get_array_member(root_obj, _JSON_KEY_TRUSTED_FACETS); + CATCH_IF_FAIL(facet_arr != NULL); + + int facet_arr_len = json_array_get_length(facet_arr); + + int i = 0; + for (; i < facet_arr_len; i++) { + JsonObject *facet_obj = json_array_get_object_element(facet_arr, i); + if (facet_obj != NULL) { + + JsonObject *ver_obj = json_object_get_object_member(facet_obj, _JSON_KEY_VERSION); + if (ver_obj != NULL) { + int major = _INVALID_INT; + int minor = _INVALID_INT; + + major = json_object_get_int_member(ver_obj, _JSON_KEY_MAJOR); + minor = json_object_get_int_member(ver_obj, _JSON_KEY_MINOR); + + if (major == _VERSION_MAJOR && minor == _VERSION_MINOR) { + JsonArray *id_arr = json_object_get_array_member(facet_obj, _JSON_KEY_IDS); + if (id_arr != NULL) { + int id_arr_len = json_array_get_length(id_arr); + + int idx = 0; + for (; idx < id_arr_len; idx++) { + const char *id = json_array_get_string_element(id_arr, idx); + if (id != NULL) { + app_id_list = g_list_append(app_id_list, strdup(id)); + } + } + } + } + } + } + } + +CATCH: + if (parser != NULL) + g_object_unref(parser); + + if (app_id_list != NULL) + app_id_list = g_list_first(app_id_list); + + return app_id_list; +} + +_response_t* +_uaf_parser_parse_uaf_response(const char *uaf_response) +{ + RET_IF_FAIL(uaf_response != NULL, NULL); + + _response_t *uaf_res_temp = (_response_t*) calloc(1, sizeof(_response_t)); + + JsonParser *parser = json_parser_new(); + CATCH_IF_FAIL(parser != NULL); + + GError *parse_err = NULL; + json_parser_load_from_data(parser, uaf_response, -1, &parse_err); + CATCH_IF_FAIL(parse_err == NULL); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonArray *uaf_array = json_node_get_array(root); + CATCH_IF_FAIL(uaf_array != NULL); + + /* Parse all and accept only 1.0 version */ + + int uaf_arr_len = json_array_get_length(uaf_array); + CATCH_IF_FAIL(uaf_arr_len > 0); + + int i = 0; + for (; i < uaf_arr_len ; i++) { + JsonObject *uaf_object = json_array_get_object_element(uaf_array, i); + CATCH_IF_FAIL(uaf_object != NULL); + + JsonObject *header_obj = json_object_get_object_member(uaf_object, _JSON_KEY_HEADER); + CATCH_IF_FAIL(header_obj != NULL); + + uaf_res_temp->header = __parse_uaf_header(header_obj); + + /* NULL signifies the header version is not 1.0 */ + if (uaf_res_temp->header == NULL) + continue; + + char *op = uaf_res_temp->header->operation; + + /*Only process reg and auth responses*/ + if ((strcmp(op, _UAF_OPERATION_NAME_KEY_REG) != 0) + && (strcmp(op, _UAF_OPERATION_NAME_KEY_AUTH) != 0)) { + goto CATCH; + } + + uaf_res_temp->fcp = __get_string_from_json_object(uaf_object, _JSON_KEY_FC_PARAMS); + + JsonArray *assrt_json_arr = json_object_get_array_member(uaf_object, _JSON_KEY_ASSERTIONS); + CATCH_IF_FAIL(assrt_json_arr != NULL); + + int assrt_arr_len = json_array_get_length(assrt_json_arr); + int i = 0; + for (; i < assrt_arr_len; i++) { + JsonObject *assrt_json_obj = json_array_get_object_element(assrt_json_arr, i); + if (assrt_json_obj != NULL) { + + _auth_reg_assertion_t *assrt_data = (_auth_reg_assertion_t*)calloc(1, sizeof(_auth_reg_assertion_t)); + assrt_data->assertion = __get_string_from_json_object(assrt_json_obj, _JSON_KEY_ASSERTION); + assrt_data->assertion_schm = __get_string_from_json_object(assrt_json_obj, _JSON_KEY_ASSERT_SCHEME); + + uaf_res_temp->assertion_list = g_list_append(uaf_res_temp->assertion_list, assrt_data); + + } + } + + } + + g_object_unref(parser); + _INFO("before _uaf_parser_parse_uaf_response end"); + return uaf_res_temp; + +CATCH: + if (parser != NULL) + g_object_unref(parser); + + if (uaf_res_temp != NULL) + _free_response(uaf_res_temp); + + return NULL; +} + +static int +__print_string_list(GList *list) +{ + RET_IF_FAIL(list != NULL, -1); + + GList *list_iter = g_list_first(list); + while (list_iter != NULL) { + char *data = (char*) (list->data); + if (data != NULL) + _INFO("[%s]", data); + + list_iter = list_iter->next; + } + + return 0; +} + +_asm_get_reg_out_t * +_uaf_parser_parser_asm_get_reg_response(const char *get_reg_resp) +{ + _INFO("_uaf_parser_parser_asm_get_reg_response start"); + + RET_IF_FAIL(get_reg_resp != NULL, NULL); + + JsonParser *parser = json_parser_new(); + RET_IF_FAIL(parser != NULL, NULL); + + GError *parser_err = NULL; + gboolean is_parsed = json_parser_load_from_data(parser, get_reg_resp, -1, &parser_err); + RET_IF_FAIL(is_parsed == TRUE, NULL); + + _INFO(""); + + _asm_get_reg_out_t *reg_out = NULL; + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + _INFO(""); + + /*responseData*/ + JsonObject *res_obj = json_object_get_object_member(root_obj, _JSON_KEY_RESP_DATA); + CATCH_IF_FAIL(res_obj != NULL); + + /*appRegs*/ + JsonArray *app_reg_json_arr = json_object_get_array_member(res_obj, _JSON_KEY_APP_REGS); + CATCH_IF_FAIL(app_reg_json_arr != NULL); + + _INFO(""); + + int app_reg_json_arr_len = json_array_get_length(app_reg_json_arr); + CATCH_IF_FAIL(app_reg_json_arr_len > 0); + + reg_out = (_asm_get_reg_out_t*) calloc(1, sizeof(_asm_get_reg_out_t)); + + int i = 0; + for (; i < app_reg_json_arr_len; i++) { + JsonObject *app_reg_json_obj = json_array_get_object_element(app_reg_json_arr, i); + if (app_reg_json_obj != NULL) { + /*appID*/ + const char *app_id = json_object_get_string_member(app_reg_json_obj, _JSON_KEY_APPID); + + _INFO(""); + + /*keyIDs*/ + JsonArray *key_id_json_arr = json_object_get_array_member(app_reg_json_obj, _JSON_KEY_KEY_IDS); + GList *key_id_list = __get_string_list_from_json_array(key_id_json_arr); + + if (app_id != NULL || key_id_list != NULL) { + _asm_app_reg_t *app_reg = (_asm_app_reg_t*) calloc(1, sizeof(_asm_app_reg_t)); + + if (app_id != NULL) { + _INFO("app_id = [%s]", app_id); + app_reg->app_id = strdup(app_id); + } + + app_reg->key_id_list = key_id_list; + __print_string_list(key_id_list); + + reg_out->app_reg_list = g_list_append(reg_out->app_reg_list, app_reg); + _INFO(""); + + } + } + } + + _INFO(""); + /*statusCode*/ + reg_out->status_code = __get_int_from_json_object(root_obj, _JSON_KEY_STATUS_CODE); + +CATCH: + g_object_unref(parser); + + _INFO("_uaf_parser_parser_asm_get_reg_response end"); + return reg_out; +} + +char * +_uaf_composer_compose_get_registrations_request(const char *auth_index) +{ + _INFO("_uaf_composer_compose_get_registrations_request"); + + JsonBuilder *builder = json_builder_new(); + + json_builder_begin_object(builder); + + /*Version : 1.0*/ + json_builder_set_member_name(builder, _JSON_KEY_ASM_VERSION); + json_builder_begin_object(builder); + json_builder_set_member_name(builder, _JSON_KEY_MAJOR); + json_builder_add_int_value(builder, _VERSION_MAJOR); + json_builder_set_member_name(builder, _JSON_KEY_MINOR); + json_builder_add_int_value(builder, _VERSION_MINOR); + json_builder_end_object(builder); + + /*authenticatorIndex*/ + json_builder_set_member_name(builder, _JSON_KEY_AUTH_INDEX); + int auth_index_int = -1; + sscanf(auth_index, "%d", &auth_index_int); + json_builder_add_int_value(builder, auth_index_int); + + + /*requestType : "GetRegistrations" */ + json_builder_set_member_name(builder, _JSON_KEY_REQ_TYPE); + json_builder_add_string_value(builder, _JSON_KEY_GET_REGS); + + + json_builder_end_object(builder); + + JsonNode *root_builder = json_builder_get_root(builder); + JsonGenerator *gen = json_generator_new(); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *json = json_generator_to_data(gen, &len); + + if (json != NULL) + _INFO("%s", json); + + g_object_unref(gen); + return json; +} + +int +_convert_asm_status_code_to_uaf_error(int asm_status_code) +{ + switch (asm_status_code) { + + case _ASM_STATUS_OK: + return FIDO_ERROR_NONE; + + case _ASM_STATUS_ERROR: + return FIDO_ERROR_UNKNOWN; + + case _ASM_STATUS_ACCESS_DENIED: + return FIDO_ERROR_PERMISSION_DENIED; + + case _ASM_STATUS_USER_CANCELLED: + return FIDO_ERROR_USER_CANCELLED; + + default: + return FIDO_ERROR_UNKNOWN; + } +} + +/* +{ + "vendor" : "Samsung Electronics", + "bin_path" : "/usr/bin/fido-asm", + "dbus_info" : "org.tizen.fido_uaf_asm.server", + "dbus_obj_path" : "/org/tizen/fido_uaf_asm/server", + "dbus_interface_name" : "org.tizen.fido_uaf_asm.server.interface", + "dbus_method_name" : "asm_request" +} +*/ + +_fido_asm_proxy_t* +_parse_asm_conf_file(const char *file_name) +{ + _INFO("_parse_asm_conf_file"); + + RET_IF_FAIL(file_name != NULL, NULL); + + JsonParser *parser = json_parser_new(); + + _fido_asm_proxy_t *proxy = NULL; + GError *err = NULL; + gboolean is_parsed = json_parser_load_from_file(parser, file_name, &err); + CATCH_IF_FAIL(is_parsed == TRUE); + + JsonNode *root = json_parser_get_root(parser); + CATCH_IF_FAIL(root != NULL); + + JsonObject *root_obj = json_node_get_object(root); + CATCH_IF_FAIL(root_obj != NULL); + + const char *vendor = json_object_get_string_member(root_obj, _JSON_KEY_VENDOR); + CATCH_IF_FAIL(vendor != NULL); + + const char *bin_path = json_object_get_string_member(root_obj, _JSON_KEY_BIN_PATH); + CATCH_IF_FAIL(bin_path != NULL); + + const char *dbus_info = json_object_get_string_member(root_obj, _JSON_KEY_DBUS_INFO); + CATCH_IF_FAIL(dbus_info != NULL); + + const char *dbus_obj_path = json_object_get_string_member(root_obj, _JSON_KEY_DBUS_OBJ_PATH); + CATCH_IF_FAIL(dbus_obj_path != NULL); + + const char *dbus_interface_name = json_object_get_string_member(root_obj, _JSON_KEY_DBUS_INTF_NAME); + CATCH_IF_FAIL(dbus_interface_name != NULL); + + const char *dbus_method_name = json_object_get_string_member(root_obj, _JSON_KEY_DBUS_METHOD_NAME); + CATCH_IF_FAIL(dbus_method_name != NULL); + + proxy = calloc(1, sizeof(_fido_asm_proxy_t)); + + proxy->vendor = strdup(vendor); + proxy->bin_path = strdup(bin_path); + proxy->dbus_info = strdup(dbus_info); + proxy->dbus_obj_path = strdup(dbus_obj_path); + proxy->dbus_interface_name = strdup(dbus_interface_name); + proxy->dbus_method_name = strdup(dbus_method_name); + +CATCH: + g_object_unref(parser); + return proxy; +} diff --git a/common/fido_json_handler.h b/common/fido_json_handler.h new file mode 100644 index 0000000..f6ade12 --- /dev/null +++ b/common/fido_json_handler.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_JSON_PARSER_H_ +#define FIDO_JSON_PARSER_H_ + +#include +#include +#include "fido_uaf_types.h" +#include "fido_internal_types.h" + +_message_t *_uaf_parser_parse_message(const char *uaf_json, const gchar *channel_binding); + +/*List of fido_authenticator_s */ +GList* _uaf_parser_parse_asm_response_discover(GList *asm_response_list, int *error_code); +GList* _uaf_parser_parse_asm_response_discover_client(char **asm_response_list, int len, int *error_code); + +_asm_out_t *_uaf_parser_parse_asm_response_reg(const char *asm_response_json, int *error_code); + +_asm_out_t *_uaf_parser_parse_asm_response_auth(const char *asm_response_json, int *error_code); + +_asm_dereg_out_t *_uaf_parser_parse_asm_response_dereg(const char *asm_response_json, int *error_code); + +GList *_uaf_parser_parse_trusted_facets(const char *json); + +_response_t *_uaf_parser_parse_uaf_response(const char *uaf_response); + +_asm_get_reg_out_t *_uaf_parser_parser_asm_get_reg_response(const char *get_reg_resp); + +int _uaf_composer_compose_asm_reg_request(_version_t *version, int auth_index, _fido_asm_reg_in_t *reg_in, char **asm_reg_json); + +int _uaf_composer_compose_asm_auth_request(_version_t *version, int auth_index, _fido_asm_auth_in_t *auth_in, char **asm_auth_json); + +int _uaf_composer_compose_asm_dereg_request(_version_t *version, int auth_index, _matched_auth_dereg_t *dereg_in, char **asm_dereg_json); + +char* _uaf_composer_compose_final_challenge(const char *app_id, const char *challenge, const char *facet_id, const char *ch_bin); + +int _uaf_composer_compose_uaf_process_response_reg(_op_header_t *header, char *final_ch, GList *assertions, char **uaf_response); + +int _uaf_composer_compose_uaf_process_response_auth(_op_header_t *header, char *final_ch, GList *assertions, char **uaf_response); + +char *_uaf_composer_compose_dereg_request(_response_t *uaf_res); + +char *_uaf_composer_compose_get_registrations_request(const char *auth_index); + +int _convert_asm_status_code_to_uaf_error(int asm_status_code); + +_fido_asm_proxy_t* _parse_asm_conf_file(const char *file_name); + + +#endif /* FIDO_JSON_PARSER_H_ */ diff --git a/common/fido_keys.h b/common/fido_keys.h new file mode 100644 index 0000000..9b1e629 --- /dev/null +++ b/common/fido_keys.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_KEYS_H +#define FIDO_KEYS_H + +#include + +typedef enum { + _USER_VER_METHOD_MIN = -1, + _USER_VER_METHOD_PRESENCE = 0X01, + _USER_VER_METHOD_FINGERPRINT = 0X02, + _USER_VER_METHOD_PASSCODE = 0X04, + _USER_VER_METHOD_VOICE_PRINT = 0X08, + _USER_VER_METHOD_FACE_PRINT = 0X10, + _USER_VER_METHOD_LOCATION = 0X20, + _USER_VER_METHOD_EYE_PRINT = 0X40, + _USER_VER_METHOD_PATTERN = 0X80, + _USER_VER_METHOD_HAND_PRINT = 0X100, + _USER_VER_METHOD_NONE = 0X200, + _USER_VER_METHOD_ALL = 0X400, + _USER_VER_METHOD_MAX +}_user_verification_method_e; + +#define _UAF_OPERATION_NAME_KEY_REG "Reg" + +#define _UAF_OPERATION_NAME_KEY_AUTH "Auth" + +#define _UAF_OPERATION_NAME_KEY_DE_REG "Dereg" + +#define TAG_UAFV1_REG_ASSERTION 0x3E01 + +#define TAG_UAFV1_AUTH_ASSERTION 0x3E02 + +#define TAG_UAFV1_KRD 0x3E03 + +#define TAG_UAFV1_SIGNED_DATA 0x3E04 + +#define TAG_ATTESTATION_CERT 0x2E05 + +#define TAG_SIGNATURE 0x2E06 + +#define TAG_ATTESTATION_BASIC_FULL 0x3E07 + +#define TAG_ATTESTATION_BASIC_SURROGATE 0x3E08 + +#define TAG_KEYID 0x2E09 + +#define TAG_FINAL_CHALLENGE 0x2E0A + +#define TAG_AAID 0x2E0B + +#define TAG_PUB_KEY 0x2E0C + +#define TAG_COUNTERS 0x2E0D + +#define TAG_ASSERTION_INFO 0x2E0E + +#define TAG_AUTHENTICATOR_NONCE 0x2E0F + +#define TAG_TRANSACTION_CONTENT_HASH 0x2E10 + +#define TAG_EXTENSION 0x3E11, 0x3E12 + +#define TAG_EXTENSION_ID 0x2E13 + +#define TAG_EXTENSION_DATA 0x2E14 + +#endif // FIDO_KEYS_H diff --git a/common/fido_logs.h b/common/fido_logs.h new file mode 100644 index 0000000..1648f30 --- /dev/null +++ b/common/fido_logs.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef __FIDO_LOGS_H__ + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "org.tizen.fido" + +#ifndef _ERR +#define _ERR(fmt, args...) LOGE("[%s:%d] "fmt"\n", __func__, __LINE__, ##args) +#endif + +#ifndef _DBG +#define _DBG(fmt, args...) LOGD("[%s:%d] "fmt"\n", __func__, __LINE__, ##args) +#endif + +#ifndef _INFO +#define _INFO(fmt, args...) LOGI("[%s:%d] "fmt"\n", __func__, __LINE__, ##args) +#endif + +#endif /* __FIDO_LOGS_H__ */ diff --git a/common/fido_tlv_util.c b/common/fido_tlv_util.c new file mode 100644 index 0000000..c84b2a4 --- /dev/null +++ b/common/fido_tlv_util.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include "fido_internal_types.h" +#include "fido_logs.h" +#include "fido_keys.h" +#include "fido_b64_util.h" +#include "fido_tlv_util.h" + +static _tlv_t* +__get_tlv_pack_by_type(const guchar *tlv_buffer_in, uint16_t type_in, int max_len_in) +{ + //_INFO("__get_tlv_pack_by_type [%u]", type_in); + + int i = 0; + + while (1) { + uint16_t lb = tlv_buffer_in[i + 0]; + uint16_t hb = tlv_buffer_in[i + 1]; + + uint16_t val = hb << 8; + val = val | lb; + + uint16_t type = val; + + lb = 0; + hb = 0; + val = 0; + + lb = tlv_buffer_in[i + 2]; + hb = tlv_buffer_in[i + 3]; + + val = hb << 8; + val = val | lb; + + uint16_t length = val; + + if (type == type_in) { + _tlv_t *tlv = (_tlv_t*)calloc(1, sizeof(_tlv_t)); + tlv->type = type; + tlv->len = length; + if (tlv->len > 0) { + tlv->val = (uint8_t *)calloc(1, tlv->len); + memcpy(tlv->val, tlv_buffer_in + i + 2 + 2, tlv->len); + } + //_INFO("Found key"); + return tlv; + } + + i += 2 + 2 + length; + if (i >= max_len_in) + break; + } + + return NULL; +} + + +_auth_reg_assertion_tlv_t* +_tlv_util_decode_reg_assertion(char *tlv_enc) +{ + _INFO("_tlv_util_decode_reg_assertion"); + + RET_IF_FAIL(tlv_enc != NULL, NULL); + + _INFO("%s", tlv_enc); + + int in_len = strlen(tlv_enc); + int tlv_dec_len = in_len * 1.5; + unsigned char *tlv_dec = calloc(1, tlv_dec_len); + + int r = _fido_b64url_decode((unsigned char *)tlv_enc, in_len, tlv_dec, &tlv_dec_len); + RET_IF_FAIL(r == 0, NULL); + + _INFO("in len = [%d], decoded len = [%d]", in_len, tlv_dec_len); + + _tlv_t *reg_tlv = __get_tlv_pack_by_type(tlv_dec, TAG_UAFV1_REG_ASSERTION, tlv_dec_len); + if (reg_tlv != NULL) { + _INFO("Found TAG_UAFV1_REG_ASSERTION"); + + _free_tlv(reg_tlv); + + int krd_start_idx = 2 + 2; + + _tlv_t *krd_tlv = __get_tlv_pack_by_type(tlv_dec + krd_start_idx, TAG_UAFV1_KRD, (tlv_dec_len - krd_start_idx)); + if (krd_tlv != NULL) { + _INFO("Found TAG_UAFV1_KRD"); + _free_tlv(krd_tlv); + + int krd_inner_start_idx = krd_start_idx + 2 + 2; + + _tlv_t *aaid_tlv = __get_tlv_pack_by_type(tlv_dec + krd_inner_start_idx, TAG_AAID, (tlv_dec_len - krd_inner_start_idx)); + + _tlv_t *key_id_tlv = __get_tlv_pack_by_type(tlv_dec + krd_inner_start_idx, TAG_KEYID, (tlv_dec_len - krd_inner_start_idx)); + + + _auth_reg_assertion_tlv_t *assrt_tlv = (_auth_reg_assertion_tlv_t*)calloc(1, sizeof(_auth_reg_assertion_tlv_t)); + + if (aaid_tlv != NULL) { + _INFO("Found TAG_AAID"); + + assrt_tlv->aaid = (char*)calloc(1, aaid_tlv->len + 1); + memcpy(assrt_tlv->aaid, aaid_tlv->val, aaid_tlv->len); + + _free_tlv(aaid_tlv); + } + + if (key_id_tlv != NULL) { + _INFO("Found TAG_KEYID"); + + assrt_tlv->key_id = (unsigned char*)calloc(1, key_id_tlv->len); + memcpy(assrt_tlv->key_id, key_id_tlv->val, key_id_tlv->len); + + assrt_tlv->key_id_len = key_id_tlv->len; + + _INFO("key_id len = [%d]", key_id_tlv->len); + + _free_tlv(key_id_tlv); + } + + _INFO("Found TAG_KEYID"); + return assrt_tlv; + } + } + + + return NULL; +} + diff --git a/common/fido_tlv_util.h b/common/fido_tlv_util.h new file mode 100644 index 0000000..6d98d1e --- /dev/null +++ b/common/fido_tlv_util.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_TLV_UTIL_H_ +#define FIDO_TLV_UTIL_H_ + +#include +#include +#include "fido_internal_types.h" + +_auth_reg_assertion_tlv_t* _tlv_util_decode_reg_assertion(char *tlv_enc); + + +#endif /* FIDO_TLV_UTIL_H_ */ + + diff --git a/common/fido_uaf_types.h b/common/fido_uaf_types.h new file mode 100644 index 0000000..095ec56 --- /dev/null +++ b/common/fido_uaf_types.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_UAF_TYPES_H_ +#define FIDO_UAF_TYPES_H_ + +#include +#include + +/** + * @addtogroup CAPI_FIDO_MODULE + * @{ + */ + +/** + * @file fido_uaf_types.h + * @brief The FIDO UAF Client API enums and typedefs. + */ + +/** + * @brief The structure type for the Authenticator handle. + * @since_tizen 3.0 + */ +typedef struct fido_authenticator_s* fido_authenticator_h; + +#define TIZEN_ERROR_FIDO -0x01030000 + +/** + * @brief Enumerations of error codes for FIDO APIs. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful. */ + FIDO_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory. */ + FIDO_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter. */ + FIDO_ERROR_NO_DATA = TIZEN_ERROR_NO_DATA, /**< Empty data. */ + FIDO_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission Denied. */ + + FIDO_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< FIDO is unsupported. */ + FIDO_ERROR_USER_ACTION_IN_PROGRESS = TIZEN_ERROR_FIDO | 0x01, /**< User action is in progress. */ + FIDO_ERROR_USER_CANCELLED = TIZEN_ERROR_FIDO | 0x02, /**< User has canceled the operation. */ + FIDO_ERROR_UNSUPPORTED_VERSION = TIZEN_ERROR_FIDO | 0x03, /**< UAF message's version is not supported. */ + FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR = TIZEN_ERROR_FIDO | 0x04, /**< No suitable authenticators found. */ + FIDO_ERROR_PROTOCOL_ERROR = TIZEN_ERROR_FIDO | 0x05, /**< Protocol error, the interaction may have timed out, or + the UAF message is malformed. */ + FIDO_ERROR_UNTRUSTED_FACET_ID = TIZEN_ERROR_FIDO | 0x06, /**< The caller's id is not allowed to use this operation. */ + FIDO_ERROR_UNKNOWN = TIZEN_ERROR_UNKNOWN /**< Unknown system error.*/ + +} fido_error_e; + +/** + * @brief Authenticator's supported algorithm and encoding. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_ALGO_SECP256R1_ECDSA_SHA256_RAW = 0X01, /**< SECP256R1 ECDSA SHA256 Raw */ + FIDO_AUTH_ALGO_SECP256R1_ECDSA_SHA256_DER = 0X02, /**< SECP256R1 ECDSA SHA256 DER*/ + FIDO_AUTH_ALGO_RSASSA_PSS_SHA256_RAW = 0x03, /**< RSA PSS SHA256 Raw*/ + FIDO_AUTH_ALGO_RSASSA_PSS_SHA256_DER = 0x04, /**< RSA PSS SHA256 DER*/ + FIDO_AUTH_ALGO_SECP256K1_ECDSA_SHA256_RAW = 0x05, /**< SECP256K1 ECDSA SHA256 Raw*/ + FIDO_AUTH_ALGO_SECP256K1_ECDSA_SHA256_DER = 0x06 /**< SECP256K1 ECDSA SHA256 DER*/ +} fido_auth_algo_e; + +/** + * @brief Authenticator's supported Attestation type. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_ATT_TYPE_BASIC_FULL = 0x3E07, /**< Full basic attestation. */ + FIDO_AUTH_ATT_TYPE_BASIC_SURROGATE = 0x3E08 /**< Surrogate basic attestation. */ +} fido_auth_attestation_type_e; + +/** + * @brief Authenticator's supported user verification method type. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_USR_VERIFY_TYPE_PRESENCE = 0x01, /**< User presence verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_FINGERPRINT = 0x02, /**< User fingerprint verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_PASSCODE = 0x04, /**< User passcode verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_VOICEPRINT = 0x08, /**< User voiceprint verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_FACEPRINT = 0x10, /**< User faceprint verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_LOCATION = 0x20, /**< User location verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_EYEPRINT = 0x40, /**< User eyeprint verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_PATTERN = 0x80, /**< User pattern verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_HANDPRINT = 0x100, /**< User handprint verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_NONE = 0x200, /**< Silent verification. */ + FIDO_AUTH_USR_VERIFY_TYPE_ALL = 0x400 /**< If an authenticator sets multiple flags for user verification types, + * it may also set this flag to indicate that all verification methods will be enforced + * (e.g. faceprint AND voiceprint). If flags for multiple user verification methods are set + * and this flag is not set, verification with only one is necessary + * (e.g. fingerprint OR passcode). + */ +} fido_auth_user_verify_type_e; + +/** + * @brief Authenticator's supported key protection method type. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_KEY_PROT_TYPE_SOFTWARE = 0x01, /**< Software based key management. */ + FIDO_AUTH_KEY_PROT_TYPE_HARDWARE = 0x02, /**< Hardware based key management. */ + FIDO_AUTH_KEY_PROT_TYPE_TEE = 0x04, /**< Trusted Execution Environment based key management. */ + FIDO_AUTH_KEY_PROT_TYPE_SECURE_ELEMENT = 0x08, /**< Secure Element based key management. */ + FIDO_AUTH_KEY_PROT_TYPE_REMOTE_HANDLE = 0x10 /**< Authenticator does not store (wrapped) UAuth keys at the client, + * but relies on a server-provided key handle. + */ +} fido_auth_key_protection_type_e; + +/** + * @brief Authenticator's supported matcher protection type. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_MATCH_PROT_TYPE_SOFTWARE = 0x01, /**< Authenticator's matcher is running in software. */ + FIDO_AUTH_MATCH_PROT_TYPE_TEE = 0x02, /**< Authenticator's matcher is running inside the Trusted Execution Environment. */ + FIDO_AUTH_MATCH_PROT_TYPE_ON_CHIP = 0x04 /**< Aauthenticator's matcher is running on the chip. */ +} fido_auth_matcher_protection_type_e; + +/** + * @brief Authenticator's supproted method to communicate to FIDO user device. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_ATTACH_HINT_INTERNAL = 0x01, /**< Authenticator is permanently attached to the FIDO User Device. */ + FIDO_AUTH_ATTACH_HINT_EXTERNAL = 0x02, /**< Authenticator is removable or remote from the FIDO User Device. */ + FIDO_AUTH_ATTACH_HINT_WIRED = 0x04, /**< The external authenticator currently has an exclusive wired connection. */ + FIDO_AUTH_ATTACH_HINT_WIRELESS = 0x08, /**< The external authenticator communicates with the FIDO User Device through + * wireless means. */ + FIDO_AUTH_ATTACH_HINT_NFC = 0x10, /**< Authenticator is able to communicate by NFC to the FIDO User Device. */ + FIDO_AUTH_ATTACH_HINT_BT = 0x20, /**< Authenticator is able to communicate by Bluetooth to the FIDO User Device. */ + FIDO_AUTH_ATTACH_HINT_NW = 0x40, /**< Authenticator is connected to the FIDO User Device ver a non-exclusive network + * (e.g. over a TCP/IP LAN or WAN, as opposed to a PAN or point-to-point connection). + */ + FIDO_AUTH_ATTACH_HINT_READY = 0x80, /**< The external authenticator is in a "ready" state. */ + FIDO_AUTH_ATTACH_HINT_WIFI_DIRECT = 0x100 /**< The external authenticator is able to + * communicate using WiFi Direct with the FIDO User Device. + */ +} fido_auth_attachment_hint_e; + +/** + * @brief Transaction confirmation display capability type. + * @remarks Refer to FIDO UAF Registry document for more details. + * @since_tizen 3.0 + */ +typedef enum +{ + FIDO_AUTH_TC_DISP_TYPE_ANY = 0x01, /**< Some form of transaction confirmation display is available on this authenticator. */ + FIDO_AUTH_TC_DISP_TYPE_PRIVILEGED_SOFTWARE = 0x02, /**< Software-based transaction confirmation display operating in a + * privileged context is available on this authenticator. + */ + FIDO_AUTH_TC_DISP_TYPE_TEE = 0x04, /**< Transaction confirmation display is in a Trusted Execution Environment. */ + FIDO_AUTH_TC_DISP_TYPE_HW = 0x08, /**< Transaction confirmation display based on hardware assisted capabilities is available on this authenticator.*/ + FIDO_AUTH_TC_DISP_TYPE_REMOTE = 0x10 /**< Transaction confirmation display is provided on a distinct device from the FIDO User Device. */ +} fido_auth_tc_display_type_e; + + +/** + * @brief The FIDO Server response for successfull interaction. + * @since_tizen 3.0 + */ +#define FIDO_SERVER_STATUS_CODE_OK 1200 + +/** + * @} + */ + +#endif /* FIDO_UAF_TYPES_H_ */ diff --git a/common/fido_uaf_utils.c b/common/fido_uaf_utils.c new file mode 100644 index 0000000..d440f30 --- /dev/null +++ b/common/fido_uaf_utils.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include "fido_logs.h" +#include "fido_internal_types.h" + +void +_free_extension(_extension_t *data) +{ + _INFO(""); + + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->id); + SAFE_DELETE(data->data); + SAFE_DELETE(data); + _INFO(""); +} + +static void +_free_extension_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_extension((_extension_t*)data); + _INFO(""); +} + +void +_free_match_criteria(_match_criteria_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + if (data->aaid_list != NULL) + g_list_free_full(data->aaid_list, free); + + if (data->vendor_list != NULL) + g_list_free_full(data->vendor_list, free); + + if (data->key_id_list != NULL) + g_list_free_full(data->key_id_list, free); + + if (data->auth_algo_list != NULL) + g_list_free(data->auth_algo_list); + + if (data->assertion_scheme_list != NULL) + g_list_free_full(data->assertion_scheme_list, free); + + if (data->attestation_type_list != NULL) + g_list_free_full(data->attestation_type_list, free); + + if (data->extension_list != NULL) + g_list_free_full(data->extension_list, _free_extension_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +static void +_free_uaf_accepted_list_inner_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_match_criteria((_match_criteria_t*)data); + _INFO(""); +} + +static void +_free_uaf_accepted_list_outer_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + GList *list = (GList*)data; + if (list != NULL) + g_list_free_full(list, _free_uaf_accepted_list_inner_item); + _INFO(""); +} + +static void +_free_uaf_disallowed_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_match_criteria((_match_criteria_t*)data); + _INFO(""); +} + +void +_free_policy(_policy_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + if (data->accepted_list != NULL) + g_list_free_full(data->accepted_list, _free_uaf_accepted_list_outer_item); + + if (data->disallowed_list != NULL) + g_list_free_full(data->disallowed_list, _free_uaf_disallowed_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_op_header(_op_header_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->version); + SAFE_DELETE(data->operation); + SAFE_DELETE(data->app_id); + SAFE_DELETE(data->server_data); + + if (data->ext_list != NULL) + g_list_free_full(data->ext_list, _free_extension_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_message(_message_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->facet_id); + + _free_op_header(data->header); + + SAFE_DELETE(data->channel_binding); + + switch (data->type) { + + case _MESSAGE_TYPE_REG: + _free_reg_request((_reg_request_t*)(data->data)); + break; + + case _MESSAGE_TYPE_AUTH: + _free_auth_request((_auth_request_t*)(data->data)); + break; + + case _MESSAGE_TYPE_DEREG: + _free_dereg_request((_dereg_request_t*)(data->data)); + break; + + default: + SAFE_DELETE(data->data); + } + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_reg_request(_reg_request_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->challenge); + SAFE_DELETE(data->user_name); + + _free_policy(data->policy); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_display_png_characteristics_descriptor(fido_display_png_characteristics_descriptor_s *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + if (data->plte != NULL) + g_list_free_full(data->plte, free); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_auth_transaction(_auth_transaction_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->content); + SAFE_DELETE(data->content_type); + + _free_display_png_characteristics_descriptor(data->display_charac); + + SAFE_DELETE(data); + _INFO(""); +} + +static void +__free_auth_transaction_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_auth_transaction((_auth_transaction_t*)data); + _INFO(""); +} + +void +_free_auth_request(_auth_request_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->challenge); + + _free_policy(data->policy); + + if (data->transaction_list != NULL) + g_list_free_full(data->transaction_list, __free_auth_transaction_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_dereg_auth_info(_dereg_auth_info_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->aaid); + SAFE_DELETE(data->key_id); + SAFE_DELETE(data); + _INFO(""); +} + +static void +__free_dereg_auth_info_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_dereg_auth_info((_dereg_auth_info_t*)data); + _INFO(""); +} + +void +_free_dereg_request(_dereg_request_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + if (data->auth_info_list != NULL) + g_list_free_full(data->auth_info_list, __free_dereg_auth_info_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_asm_display_png_characteristics_descriptor_t(_fido_asm_display_png_characteristics_descriptor_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + if (data->plte != NULL) + g_list_free_full(data->plte, free); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_fido_asm_proxy(void *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _fido_asm_proxy_t *data_impl = (_fido_asm_proxy_t*)data; + SAFE_DELETE(data_impl->asm_id); + SAFE_DELETE(data_impl->vendor); + SAFE_DELETE(data_impl->bin_path); + SAFE_DELETE(data_impl->dbus_info); + SAFE_DELETE(data_impl->dbus_obj_path); + SAFE_DELETE(data_impl->dbus_interface_name); + SAFE_DELETE(data_impl->dbus_method_name); + + g_object_unref(data_impl->dbus_proxy); + + SAFE_DELETE(data_impl); + + _INFO(""); +} + +void +_free_asm_discover_response(_asm_discover_response_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->asm_id); + SAFE_DELETE(data->asm_response_json); + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_fido_asm_authenticator(fido_authenticator_s *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->asm_id); + + _INFO(""); + + SAFE_DELETE(data->auth_index); + + _INFO(""); + + if (data->key_ids != NULL) + g_list_free_full(data->key_ids, free); + _INFO(""); + + /*TODO : asm_versions is not used anywhere*/ + + SAFE_DELETE(data->aaid); + _INFO(""); + + SAFE_DELETE(data->assertion_scheme); + _INFO(""); + + if (data->attestation_types != NULL) + g_list_free(data->attestation_types); + _INFO(""); + + if (data->supported_extension_IDs != NULL) + g_list_free_full(data->supported_extension_IDs, free); + _INFO(""); + + SAFE_DELETE(data->tc_display_content_type); + _INFO(""); + + if (data->tc_display_png_characteristics != NULL) + g_list_free_full(data->tc_display_png_characteristics, _free_tc_disp_png_char); + _INFO(""); + + SAFE_DELETE(data->title); + _INFO(""); + + SAFE_DELETE(data->description); + _INFO(""); + + SAFE_DELETE(data->icon); + _INFO(""); + + if (data->supported_versions != NULL) + g_list_free_full(data->supported_versions, free); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_fido_asm_authenticator_list_item(gpointer data) +{ + RET_IF_FAIL_VOID(data != NULL); + + fido_authenticator_s *data_impl = (fido_authenticator_s*)data; + + _free_fido_asm_authenticator(data_impl); +} + +void +_free_fido_asm_reg_in(_fido_asm_reg_in_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->app_id); + SAFE_DELETE(data->user_name); + SAFE_DELETE(data->final_challenge); + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_fido_asm_transaction(_fido_asm_transaction_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->content); + SAFE_DELETE(data->content_type); + _free_asm_display_png_characteristics_descriptor_t(data->display_charac); + SAFE_DELETE(data); + _INFO(""); +} + +static void +__free_fido_asm_transaction_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_fido_asm_transaction((_fido_asm_transaction_t *)data); + _INFO(""); +} + +void +_free_fido_asm_auth_in(_fido_asm_auth_in_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->app_id); + SAFE_DELETE(data->final_challenge); + if (data->key_ids != NULL) + g_list_free_full(data->key_ids, free); + + if (data->trans_list != NULL) + g_list_free_full(data->trans_list, __free_fido_asm_transaction_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_fido_asm_dereg_in(_fido_asm_dereg_in_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->app_id); + SAFE_DELETE(data->key_id); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_ui_auth_data(_ui_auth_data_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->asm_id); + SAFE_DELETE(data->auth_index); + SAFE_DELETE(data->label); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_auth_reg_assertion(_auth_reg_assertion_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->assertion_schm); + SAFE_DELETE(data->assertion); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_auth_reg_assertion_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_auth_reg_assertion((_auth_reg_assertion_t*)data); + _INFO(""); +} + +void +_free_asm_out(_asm_out_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + switch (data->type) { + + case _ASM_OUT_TYPE_REG: + _free_asm_reg_out((_asm_reg_out_t*)(data->response_data)); + break; + + case _ASM_OUT_TYPE_AUTH: + _free_asm_auth_out((_asm_auth_out_t*)(data->response_data)); + break; + + default: + SAFE_DELETE(data->response_data); + } + + if (data->ext_list != NULL) { + _INFO("Freeing ext list"); + g_list_free_full(data->ext_list, free); + _INFO("After Freeing ext list"); + } + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_asm_reg_out(_asm_reg_out_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->assertion); + SAFE_DELETE(data->assertion_schm); + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_asm_auth_out(_asm_auth_out_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->assertion); + SAFE_DELETE(data->assertion_scheme); + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_tlv(_tlv_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->val); + SAFE_DELETE(data); + + _INFO(""); +} + +void +_free_tc_disp_png_char(gpointer data) +{ + _INFO(""); + if (data == NULL) + return; + + fido_display_png_characteristics_descriptor_s *png = (fido_display_png_characteristics_descriptor_s*)data; + if (png->plte != NULL) + g_list_free_full(png->plte, free); + + SAFE_DELETE(png); + _INFO(""); +} + +void +_free_asm_auth_list(gpointer data) +{ + _INFO("_free_asm_auth_list start"); + + if (data == NULL) + return; + + _free_fido_asm_authenticator((fido_authenticator_s*)data); + + _INFO("_free_asm_auth_list end"); + +} + +void +_free_matched_auth_dereg(_matched_auth_dereg_t *data) +{ + _INFO("_free_matched_auth_dereg start"); + if (data == NULL) + return; + + SAFE_DELETE(data->asm_id); + SAFE_DELETE(data->auth_index); + SAFE_DELETE(data->app_id); + SAFE_DELETE(data->key_id); + + SAFE_DELETE(data); + _INFO("_free_matched_auth_dereg end"); +} + +void +_free_asm_app_reg(_asm_app_reg_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->app_id); + + if (data->key_id_list != NULL) + g_list_free_full(data->key_id_list, free); + + SAFE_DELETE(data); + _INFO(""); +} + +static void +__free_asm_app_reg_list_item(gpointer data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_asm_app_reg((_asm_app_reg_t*)data); + _INFO(""); +} + +void +_free_asm_get_reg_out(_asm_get_reg_out_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + if (data->app_reg_list != NULL) + g_list_free_full(data->app_reg_list, __free_asm_app_reg_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_auth_reg_assertion_tlv(_auth_reg_assertion_tlv_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->aaid); + SAFE_DELETE(data->key_id); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_response(_response_t *data) +{ + _INFO(""); + RET_IF_FAIL_VOID(data != NULL); + + _free_op_header(data->header); + SAFE_DELETE(data->fcp); + + if (data->assertion_list != NULL) + g_list_free_full(data->assertion_list, _free_auth_reg_assertion_list_item); + + SAFE_DELETE(data); + _INFO(""); +} + +void +_free_matched_auth_data(gpointer data) +{ + _INFO("_free_matched_auth_data start"); + if (data == NULL) + return; + + _matched_auth_data_t *match_auth_data = (_matched_auth_data_t*)data; + + SAFE_DELETE(match_auth_data->asm_id); + SAFE_DELETE(match_auth_data->auth_index); + SAFE_DELETE(match_auth_data->label); + SAFE_DELETE(match_auth_data); + + _INFO("_free_matched_auth_data end"); +} diff --git a/doc/fido_doc.h b/doc/fido_doc.h new file mode 100755 index 0000000..b3f433b --- /dev/null +++ b/doc/fido_doc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef __FIDO_DOC_H__ +#define __FIDO_DOC_H__ + +/** + * @defgroup CAPI_FIDO_MODULE FIDO + * @ingroup CAPI_ACCOUNT_FRAMEWORK + * @brief The FIDO APIs provide Fast IDentity Online UAF Client specification APIs. + * + * @section CAPI_FIDO_HEADER Required Header + * \#include + * + * @section CAPI_FIDO_MODULE_OVERVIEW Overview + * The FIDO Universal Authentication Framework (UAF) Client APIs provide APIs for application developers to utilize Device's available authenticators for online service integration. + * The goal of this Universal Authentication Framework is to provide a unified and extensible authentication mechanism that supplants passwords while avoiding the shortcomings of current alternative authentication approaches. + * More details about the FIDO specification can be found in https://fidoalliance.org/specifications/download/ + * + * @defgroup CAPI_FIDO_UAF_MESSAGES_MODULE FIDO UAF MESSAGES + * @ingroup CAPI_FIDO_MODULE + * @brief Fido UAF Messasges + * + * @section CAPI_FIDO_UAF_CLIENT_HEADER Required Header + * \#include + * + * @section CAPI_FIDO_REQUESTS_MODULE_OVERVIEW Overview + * The FIDO UAF Client APIs which process UAF meesages from fido server. + * More details about the FIDO specification can be found in https://fidoalliance.org/specifications/download + * + * @defgroup CAPI_FIDO_AUTHENTICATOR_MODULE FIDO AUTHENTICATOR + * @ingroup CAPI_FIDO_MODULE + * @brief Fido Authenticator + * + * @section CAPI_FIDO_UAF_AUTHENTICATOR_HEADER Required Header + * \#include + * + * @section CAPI_FIDO_AUTHENTICATOR_MODULE_OVERVIEW Overview + * Authenticator information, received in response of fido_foreach_authenticator() call, via fido_authenticator_cb() callback. + * More details about the FIDO specification can be found in https://fidoalliance.org/specifications/download/ +*/ + +#endif /* __FIDO_DOC_H__ */ diff --git a/dummyasm.manifest b/dummyasm.manifest new file mode 100644 index 0000000..75b0fa5 --- /dev/null +++ b/dummyasm.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/fido.manifest b/fido.manifest new file mode 100644 index 0000000..dc03798 --- /dev/null +++ b/fido.manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/fido_svc_ui/CMakeLists.txt b/fido_svc_ui/CMakeLists.txt new file mode 100644 index 0000000..fe4ae45 --- /dev/null +++ b/fido_svc_ui/CMakeLists.txt @@ -0,0 +1,69 @@ +IF(NOT DEFINED UI_PACKAGE_NAME) + SET(UI_PACKAGE_NAME "org.tizen.fidosvcui") +ENDIF(NOT DEFINED UI_PACKAGE_NAME) + +SET(UI_PREFIX "/usr/apps/${UI_PACKAGE_NAME}") + +IF(NOT DEFINED UI_BINDIR) + SET(UI_BINDIR "${UI_PREFIX}/bin") +ENDIF(NOT DEFINED UI_BINDIR) + +IF(NOT DEFINED UI_RESDIR) + SET(UI_RESDIR "${UI_PREFIX}/res") +ENDIF(NOT DEFINED UI_RESDIR) + +IF(NOT DEFINED UI_LOCALEDIR) + SET(UI_LOCALEDIR "${UI_PREFIX}/res/locale") +ENDIF(NOT DEFINED UI_LOCALEDIR) + +IF(NOT DEFINED UI_MANIFESTDIR) + SET(UI_MANIFESTDIR "/usr/share/packages") +ENDIF(NOT DEFINED UI_MANIFESTDIR) + +IF(NOT DEFINED UI_DESKTOP_ICONDIR) + SET(UI_DESKTOP_ICONDIR "/usr/share/icons/default/small") +ENDIF(NOT DEFINED UI_DESKTOP_ICONDIR) + +IF(NOT DEFINED UI_DESKTOP_ICON) + SET(UI_DESKTOP_ICON ${UI_PACKAGE_NAME}.png) +ENDIF(NOT DEFINED UI_DESKTOP_ICON) + +SET(UI_SRCS + ${CMAKE_SOURCE_DIR}/fido_svc_ui/fido_ui_server.c +) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/common) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) + +ADD_DEFINITIONS("-DPACKAGE=\"${PACKAGE_NAME}\"") + +INCLUDE(FindPkgConfig) +pkg_check_modules(UI_PKGS REQUIRED + elementary + efl-extension + capi-appfw-application + capi-system-system-settings + dlog + json-glib-1.0 + glib-2.0 + gio-unix-2.0) + +FOREACH(flag ${UI_PKGS_CFLAGS}) + SET(EXTRA_CFLGAS "${EXTRA_CFLGAS} ${flag}") +ENDFOREACH(flag) + +ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_SOURCE_DIR}/common/fido-stub.c ${CMAKE_SOURCE_DIR}/common/fido-stub.h +WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/common/ +COMMAND gdbus-codegen --interface-prefix org.tizen. --generate-c-code fido-stub ${CMAKE_SOURCE_DIR}/common/dbus_interfaces/fido.xml +COMMENT "Generating FIDO GDBus stubs........................") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE ${EXTRA_CFLGAS}") +ADD_EXECUTABLE(${UI_PACKAGE_NAME} ${UI_SRCS} ${CMAKE_SOURCE_DIR}/common/fido-stub.c) +ADD_DEPENDENCIES(${UI_PACKAGE_NAME} ${CMAKE_SOURCE_DIR}/common/fido-stub.h) +ADD_DEPENDENCIES(${UI_PACKAGE_NAME} ${CMAKE_SOURCE_DIR}/common/fido-stub.c) +TARGET_LINK_LIBRARIES(${UI_PACKAGE_NAME} "-pie" ${UI_PKGS_LDFLAGS}) +CONFIGURE_FILE(${UI_PACKAGE_NAME}.xml.in ${UI_PACKAGE_NAME}.xml) + +INSTALL(TARGETS ${UI_PACKAGE_NAME} DESTINATION ${UI_BINDIR}) +INSTALL(FILES ${UI_PACKAGE_NAME}.xml DESTINATION ${UI_MANIFESTDIR}) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/fido_svc_ui/${UI_DESKTOP_ICON} DESTINATION ${UI_DESKTOP_ICONDIR}) diff --git a/fido_svc_ui/fido_ui_server.c b/fido_svc_ui/fido_ui_server.c new file mode 100644 index 0000000..46b6712 --- /dev/null +++ b/fido_svc_ui/fido_ui_server.c @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#if !GLIB_CHECK_VERSION (2, 31, 0) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "fido_internal_types.h" +#include "fido_logs.h" + +#include "fido-stub.h" +#include "fido_internal_types.h" + +#define _FIDO_SERVICE_UI_DBUS_PATH "/org/tizen/fidosvcui" +#define _FIDO_SERVICE_PATH "/usr/bin/fido-service" + +#define _FREEDESKTOP_SERVICE "org.freedesktop.DBus" +#define _FREEDESKTOP_PATH "/org/freedesktop/DBus" +#define _FREEDESKTOP_INTERFACE "org.freedesktop.DBus" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "fidosvcui" + +static bool auth_option_selected = FALSE; +static Fido *_fido_dbus_obj = NULL; + +typedef struct _ui_data_s { + char *asm_id; + char *auth_index; + char *label; + int att_t; +} ui_data_s; + +typedef struct appdata { + Evas_Object *win; + Evas_Object *conform; + Evas_Object *nf; + Evas_Object *box; + Evas_Object *genlist; + Elm_Genlist_Item_Class* itc; + Evas_Object *group; + Evas_Object *radio; + Evas_Object *btn; + GList *ui_data_list; + GDBusMethodInvocation *invocation; +} appdata_s; + +static appdata_s *ad = NULL; + +static void +__free_ui_data(ui_data_s *data) +{ + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->asm_id); + SAFE_DELETE(data->auth_index); + SAFE_DELETE(data->label); + + SAFE_DELETE(data); +} + +static void +__add_string_to_json_object(JsonBuilder *json_obj, const char *key, const char *val) +{ + if (key == NULL || val == NULL) + return; + + json_builder_set_member_name(json_obj, key); + json_builder_add_string_value(json_obj, val); +} + +static void +__add_int_to_json_object(JsonBuilder *json_obj, const char *key, int val) +{ + if (key == NULL || val == _INVALID_INT) + return; + + json_builder_set_member_name(json_obj, key); + json_builder_add_int_value(json_obj, val); +} + +static void +__init_dbus(void) +{ + _INFO("init_dbus"); +#if !GLIB_CHECK_VERSION(2,35,0) + g_type_init(); +#endif + + GDBusConnection *connection = NULL; + GError *error = NULL; + + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + _INFO("after g_bus_get_sync"); + + + /* Create the object */ + _fido_dbus_obj = fido_proxy_new_sync(connection, + G_DBUS_PROXY_FLAGS_NONE, + _FIDO_DBUS_NAME, + _FIDO_DBUS_PATH, + NULL, + &error); +} + +static Fido * +__dbus_proxy_get_instance(int time_out) +{ + _INFO("_dbus_proxy_get_instance singleton"); + + static pthread_once_t onceBlock = PTHREAD_ONCE_INIT; + if (_fido_dbus_obj == NULL) { + pthread_once(&onceBlock, __init_dbus); + if (_fido_dbus_obj == NULL) { + _ERR("init_dbus failed"); + onceBlock = PTHREAD_ONCE_INIT; + } + } + _INFO("_dbus_proxy_get_instance end"); + + g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(_fido_dbus_obj), time_out); + + return _fido_dbus_obj; +} + +static void +__send_response_to_fido_svc(int error, const char *ui_resp) +{ + auth_option_selected = FALSE; + + Fido *dbus_proxy = __dbus_proxy_get_instance(_DBUS_TIMEOUT_USE_DEFAULT); + if (dbus_proxy == NULL) { + _ERR("DBus proxy failed"); + return; + } + + _INFO("Sending to FIDO Service"); + + GError *dbus_err = NULL; + if (ui_resp == NULL) + fido_call_ui_response_sync(dbus_proxy, FIDO_ERROR_USER_CANCELLED, _EMPTY_JSON_STRING, NULL, &dbus_err); + else + fido_call_ui_response_sync(dbus_proxy, error, ui_resp, NULL, &dbus_err); + + if (dbus_err != NULL) + g_error_free(dbus_err); + + _INFO("UI end"); +} + +char* +_create_json_response(ui_data_s *selected_auth) +{ + _INFO("_create_json_response"); + + /*Builder start*/ + JsonBuilder *builder = json_builder_new(); + json_builder_begin_object(builder); + + /*requestType*/ + __add_string_to_json_object(builder, UI_DATA_ASM_ID, selected_auth->asm_id); + __add_string_to_json_object(builder, UI_DATA_AUTH_INDEX, selected_auth->auth_index); + __add_string_to_json_object(builder, UI_DATA_LABEL, selected_auth->label); + __add_int_to_json_object(builder, UI_DATA_ATT_TYPE, selected_auth->att_t); + + json_builder_end_object(builder); + /*Builder end*/ + + JsonGenerator *gen = json_generator_new(); + JsonNode *root_builder = json_builder_get_root(builder); + json_generator_set_root(gen, root_builder); + + json_node_free(root_builder); + g_object_unref(builder); + + gsize len = 0; + char *json = json_generator_to_data(gen, &len); + if (json != NULL) { + + if (gen != NULL) + g_object_unref(gen); + + _INFO("%s", json); + _INFO("_create_json_response end"); + + return json; + } + + g_object_unref(gen); + + _INFO("_create_json_response fail"); + return NULL; +} + +void +_list_destroy(gpointer data) +{ + ui_data_s *list_data = (ui_data_s *) data; + SAFE_DELETE(list_data->auth_index); + SAFE_DELETE(list_data->label); +} + +void +_hide_ui(void) +{ + elm_genlist_clear(ad->genlist); + g_list_free_full(ad->ui_data_list, (GDestroyNotify) _list_destroy); + ad->ui_data_list = NULL; + evas_object_hide(ad->win); +} + +void genlist_select_cb(void *data, Evas_Object *obj, void *event_info) +{ + _INFO("genlist_select_cb"); + + if (data == NULL) { + _INFO("data is NULL"); + return; + } + + if (event_info == NULL) { + _INFO("event_info is NULL"); + return; + } + + ui_data_s *selected_auth = (ui_data_s*) data; + auth_option_selected = TRUE; + + Elm_Object_Item *item = (Elm_Object_Item *) event_info; + char *sel_txt = (char *) elm_object_item_data_get(item); + + if (!strcmp(sel_txt, selected_auth->label)) { + char *response = _create_json_response(selected_auth); + if (response != NULL) { + _hide_ui(); + + _INFO("sending response to ui adaptor"); + __send_response_to_fido_svc(FIDO_ERROR_NONE, response); + + SAFE_DELETE(response); + } + } +} + +static char* +_item_label_get(void *data, Evas_Object *obj, const char *part) +{ + char buf[256]; + snprintf(buf, sizeof(buf), "%s", (char*) data); + return strdup(buf); +} + +void +_auth_arr_cb(JsonArray *array, guint index, JsonNode *element_node, gpointer user_data) +{ + _INFO("_auth_arr_cb"); + + JsonObject *obj = NULL; + obj = json_node_get_object(element_node); + if (!obj) { + _ERR("json_node_get_object() failed"); + return; + } + + ui_data_s *ui_data = (ui_data_s *) calloc(1, sizeof(ui_data_s)); + if (!ui_data) { + _ERR("Out of memory"); + return; + } + + const char *asm_id = json_object_get_string_member(obj, UI_DATA_ASM_ID); + if (!asm_id) { + _ERR("json_object_get_string_member() failed"); + + __free_ui_data(ui_data); + return; + } + + const char *auth_idx = NULL; + auth_idx = json_object_get_string_member(obj, UI_DATA_AUTH_INDEX); + if (!auth_idx) { + _ERR("json_object_get_string_member() failed"); + + __free_ui_data(ui_data); + return; + } + + const char *label = NULL; + label = json_object_get_string_member(obj, UI_DATA_LABEL); + + int att = -1; + att = json_object_get_int_member(obj, UI_DATA_ATT_TYPE); + + ui_data->asm_id = strdup(asm_id); + + ui_data->auth_index = strdup(auth_idx); + if (label == NULL) { + ui_data->label = calloc(1, 128); + snprintf(ui_data->label, 127, "%s", "Unknown Authenticator"); + } + else + ui_data->label = strdup(label); + + ui_data->att_t = att; + ad->ui_data_list = g_list_append(ad->ui_data_list, ui_data); + + _INFO("Adding to ui_data list | auth_index %s | label %s | att_type %d", + auth_idx, ui_data->label, att); + + elm_genlist_item_append(ad->genlist, ad->itc, ui_data->label, NULL, + ELM_GENLIST_ITEM_NONE, genlist_select_cb, ui_data); + +} + +static void +_parse_json_ui_in(const char *ui_auth_json) +{ + _INFO("_parse_json_ui_in data %s", ui_auth_json); + + char * ui_auth = strdup(ui_auth_json); + GError *parse_err = NULL; + JsonParser *parser = NULL; + JsonNode *root = NULL; + JsonArray *auth_data_arr = NULL; + + parser = json_parser_new(); + if (!parser) { + _ERR("json_parser_new failed"); + goto CATCH; + } + + json_parser_load_from_data(parser, ui_auth, -1, &parse_err); + if (parse_err != NULL) { + _ERR("json parse failure"); + goto CATCH; + } + + root = json_parser_get_root(parser); + if (!root) { + _ERR("json_parser_get_root() failed"); + goto CATCH; + } + + auth_data_arr = json_node_get_array(root); + if (!auth_data_arr) { + _ERR("json_node_get_array() failed"); + goto CATCH; + } + + /* Genlist Item */ + ad->itc = elm_genlist_item_class_new(); + ad->itc->item_style = "default"; + ad->itc->func.text_get = _item_label_get; + ad->itc->func.content_get = NULL; + ad->itc->func.state_get = NULL; + + json_array_foreach_element(auth_data_arr, _auth_arr_cb, NULL); + +CATCH: + if (parser != NULL) { + g_object_unref(parser); + parser = NULL; + } + + if (parse_err != NULL) { + g_error_free(parse_err); + parse_err = NULL; + } + + SAFE_DELETE(ui_auth); + + return; +} + +// TODO button callback +/* +static void btn_clicked_cb(void *data, Evas_Object *obj, void *event_info) { + + _INFO("clicked event on Button"); + + if (auth_option_selected == TRUE && selected_auth != NULL) { + + char *selected_auth_json = _create_json_response(selected_auth); + + _INFO("sending selected authenticator response"); + fidosvcui_complete_ui_auth_request(ad->object, ad->invocation, 0, selected_auth_json); + + } +} +*/ + +static void +_win_back_cb(void *data, Evas_Object *obj, void *event_info) +{ + if (auth_option_selected == FALSE) { + _ERR("Authenticator not selected by user"); + _hide_ui(); + __send_response_to_fido_svc(FIDO_ERROR_USER_CANCELLED, NULL); + } +} + +static void +_create_ui(void) +{ + _INFO("_create_ui"); + + /* Window */ + //ad->win = elm_win_add(NULL, UI_SVC_PACKAGE, ELM_WIN_BASIC); + ad->win = elm_win_util_standard_add(_UI_SVC_PACKAGE, "Authenticator Selection UI"); + if (ad->win != NULL) + _INFO("elm_win_util_standard_add successful"); + else + _ERR("elm_win_util_standard_add failed"); + + elm_win_autodel_set(ad->win, EINA_TRUE); + + if (elm_win_wm_rotation_supported_get(ad->win)) { + int rots[4] = { 0, 90, 180, 270 }; + elm_win_wm_rotation_available_rotations_set(ad->win, + (const int *) (&rots), 4); + } + + eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, _win_back_cb, ad); + evas_object_smart_callback_add(ad->win, "unfocused", _win_back_cb, NULL); + + /* Conformant */ + ad->conform = elm_conformant_add(ad->win); + elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW); + elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE); + evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + elm_win_resize_object_add(ad->win, ad->conform); + evas_object_show(ad->conform); + + /* Naviframe */ + ad->nf = elm_naviframe_add(ad->conform); + elm_object_content_set(ad->conform, ad->nf); + evas_object_show(ad->nf); + + /* Box */ + ad->box = elm_box_add(ad->nf); + + /* Genlist */ + ad->genlist = elm_genlist_add(ad->box); + elm_genlist_homogeneous_set(ad->genlist, EINA_TRUE); + + /* Radio */ + Evas_Object *radio_main = elm_radio_add(ad->genlist); + elm_radio_state_value_set(radio_main, 0); + elm_radio_value_set(radio_main, 0); + evas_object_data_set(ad->genlist, "radio_main", radio_main); + + evas_object_size_hint_weight_set(ad->genlist, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(ad->genlist, EVAS_HINT_FILL, + EVAS_HINT_FILL); + evas_object_show(ad->genlist); + elm_box_pack_end(ad->box, ad->genlist); + + //~ /* Button */ // TODO check button visibility + //~ ad->btn = elm_button_add(ad->box); + //~ elm_object_text_set(ad->btn, "OK"); + //~ evas_object_size_hint_weight_set(ad->btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + //~ evas_object_size_hint_align_set(ad->btn, EVAS_HINT_FILL, EVAS_HINT_FILL); + + //~ Evas_Object *btn_bg = elm_bg_add(ad->btn); + //~ elm_bg_color_set(btn_bg, 90, 160, 200); + + //~ evas_object_smart_callback_add(ad->btn, "clicked", btn_clicked_cb, ad); + //~ evas_object_show(ad->btn); + //~ elm_box_pack_end(ad->box, ad->btn); + + + elm_naviframe_item_push(ad->nf, "Select Authenticator", + NULL, NULL, ad->box, NULL); + + /* Keep window hidden after base gui is set up */ + //evas_object_hide(ad->win); + +} + +static bool +app_create(void *data) +{ + ad = data; + _create_ui(); + + return true; + } + +static void +app_control(app_control_h app_control, void *data) +{ + //_UI_IPC_KEY_REQ + RET_IF_FAIL_VOID(app_control != NULL); + + char *req_json = NULL; + app_control_get_extra_data(app_control, _UI_IPC_KEY_REQ, &req_json); + RET_IF_FAIL_VOID(req_json != NULL); + + _parse_json_ui_in(req_json); + + evas_object_show(ad->win); +} + +static void +app_pause(void *data) +{ + + } + +static void +app_resume(void *data) +{ + + } + +static void +app_terminate(void *data) +{ + +} + +static void +ui_app_lang_changed(app_event_info_h event_info, void *user_data) +{ + + char *locale = NULL; + system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale); + elm_language_set(locale); + free(locale); + return; + } + +static void +ui_app_orient_changed(app_event_info_h event_info, void *user_data) +{ + return; + } + +static void +ui_app_region_changed(app_event_info_h event_info, void *user_data) +{ +} + +static void +ui_app_low_battery(app_event_info_h event_info, void *user_data) +{ + + } + +static void +ui_app_low_memory(app_event_info_h event_info, void *user_data) +{ + +} + +EXPORT_API int +main(int argc, char *argv[]) +{ + appdata_s ad = {0,}; + int ret = 0; + + ui_app_lifecycle_callback_s event_callback = {0,}; + app_event_handler_h handlers[5] = {NULL, }; + + event_callback.create = app_create; + event_callback.terminate = app_terminate; + event_callback.pause = app_pause; + event_callback.resume = app_resume; + event_callback.app_control = app_control; + + ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, ui_app_low_battery, &ad); + ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, ui_app_low_memory, &ad); + ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, ui_app_orient_changed, &ad); + ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad); + ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, ui_app_region_changed, &ad); + ui_app_remove_event_handler(handlers[APP_EVENT_LOW_MEMORY]); + + ret = ui_app_main(argc, argv, &event_callback, &ad); + if (ret != APP_ERROR_NONE) { + _INFO("app_main() is failed. err = %d", ret); + } + + return ret; +} diff --git a/fido_svc_ui/org.tizen.fidosvcui.png b/fido_svc_ui/org.tizen.fidosvcui.png new file mode 100644 index 0000000000000000000000000000000000000000..9765b1bda7e5bddf0925555ab204b887a873bf24 GIT binary patch literal 57662 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 kZ}gYfNaCF}xV$|1>H6z0+kD + + + + + org.tizen.fidosvcui.png + + + http://tizen.org/privilege/account.read + http://tizen.org/privilege/account.write + + diff --git a/include/fido.h b/include/fido.h new file mode 100644 index 0000000..30e0c45 --- /dev/null +++ b/include/fido.h @@ -0,0 +1,45 @@ + +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef _FIDO_H_ +#define _FIDO_H_ + +#include + +#include +#include +#include + +/** + * Tizen FIDO UAF Client Framework. + * Refer to https://fidoalliance.org/specifications/download/ about FIDO UAF. + * Also FIDO server document needs to be referred for using end points and additional parameters. + */ + +/** + * @addtogroup CAPI_FIDO_MODULE + * @{ + */ + +/* End of FIDO APIs */ +/** + * @} + */ + +#endif // _FIDO_H_ + diff --git a/include/fido_uaf_authenticator.h b/include/fido_uaf_authenticator.h new file mode 100755 index 0000000..d538384 --- /dev/null +++ b/include/fido_uaf_authenticator.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef _FIDO_UAF_AUTH_H_ +#define _FIDO_UAF_AUTH_H_ + +#include "fido_uaf_types.h" + +/** + * @file fido_uaf_authenticator.h + * @brief Authenticator information, received in response of fido_foreach_authenticator() call, + * via fido_authenticator_cb() callback. + */ + +/** + * @addtogroup CAPI_FIDO_AUTHENTICATOR_MODULE + * @{ + */ + +/** + * @brief Called once for each result of calling fido_foreach_authenticator() + * @since_tizen 3.0 + * + * @param[out] auth_info The Authenticator info handle. This param will be freed by framework. + * @param[out] user_data The user data that was attached during fido_foreach_authenticator() call. + * @see fido_foreach_authenticator() + */ +typedef void (*fido_authenticator_cb)(const fido_authenticator_h auth_info, void *user_data); + +/** + * @brief Retrieves all the available FIDO authenticators supported by this Device. + * @details fido_authenticator_cb() callback is called synchronously once for each authenticator. + * @since_tizen 3.0 + * + * + * @param[in] cb The iteration callback handle. + * @param[in] user_data The user data handle. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #FIDO_ERROR_PERMISSION_DENIED The application does not have permission to call this API. + * @retval #FIDO_ERROR_NOT_SUPPORTED FIDO is not supported on this device. + */ +EXPORT_API int fido_foreach_authenticator(fido_authenticator_cb cb, void *user_data); + +/** + * @brief Gets the Authenticator title. + * @since_tizen 3.0 + * + * @remarks The application must free title using free(). + * @param[in] auth The Authenticator handle. + * @param[out] title The title. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_title(const fido_authenticator_h auth, char **title); + +/** + * @brief Retrieves the Authenticator AAID(Authenticator Attestation ID). + * @since_tizen 3.0 + * + * @remarks The application must free aaid using free(). + * @param[in] auth The Authenticator handle. + * @param[out] aaid The AAID. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_aaid(const fido_authenticator_h auth, char **aaid); + +/** + * @brief Retrieves the Authenticator description + * @since_tizen 3.0 + * + * @remarks The application must free desc using free(). + * @param[in] auth The Authenticator handle. + * @param[out] desc The description. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_description(const fido_authenticator_h auth, char **desc); + +/** + * @brief Retrieves the Authenticator assertion scheme. + * @since_tizen 3.0 + * + * @remarks The application must free scheme using free().Refer to FIDO UAF Registry document for more details. + * @param[in] auth The Authenticator handle. + * @param[out] scheme The assertion scheme. UAFV1TLV is the default assertion scheme. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_assertion_scheme(const fido_authenticator_h auth, char **scheme); + +/** + * @brief Retrieves the Authenticator algorithm + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[out] algo The authenitcation algorithm. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_algorithm(const fido_authenticator_h auth, fido_auth_algo_e *algo); + +/** + * @brief Called once for each result of calling fido_authenticator_foreach_attestation_type() + * @since_tizen 3.0 + * + * @param[out] att_type The Authenticator attestation type. + * @param[out] user_data The user data that was attached during fido_authenticator_foreach_attestation_type() call. + */ +typedef void (*fido_attestation_type_cb)(fido_auth_attestation_type_e att_type, void *user_data); + +/** + * @brief Retrieves all the available attestation types for this Authenticator. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[in] cb The iteration callback. + * @param[in] user_data The user data. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_foreach_attestation_type(const fido_authenticator_h auth, fido_attestation_type_cb cb, + void *user_data); + +/** + * @brief Retrieves the user verification method of this Authenticator. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[out] user_verification The user verification method. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_verification_method(const fido_authenticator_h auth, + fido_auth_user_verify_type_e *user_verification); + +/** + * @brief Retrieves the key protection method of this Authenticator. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[out] key_protection The key protection method. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_key_protection_method(const fido_authenticator_h auth, + fido_auth_key_protection_type_e *key_protection); + +/** + * @brief Retrieves the matcher protection method of this Authenticator. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[out] matcher_protection The matcher protection method. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_matcher_protection_method(const fido_authenticator_h auth, + fido_auth_matcher_protection_type_e *matcher_protection); + +/** + * @brief Retrieves the attachment hint of this Authenticator. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[out] attachment_hint The matcher protection method. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_attachment_hint(const fido_authenticator_h auth, + fido_auth_attachment_hint_e *attachment_hint); + +/** + * @brief Checks if the Authenticator is Second factor only which is supported by U2F standards. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * + * @return @c true if its only second factor, + * otherwise false. + */ +EXPORT_API bool fido_authenticator_get_is_second_factor_only(const fido_authenticator_h auth); + +/** + * @brief Retrieves the Transaction Confirmation display type of this Authenticator. + * @since_tizen 3.0 + * + * @param[in] auth The Authenticator handle. + * @param[out] tc_display The TC display type. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_tc_discplay(const fido_authenticator_h auth, + fido_auth_tc_display_type_e *tc_display); + +/** + * @brief Retrieves the Transaction Confirmation display content type of this Authenticator. + * @since_tizen 3.0 + * + * @remarks The application must free tc_display_content_type using free(). + * @param[in] auth The Authenticator handle. + * @param[out] tc_display_content_type The TC display content type which is supported MIME type [RFC2049] such as text/plain or image/png. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_tc_display_type(const fido_authenticator_h auth, char **tc_display_content_type); + +/** + * @brief Retrieves the icon of this Authenticator. + * @since_tizen 3.0 + * + * @remarks The application must free icon using free(). + * @param[in] auth The Authenticator handle. + * @param[out] icon The icon. Portable Network Graphic (PNG) format image file representing the icon encoded as a data: url[RFC2397]. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_authenticator_get_icon(const fido_authenticator_h auth, char **icon); + +/** + * @} + */ + +#endif diff --git a/include/fido_uaf_client.h b/include/fido_uaf_client.h new file mode 100755 index 0000000..c809a32 --- /dev/null +++ b/include/fido_uaf_client.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_UAF_CLIENT_H_ +#define FIDO_UAF_CLIENT_H_ + +#include + +/** + * @file fido_uaf_client.h + * @brief The FIDO UAF Client APIs. + */ + +/** + * @addtogroup CAPI_FIDO_MODULE + * @{ + */ + +/** + * @brief Gets the FIDO client vendor name. + * @since_tizen 3.0 + * + * @remarks The application must free vendor_name using free(). + * @param[out] vendor_name The vendor name. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_get_client_vendor(char **vendor_name); + +/** + * @brief Gets the FIDO client vendor version information. + * @since_tizen 3.0 + * + * @param[out] client_major_version The FIDO client major version. + * @param[out] client_minor_version The FIDO client minor version. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + */ +EXPORT_API int fido_get_client_version(int *client_major_version, int *client_minor_version); + +/** + * @} + */ + +/** + * @addtogroup CAPI_FIDO_UAF_MESSAGES_MODULE + * @{ + */ + +/** + * @brief Checks whether the FIDO message can be processed. + * @since_tizen 3.0 + * + * @param[in] uaf_message_json The FIDO message in json format which is recieved from the relying party server. + * @param[out] is_supported True if the message can be handled by the device, else false. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #FIDO_ERROR_NOT_SUPPORTED FIDO is not supported + * @retval #FIDO_ERROR_PERMISSION_DENIED The application does not have permission to call this API. + * @retval #FIDO_ERROR_UNSUPPORTED_VERSION The UAFMessage does not specify a protocol version supported by this FIDO UAF Client. + * @retval #FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR No suitable authenticators found. + * @retval #FIDO_ERROR_PROTOCOL_ERROR The interaction may have timed out, or the UAF message is malformed. + * @retval #FIDO_ERROR_UNTRUSTED_FACET_ID The caller's id is not allowed to use this operation. + * + */ +EXPORT_API int fido_uaf_is_supported(const char *uaf_message_json, bool *is_supported); + +/** + * @brief Called when fido_uaf_get_response_message() response comes. + * @since_tizen 3.0 + * + * @param[in] tizen_error_code Tizen platform error code. + * @param[in] uaf_response_json FIDO resonse message in json format. + * @param[in] user_data The user data passed from the callback function. + * + * @pre fido_uaf_get_response_message() must be called to get this callback invoked. + * @see fido_uaf_get_response_message() + */ +typedef void (*fido_uaf_response_message_cb) (fido_error_e tizen_error_code, const char *uaf_response_json, void *user_data); + +/** + * @brief Processes the given FIDO UAF message. + * @details The response is delivered via fido_uaf_response_message_cb(). Depending on the FIDO message type, this may involve user interactions. + * + * @since_tizen 3.0 + * + * @param[in] uaf_request_json The FIDO UAF message in json format which is recieved from the relying party server. + * @param[in] channel_binding The channel binding data in json format which is recieved from the relying party server. + * @param[in] callback The callback to receive response. + * @param[in] user_data The user data to be passed to the callback function. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #FIDO_ERROR_NOT_SUPPORTED FIDO is not supported + * @retval #FIDO_ERROR_USER_ACTION_IN_PROGRESS User action is in progress. + * @retval #FIDO_ERROR_USER_CANCELLED User has canceled the operation. + * @retval #FIDO_ERROR_PERMISSION_DENIED The application does not have permission to call this API. + * @retval #FIDO_ERROR_UNSUPPORTED_VERSION The UAFMessage does not specify a protocol version supported by this FIDO UAF Client. + * @retval #FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR No suitable authenticators found. + * @retval #FIDO_ERROR_PROTOCOL_ERROR The interaction may have timed out, or the UAF message is malformed. + * @retval #FIDO_ERROR_UNTRUSTED_FACET_ID The caller's id is not allowed to use this operation. + * + * @see fido_uaf_response_message_cb() + */ +EXPORT_API int fido_uaf_get_response_message(const char *uaf_request_json, const char *channel_binding, + fido_uaf_response_message_cb callback, void *user_data); + +/** + * @brief Notifies the server result to the FIDO client. FIDO Server sends the result of processing a UAF message to FIDO client. + * @remarks This is especially important as a new registration may be considered by the client to be in a pending state + * until it is communicated that the server accepted it. + * + * @since_tizen 3.0 + * + * @param[in] response_code The status code received from Server, FIDO_SERVER_STATUS_CODE_OK implies success. + * @param[in] uaf_response_json The FIDO response message sent to server in json format. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #FIDO_ERROR_NONE Successful + * @retval #FIDO_ERROR_OUT_OF_MEMORY Out of Memory + * @retval #FIDO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #FIDO_ERROR_NOT_SUPPORTED FIDO is not supported + * @retval #FIDO_ERROR_PERMISSION_DENIED The application does not have permission to call this API. + * @retval #FIDO_ERROR_UNSUPPORTED_VERSION The UAFMessage does not specify a protocol version supported by this FIDO UAF Client. + * @retval #FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR No suitable authenticators found. + * @retval #FIDO_ERROR_PROTOCOL_ERROR The interaction may have timed out, or the UAF message is malformed. + * @retval #FIDO_ERROR_UNTRUSTED_FACET_ID The caller's id is not allowed to use this operation. + * + * @see fido_uaf_response_message_cb() + */ +EXPORT_API int fido_uaf_set_server_result(int response_code, const char *uaf_response_json); + +/** + * @} + */ + +#endif /* FIDO_UAF_CLIENT_H_ */ diff --git a/org.tizen.FidoSample.manifest b/org.tizen.FidoSample.manifest new file mode 100755 index 0000000..058c45f --- /dev/null +++ b/org.tizen.FidoSample.manifest @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.tizen.fidosvcui.manifest b/org.tizen.fidosvcui.manifest new file mode 100755 index 0000000..75b0fa5 --- /dev/null +++ b/org.tizen.fidosvcui.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/fido-client.spec b/packaging/fido-client.spec new file mode 100644 index 0000000..4d8d775 --- /dev/null +++ b/packaging/fido-client.spec @@ -0,0 +1,218 @@ + +Name: fido-client +Summary: Tizen FIDO Client +Version: 0.0.1 +Release: 1 +Group: Social & Content/API +License: Apache-2.0 +Source0: fido-client-%{version}.tar.gz +Source1: org.tizen.fido.service +Source2: org.tizen.fido.conf +Source3: org.tizen.fido.service + +Source4: org.tizen.dummyasm.service +Source5: org.tizen.dummyasm.conf + +BuildRequires: cmake +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(glib-2.0) >= 2.26 +BuildRequires: pkgconfig(gio-unix-2.0) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-session) +BuildRequires: pkgconfig(cynara-creds-gdbus) +BuildRequires: pkgconfig(pkgmgr-info) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(json-glib-1.0) +##BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-appfw-app-manager) +BuildRequires: pkgconfig(libsoup-2.4) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(efl-extension) +BuildRequires: pkgconfig(openssl) +BuildRequires: pkgconfig(bundle) +BuildRequires: python-xml + +Requires(post): /sbin/ldconfig +Requires(post): /usr/bin/sqlite3 +Requires(postun): /sbin/ldconfig + +%description +Tizen FIDO Client + +%package devel +Summary: Development files for %{name} +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +%description devel +Development files for %{name} + +%prep +%setup -q + +%build +#export CFLAGS+=" -Wextra -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wswitch-default" +#export CXXFLAGS+=" -Wextra -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wswitch-default -Wnon-virtual-dtor -Wno-c++0x-compat" +#export CFLAGS+=" -Wno-unused-parameter -Wno-empty-body" +#export CXXFLAGS+=" -Wno-unused-parameter -Wno-empty-body" + +#export CFLAGS+=" -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-strict-aliasing -fno-unroll-loops -fsigned-char -fstrict-overflow -fno-common" +#export CXXFLAGS+=" -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-strict-aliasing -fno-unroll-loops -fsigned-char -fstrict-overflow" + +export CFLAGS="${CFLAGS} -fPIC -fvisibility=hidden" +cmake . -DCMAKE_INSTALL_PREFIX=/usr + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +cp %{_builddir}/%{name}-%{version}/LICENSE.Apache-2.0 %{buildroot}/usr/share/license/%{name} +%make_install + +mkdir -p %{buildroot}/usr/share/dbus-1/system-services +install -m 0644 %SOURCE1 %{buildroot}/usr/share/dbus-1/system-services/org.tizen.fido.service + +mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d +install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/dbus-1/system.d/ + +mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants +install -m 644 %SOURCE3 %{buildroot}%{_unitdir}/org.tizen.fido.service +%install_service multi-user.target.wants org.tizen.fido.service + + +mkdir -p %{buildroot}/usr/share/dbus-1/system-services +install -m 0644 %SOURCE4 %{buildroot}/usr/share/dbus-1/system-services/org.tizen.dummyasm.service + +mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d +install -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/dbus-1/system.d/ + +mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants +install -m 644 %SOURCE4 %{buildroot}%{_unitdir}/org.tizen.dummyasm.service +%install_service multi-user.target.wants org.tizen.dummyasm.service + +install -m 0644 test/Dummy_ASM_DBUS/dummy_asm.json %{buildroot}%{_libdir}/fido/asm/dummy_asm.json + +##rm -rf %{buildroot}/usr/lib/fido + +%post +mkdir -p /usr/lib/fido/asm/ +chsmack -a '_' /usr/lib/fido/ +chsmack -a '_' /usr/lib/fido/asm/ +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +/usr/share/license/%{name} +%{_libdir}/*.so.* +%manifest fido.manifest +%config %{_sysconfdir}/dbus-1/system.d/org.tizen.fido.conf +%{_bindir}/fido-service +%attr(0644,root,root) %{_unitdir}/org.tizen.fido.service +%attr(0644,root,root) %{_unitdir}/multi-user.target.wants/org.tizen.fido.service +%attr(0644,root,root) /usr/share/dbus-1/system-services/org.tizen.fido.service + +%files devel +%defattr(-,root,root,-) +%{_libdir}/*.so +%{_libdir}/pkgconfig/*.pc +%{_includedir}/*.h +/opt/usr/devel/fido/tc/* + + +################################################################################# +# FIDO Service UI + +%package -n org.tizen.fidosvcui +Summary: FIDO Service UI +Group: Account +#Requires: %{name} = %{version}-%{release} + +BuildRequires: cmake +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-system-system-settings) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(efl-extension) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(glib-2.0) >= 2.26 +BuildRequires: pkgconfig(gio-unix-2.0) +Requires: fido-client + +%description -n org.tizen.fidosvcui +FIDO Service UI + +%files -n org.tizen.fidosvcui +%defattr(-,root,root,-) +/usr/share/license/%{name} +%manifest org.tizen.fidosvcui.manifest +/usr/apps/org.tizen.fidosvcui/bin/* +##/usr/apps/org.tizen.fidosvcui/res/* +/usr/share/packages/org.tizen.fidosvcui.xml +/usr/share/icons/default/small/org.tizen.fidosvcui.png + +################################################################################# +# FIDO Dummy ASM +%package -n dummyasm +Summary: FIDO Dummy ASM (Internal Dev) +Group: Account/Testing + +BuildRequires: cmake +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-system-system-settings) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(efl-extension) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(glib-2.0) >= 2.26 +BuildRequires: pkgconfig(gio-unix-2.0) +BuildRequires: pkgconfig(libtzplatform-config) +Requires: fido-client + +%description -n dummyasm +This is a dummy ASM. + +%files -n dummyasm +%manifest dummyasm.manifest +%config %{_sysconfdir}/dbus-1/system.d/org.tizen.dummyasm.conf +%{_bindir}/dummyasm-service +%attr(0644,root,root) %{_unitdir}/org.tizen.dummyasm.service +%attr(0644,root,root) %{_unitdir}/multi-user.target.wants/org.tizen.dummyasm.service +%attr(0644,root,root) /usr/share/dbus-1/system-services/org.tizen.dummyasm.service +%{_libdir}/fido/asm/dummy_asm.json + +################################################################################# +# Fido Sample App + +%package -n org.tizen.FidoSample +Summary: Fido Sample App (Internal Dev) +Group: Account/Testing +#Requires: %{name} = %{version}-%{release} + +BuildRequires: cmake +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-system-system-settings) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(efl-extension) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(glib-2.0) >= 2.26 +BuildRequires: pkgconfig(gio-unix-2.0) +Requires: fido-client + +%description -n org.tizen.FidoSample +This is a program to test the Fido service internally. + +%files -n org.tizen.FidoSample +%defattr(-,root,root,-) +/usr/share/license/%{name} +%manifest org.tizen.FidoSample.manifest +/opt/usr/apps/org.tizen.FidoSample/bin/* +/opt/usr/apps/org.tizen.FidoSample/res/* +/opt/usr/apps/org.tizen.FidoSample/shared/res/* +/opt/share/packages/org.tizen.FidoSample.xml +##/opt/share/icons/default/small/org.tizen.FidoSample.png diff --git a/packaging/org.tizen.dummyasm.conf b/packaging/org.tizen.dummyasm.conf new file mode 100644 index 0000000..853906b --- /dev/null +++ b/packaging/org.tizen.dummyasm.conf @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/org.tizen.dummyasm.service b/packaging/org.tizen.dummyasm.service new file mode 100644 index 0000000..976d582 --- /dev/null +++ b/packaging/org.tizen.dummyasm.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.tizen.dummyasm +Exec=/usr/bin/dummyasm-service +User=system +Group=system diff --git a/packaging/org.tizen.fido.conf b/packaging/org.tizen.fido.conf new file mode 100644 index 0000000..12260bc --- /dev/null +++ b/packaging/org.tizen.fido.conf @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/org.tizen.fido.service b/packaging/org.tizen.fido.service new file mode 100644 index 0000000..32cc443 --- /dev/null +++ b/packaging/org.tizen.fido.service @@ -0,0 +1,8 @@ +[Unit] +Description=FIDO Service D-Bus + +[D-BUS Service] +Name=org.tizen.fido +Exec=/usr/bin/fido-service +User=system +Group=system diff --git a/packaging/org.tizen.fidosvcui.service b/packaging/org.tizen.fidosvcui.service new file mode 100644 index 0000000..7f83467 --- /dev/null +++ b/packaging/org.tizen.fidosvcui.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.tizen.fidosvcui +Exec=/usr/bin/fido-ui-service +User=system +Group=system diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 0000000..015a31e --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,56 @@ +SET(SVC_DAEMON fido-service) + +INCLUDE(FindPkgConfig) +pkg_check_modules(SERVER_pkgs REQUIRED + dlog + glib-2.0 + gio-unix-2.0 + capi-base-common + json-glib-1.0 + capi-appfw-application + aul + libsoup-2.4 + capi-appfw-app-manager + openssl + bundle + cynara-client + cynara-session + cynara-creds-gdbus + libtzplatform-config +) + +FOREACH(flag ${SERVER_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(SERVER_SRCS + fido_server.c + fido_asm_plugin_manager.c + fido_uaf_policy_checker.c + fido_selection_ui_adaptor.c + ../common/fido_uaf_utils.c + ../common/fido_json_handler.c + ../common/fido_tlv_util.c + fido_app_id_handler.c + ../common/fido_b64_util.c + fido_privilege_checker.c +) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/common) + +ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_SOURCE_DIR}/common/fido-stub.c ${CMAKE_SOURCE_DIR}/common/fido-stub.h +WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/common/ +COMMAND gdbus-codegen --interface-prefix org.tizen. --generate-c-code fido-stub ${CMAKE_SOURCE_DIR}/common/dbus_interfaces/fido.xml +COMMENT "Generating FIDO GDBus stubs........................") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror") +SET(CMAKE_LDFLAGS "-Wl,-zdefs") + +ADD_EXECUTABLE(${SVC_DAEMON} ${SERVER_SRCS} ${CMAKE_SOURCE_DIR}/common/fido-stub.c) +ADD_DEPENDENCIES(${SVC_DAEMON} ${CMAKE_SOURCE_DIR}/common/fido-stub.h) +ADD_DEPENDENCIES(${SVC_DAEMON} ${CMAKE_SOURCE_DIR}/common/fido-stub.c) + +TARGET_LINK_LIBRARIES(${SVC_DAEMON} ${SERVER_pkgs_LDFLAGS}) + +INSTALL(TARGETS ${SVC_DAEMON} DESTINATION bin) + diff --git a/server/fido_app_id_handler.c b/server/fido_app_id_handler.c new file mode 100644 index 0000000..7046163 --- /dev/null +++ b/server/fido_app_id_handler.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fido_internal_types.h" +#include "fido_json_handler.h" +#include "fido_app_id_handler.h" +#include "fido_logs.h" + +#define _FREEDESKTOP_SERVICE "org.freedesktop.DBus" +#define _FREEDESKTOP_PATH "/org/freedesktop/DBus" +#define _FREEDESKTOP_INTERFACE "org.freedesktop.DBus" + +#define _MAX_NW_TIME_OUT 20 + +typedef struct _app_id_cb_data { + char *caller_app_id; + char *real_app_id; + _facet_id_cb cb; + void *user_data; +}_app_id_cb_data_t; + +static inline int +__read_proc(const char *path, char *buf, int size) +{ + int fd = 0; + int ret = 0; + + if (buf == NULL || path == NULL) { + _ERR("path and buffer is mandatory\n"); + return -1; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + _ERR("fd open error(%d)\n", fd); + return -1; + } + + ret = read(fd, buf, size - 1); + if (ret <= 0) { + _ERR("fd read error(%d)\n", fd); + close(fd); + return -1; + } else + buf[ret] = 0; + + close(fd); + + return ret; +} + +static char* +__get_appid_of_dbus_caller(GDBusMethodInvocation *invocation) +{ + pid_t remote_pid = 0; + GError *error = NULL; + GDBusConnection *connection = NULL; + GVariant *response = NULL; + guint32 upid; + const gchar *sender = NULL; + + sender = g_dbus_method_invocation_get_sender (invocation); + if (!sender) { + _ERR("Failed to get sender"); + return NULL; + } + + connection = g_dbus_method_invocation_get_connection(invocation); + if (connection == NULL) { + _ERR("Failed to open connection for the invocation"); + return NULL; + } + + error = NULL; + response = g_dbus_connection_call_sync (connection, + _FREEDESKTOP_SERVICE, _FREEDESKTOP_PATH, + _FREEDESKTOP_INTERFACE, "GetConnectionUnixProcessID", + g_variant_new ("(s)", sender), ((const GVariantType *) "(u)"), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + + //g_object_unref (connection); + + if (response == NULL) { + _ERR("Failed to get caller id [%s]", error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (response, "(u)", &upid); + _INFO("Remote msg-bus peer service=%s pid=%u", sender, upid); + remote_pid = (pid_t) upid; + + g_variant_unref (response); + + char *app_id = NULL; + int ret = app_manager_get_app_id(remote_pid, &app_id); + + if (app_id == NULL) { + _ERR("app_manager_get_app_id for %d failed = %d", remote_pid, ret); + + /* Exception case : Daemons will not have app-ids, for them path will be set : /usr/bin/sample-service */ + char buf[128]; + int ret = 0; + + snprintf(buf, sizeof(buf), "/proc/%d/cmdline", upid); + ret = __read_proc(buf, buf, sizeof(buf)); + if (ret <= 0) { + _ERR("No proc directory (%d)\n", upid); + return NULL; + } + + _INFO("Caller=[%s]", buf); + + app_id = strdup(buf); + } + + + return app_id; +} + +static void +__soup_cb(SoupSession *session, SoupMessage *msg, gpointer user_data) +{ + _INFO("__soup_cb"); + + if (user_data == NULL) + return; + + _app_id_cb_data_t *cb_data = (_app_id_cb_data_t*)user_data; + + GList *app_id_list = NULL; + char *real_app_id = NULL; + + int error_code = FIDO_ERROR_UNTRUSTED_FACET_ID; + + SoupBuffer *request = NULL; + + _INFO("status_code = [%d]", msg->status_code); + + CATCH_IF_FAIL_X(msg->status_code == SOUP_STATUS_OK, error_code = FIDO_ERROR_UNTRUSTED_FACET_ID); + + request = soup_message_body_flatten(msg->response_body); + app_id_list = _uaf_parser_parse_trusted_facets(request->data); + + soup_buffer_free(request); + request = NULL; + + if (app_id_list == NULL) + error_code = FIDO_ERROR_UNTRUSTED_FACET_ID; + + GList *app_id_list_iter = app_id_list; + while (app_id_list_iter != NULL) { + char *id = (char *)(app_id_list_iter->data); + SoupURI *parsed_uri = soup_uri_new(id); + if (parsed_uri == NULL) + if (strcmp(cb_data->caller_app_id, id) == 0) { + real_app_id = strdup(id); + error_code = FIDO_ERROR_NONE; + break; + } + soup_uri_free(parsed_uri); + + app_id_list_iter = app_id_list_iter->next; + } + +CATCH: + (cb_data->cb)(error_code, real_app_id, cb_data->user_data); + + if (app_id_list != NULL) + g_list_free_full(app_id_list, free); + + SAFE_DELETE(real_app_id); + SAFE_DELETE(cb_data->real_app_id); + SAFE_DELETE(cb_data->caller_app_id); + SAFE_DELETE(cb_data); +} + +static void +_free_app_id_cb_data(_app_id_cb_data_t* data) +{ + _INFO(""); + + RET_IF_FAIL_VOID(data != NULL); + + SAFE_DELETE(data->real_app_id); + SAFE_DELETE(data->caller_app_id); + + SAFE_DELETE(data); + + _INFO(""); +} + +static gboolean +__timer_expired(gpointer data) +{ + _INFO("__timer_expired"); + _app_id_cb_data_t *cb_data = (_app_id_cb_data_t*)data; + (cb_data->cb)(FIDO_ERROR_NONE, cb_data->real_app_id, cb_data->user_data); + + _free_app_id_cb_data(cb_data); + + return FALSE; +} + +int +_verify_and_get_facet_id(const char *uaf_app_id, GDBusMethodInvocation *invocation, _facet_id_cb cb, void *user_data) +{ + _INFO("_verify_and_get_facet_id"); + + char *app_id = __get_appid_of_dbus_caller(invocation); + if (app_id == NULL) { + return FIDO_ERROR_PERMISSION_DENIED; + } + + _app_id_cb_data_t *cb_data = (_app_id_cb_data_t*)calloc(1, sizeof(_app_id_cb_data_t)); + if (cb_data == NULL) + return FIDO_ERROR_OUT_OF_MEMORY; + + cb_data->caller_app_id = app_id; + cb_data->cb = cb; + cb_data->user_data = user_data; + + if (uaf_app_id == NULL) { + cb_data->real_app_id = strdup(app_id); + g_timeout_add(2, __timer_expired, cb_data); + return FIDO_ERROR_NONE; + } + + + SoupURI *parsed_uri = soup_uri_new(uaf_app_id); + + if (parsed_uri == NULL) { + + if (strcmp(app_id, uaf_app_id) == 0) { + cb_data->real_app_id = strdup(uaf_app_id); + g_timeout_add(2, __timer_expired, cb_data); + return FIDO_ERROR_NONE; + } + else { + _free_app_id_cb_data(cb_data); + return FIDO_ERROR_PERMISSION_DENIED; + } + } + + const char *scheme = soup_uri_get_scheme(parsed_uri); + if (scheme == NULL) { + _free_app_id_cb_data(cb_data); + return FIDO_ERROR_INVALID_PARAMETER; + } + + if (strcmp(SOUP_URI_SCHEME_HTTPS, scheme) != 0) { + _free_app_id_cb_data(cb_data); + return FIDO_ERROR_INVALID_PARAMETER; + } + + _INFO("%s", uaf_app_id); + + SoupMessage *soup_message = soup_message_new_from_uri ("GET", parsed_uri); + + soup_uri_free(parsed_uri); + + SoupSession *session = soup_session_new_with_options( + SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT, + SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE, + SOUP_SESSION_TIMEOUT, _MAX_NW_TIME_OUT, + NULL); + + bool ssl_strict = FALSE;//changed to make sure https cert errors dont occur, only for testing + g_object_set(session, "ssl-strict", ssl_strict, NULL); + + soup_session_queue_message(session, soup_message, __soup_cb, cb_data); + + _INFO("Added in soup_session_queue_message"); + + return FIDO_ERROR_NONE; +} diff --git a/server/fido_app_id_handler.h b/server/fido_app_id_handler.h new file mode 100644 index 0000000..19e307d --- /dev/null +++ b/server/fido_app_id_handler.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef __FIDO_APP_ID_HANDLER_H__ +#define __FIDO_APP_ID_HANDLER_H__ + +#include +#include + +typedef void (*_facet_id_cb) (int eror_code, const char *facet_id, void *user_data); + +int _verify_and_get_facet_id(const char *uaf_app_id, GDBusMethodInvocation *invocation, _facet_id_cb cb, void *user_data); + +#endif /* __FIDO_APP_ID_HANDLER_H__ */ diff --git a/server/fido_asm_plugin_manager.c b/server/fido_asm_plugin_manager.c new file mode 100644 index 0000000..e61e2a2 --- /dev/null +++ b/server/fido_asm_plugin_manager.c @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "fido_logs.h" +#include "fido_uaf_types.h" +#include "fido_internal_types.h" +#include "fido_json_handler.h" +#include "fido_internal_types.h" + +#include "fido_asm_plugin_manager.h" + +#define _ASM_CONF_DIR_PATH "/usr/lib/fido/asm/" + +typedef struct _asm_ipc_cb_data { + _asm_ipc_response_cb cb; + void *user_data; +} _asm_ipc_cb_data_t; + +typedef struct _asm_ipc_discover_cb_data { + _asm_plugin_discover_response_cb cb; + GList *asm_proxy_list_iter; + void *user_data; + GList *asm_resp_list; +} _asm_ipc_discover_cb_data_t; + +static GHashTable *asm_proxy_table = NULL; +static GFileMonitor *__monitor = NULL; + +static GDBusConnection * +__get_dbus_connection(void) +{ + GError *error = NULL; + + GDBusConnection *dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + if (dbus_conn == NULL) { + _ERR("Unable to connect to dbus: %s", error->message); + g_clear_error(&error); + } + + return dbus_conn; +} + +static GDBusProxy* +__get_dbus_proxy(const char *dbus_name, const char *obj_path, + const char *intf_name) +{ + GDBusConnection *conn = __get_dbus_connection(); + if (conn == NULL) + return NULL; + + GError *err = NULL; + + GDBusProxy *dbus_proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + dbus_name, + obj_path, + intf_name, + NULL, + &err); + + if (err != NULL) + _ERR("g_dbus_proxy_new_sync failed [%d][%s]", err->code, err->message); + + return dbus_proxy; +} + +static void +__free_asm_proxy_data(gpointer data) +{ + if (data != NULL) { + _fido_asm_proxy_t *proxy = data; + + SAFE_DELETE(proxy->bin_path); + SAFE_DELETE(proxy->dbus_info); + SAFE_DELETE(proxy->dbus_interface_name); + SAFE_DELETE(proxy->dbus_method_name); + SAFE_DELETE(proxy->dbus_obj_path); + SAFE_DELETE(proxy->vendor); + + SAFE_DELETE(proxy); + } + + +} + +static int +__load_plugins(const char *path) +{ + RET_IF_FAIL(path != NULL, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR); + + if (asm_proxy_table != NULL) { + g_hash_table_destroy(asm_proxy_table); + asm_proxy_table = NULL; + } + + asm_proxy_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, _free_fido_asm_proxy); + + DIR *dir; + struct dirent *entry; + + dir = opendir(path); + if (dir == NULL) { + + _ERR("Could not open [%s] path = [%s]", path, strerror(errno)); + return FIDO_ERROR_PERMISSION_DENIED; + } + + bool is_asm_found = false; + + _INFO("Loading ASM conf files"); + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_type == DT_REG) { + char *conf_file_name = entry->d_name; + if (conf_file_name != NULL) { + char conf_file_name_full[128] = {0, }; + /*TODO make safe size*/ + snprintf(conf_file_name_full, 127, "%s%s", _ASM_CONF_DIR_PATH, conf_file_name); + _INFO("Processing [%s]", conf_file_name_full); + _fido_asm_proxy_t *asm_proxy = _parse_asm_conf_file(conf_file_name_full); + if (asm_proxy != NULL) { + asm_proxy->dbus_proxy = __get_dbus_proxy(asm_proxy->dbus_info, asm_proxy->dbus_obj_path, + asm_proxy->dbus_interface_name); + if (asm_proxy->dbus_proxy != NULL) { + is_asm_found = true; + + asm_proxy->asm_id = strdup(conf_file_name); + g_hash_table_insert(asm_proxy_table, strdup(conf_file_name), asm_proxy); + } + else { + _ERR("Failed to get dbus proxy for the ASM"); + __free_asm_proxy_data((gpointer)asm_proxy); + } + } + + } + } + } + + closedir(dir); + + if (is_asm_found == false) + return FIDO_ERROR_NOT_SUPPORTED; + + return FIDO_ERROR_NONE; +} + +static void +__plugin_changed_cb(GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, + void* user_data) +{ + int ret = __load_plugins(_ASM_CONF_DIR_PATH); + _INFO("__load_plugins=[%d]", ret); +} + +static void +__set_up_watcher(const char *watch_path) +{ + if ((watch_path == NULL) + || (strlen(watch_path) == 0)) + return; + + GFile* file = g_file_new_for_path(watch_path); + + if (__monitor != NULL) + g_object_unref(__monitor); + + __monitor = g_file_monitor(file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref(file); + + if (__monitor == NULL) + return; + + g_signal_connect(__monitor, "changed", G_CALLBACK(__plugin_changed_cb), NULL); +} + +int +_asm_plugin_mgr_init(void) +{ + + _INFO("_asm_plugin_mgr_init start"); + + int ret = __load_plugins(_ASM_CONF_DIR_PATH); + _INFO("__load_plugins=[%d]", ret); + + __set_up_watcher(_ASM_CONF_DIR_PATH); + + /*Ignored load_plugins error, since ASM might get installed later*/ + return FIDO_ERROR_NONE; +} + +void +_asm_plugin_mgr_destroy(void) +{ + if (asm_proxy_table != NULL) { + g_hash_table_destroy(asm_proxy_table); + asm_proxy_table = NULL; + } + if (__monitor != NULL) + g_object_unref(__monitor); +} + +static void +__discover_cb_internal(int error_code, const char *asm_response_json, void *user_data) +{ + _asm_ipc_discover_cb_data_t *cb_data = user_data; + + _asm_discover_response_t *response_info = calloc(1, sizeof(_asm_discover_response_t)); + response_info->error_code = error_code; + if (asm_response_json != NULL) + response_info->asm_response_json = strdup(asm_response_json); + + _fido_asm_proxy_t *asm_proxy = (_fido_asm_proxy_t*)(cb_data->asm_proxy_list_iter->data); + response_info->asm_id = strdup(asm_proxy->asm_id); + + cb_data->asm_resp_list = g_list_append(cb_data->asm_resp_list, response_info); + + cb_data->asm_proxy_list_iter = g_list_next(cb_data->asm_proxy_list_iter); + if (cb_data->asm_proxy_list_iter == NULL) { + _INFO("All ASM processing finished"); + + cb_data->asm_resp_list = g_list_first(cb_data->asm_resp_list); + (cb_data->cb)(cb_data->asm_resp_list, cb_data->user_data); + + cb_data->asm_proxy_list_iter = g_list_first(cb_data->asm_proxy_list_iter); + g_list_free(cb_data->asm_proxy_list_iter); + + SAFE_DELETE(cb_data); + } + else { + + _fido_asm_proxy_t *asm_proxy = (_fido_asm_proxy_t*)(cb_data->asm_proxy_list_iter->data); + int ret = _asm_ipc_send(asm_proxy->asm_id, _GET_INFO_ASM_REQUEST_JSON, __discover_cb_internal, cb_data); + if (ret != FIDO_ERROR_NONE) + __discover_cb_internal(ret, NULL, user_data); + } + +} + +int +_asm_plugin_mgr_discover_all(_asm_plugin_discover_response_cb cb, void *user_data) +{ + if (asm_proxy_table == NULL + || g_hash_table_size(asm_proxy_table) <= 0) { + _ERR("No ASM found"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + _asm_ipc_discover_cb_data_t *cb_data = calloc(1, sizeof(_asm_ipc_discover_cb_data_t)); + if (cb_data == NULL) + return -1; + + cb_data->cb = cb; + cb_data->asm_proxy_list_iter = g_hash_table_get_values(asm_proxy_table); + + cb_data->user_data = user_data; + + _fido_asm_proxy_t *asm_proxy = (_fido_asm_proxy_t*)(cb_data->asm_proxy_list_iter->data); + + return _asm_ipc_send(asm_proxy->asm_id, _GET_INFO_ASM_REQUEST_JSON, __discover_cb_internal, cb_data); +} + +static void +_on_asm_dbus_reply(GObject *proxy, GAsyncResult *res, gpointer user_data) +{ + _INFO("_on_asm_dbus_reply"); + + GError *dbus_err = NULL; + + if (user_data == NULL) { + _ERR("Can not proceed since callback data is NULL"); + return; + } + + _asm_ipc_cb_data_t *cb_data = (_asm_ipc_cb_data_t *)user_data; + if (cb_data == NULL) { + _ERR("Can not proceed since callback data is NULL"); + return; + } + + if (cb_data->cb == NULL) { + _ERR("Can not proceed since callback data's cb part is NULL"); + return; + } + + int tizen_err = FIDO_ERROR_NONE; + char *asm_response_json = NULL; + + GError *error = NULL; + + /*For dereg request, ASM does not send any reponse, so this is not error for dereg*/ + GVariant *dbus_resp = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error); + if (dbus_resp == NULL) { + _ERR("g_dbus_proxy_call_finish failed with [%d][%s]", error->code, error->message); + (cb_data->cb)(FIDO_ERROR_PERMISSION_DENIED, NULL, cb_data->user_data); + + SAFE_DELETE(cb_data); + + return; + } + + g_variant_get(dbus_resp, "(is)", + &tizen_err, + &asm_response_json); + + + g_clear_error(&dbus_err); + + if (asm_response_json != NULL) + _INFO("asm_response_json=[%s]", asm_response_json); + + (cb_data->cb)(tizen_err, asm_response_json, cb_data->user_data); + + if (dbus_resp != NULL) + g_variant_unref(dbus_resp); + + SAFE_DELETE(cb_data); +} + +static char* +__get_asm_req_dbus_method_name(const char *intf_name, const char *dbus_method_name) +{ + char *method_name = (char *)calloc(1, 128); + if (method_name == NULL) + return NULL; + + snprintf(method_name, 127, "%s.%s", intf_name, dbus_method_name); + + return method_name; +} + +int +_asm_ipc_send(const char *asm_id, const char *asm_request, _asm_ipc_response_cb cb, void *user_data) +{ + _INFO("asm_request=[%s]", asm_request); + + if (asm_id == NULL) { + _ERR("dbus proxy failed"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + _fido_asm_proxy_t *asm_proxy = g_hash_table_lookup(asm_proxy_table, asm_id); + if (asm_proxy == NULL) { + _ERR("dbus proxy failed"); + return FIDO_ERROR_NOT_SUPPORTED; + } + + _INFO("For=[%s]", asm_id); + + if (asm_proxy->dbus_info != NULL) + _INFO("For DBUS = [%s]", asm_proxy->dbus_info); + + _asm_ipc_cb_data_t *cb_data = (_asm_ipc_cb_data_t*)calloc(1, sizeof(_asm_ipc_cb_data_t)); + if (cb_data == NULL) + return -1; + + cb_data->cb = cb; + cb_data->user_data = user_data; + + char *method_name = __get_asm_req_dbus_method_name(asm_proxy->dbus_interface_name, + asm_proxy->dbus_method_name); + if (method_name == NULL) { + + SAFE_DELETE(cb_data); + return FIDO_ERROR_OUT_OF_MEMORY; + } + + g_dbus_proxy_call(asm_proxy->dbus_proxy, + method_name, + g_variant_new ("(s)", + asm_request), + G_DBUS_CALL_FLAGS_NONE, + _DBUS_TIMEOUT_INFINITE, + NULL, + _on_asm_dbus_reply, + cb_data); + + SAFE_DELETE(method_name); + + return 0; +} + +char * +_asm_ipc_send_sync(const char *asm_id, const char *asm_req) +{ + _INFO("_asm_ipc_send_sync"); + + if (asm_id == NULL) { + _ERR("dbus proxy failed"); + return NULL; + } + + _INFO("For=[%s]", asm_id); + + _fido_asm_proxy_t *asm_proxy = g_hash_table_lookup(asm_proxy_table, asm_id); + if (asm_proxy == NULL) { + _ERR("dbus proxy failed"); + return NULL; + } + + if (asm_proxy->dbus_info != NULL) + _INFO("For DBUS = [%s]", asm_proxy->dbus_info); + + int tz_err = FIDO_ERROR_NONE; + char *asm_res_json = NULL; + + GError *error = NULL; + GVariant *_ret; + + char *method_name = __get_asm_req_dbus_method_name(asm_proxy->dbus_interface_name, + asm_proxy->dbus_method_name); + + if (method_name == NULL) + return NULL; + + _ret = g_dbus_proxy_call_sync(asm_proxy->dbus_proxy, + method_name, + g_variant_new ("(s)", + asm_req), + G_DBUS_CALL_FLAGS_NONE, + _DBUS_TIMEOUT_USE_DEFAULT, + NULL, + &error); + + if (error != NULL) + _ERR("g_dbus_proxy_call_sync failed [%s]", error->message); + else + _INFO("g_dbus_proxy_call_sync success"); + + if (_ret == NULL) + goto CATCH; + + g_variant_get (_ret, "(is)", &tz_err, &asm_res_json); + if (asm_res_json != NULL) + _INFO("ASM returned = %s", asm_res_json); + + //g_variant_unref (_ret); + +CATCH: + return asm_res_json; +} diff --git a/server/fido_asm_plugin_manager.h b/server/fido_asm_plugin_manager.h new file mode 100644 index 0000000..ac7a62a --- /dev/null +++ b/server/fido_asm_plugin_manager.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef __FIDO_ASM_PLUGIN_MGR_H__ +#define __FIDO_ASM_PLUGIN_MGR_H__ + +#include +#include +#include "fido_internal_types.h" + +int _asm_plugin_mgr_init(void); + +void _asm_plugin_mgr_destroy(void); + +/*List of _asm_discover_response_t*/ +typedef void (*_asm_plugin_discover_response_cb) (GList *asm_disc_resp_list, void * user_data); +int _asm_plugin_mgr_discover_all(_asm_plugin_discover_response_cb cb, void *user_data); + +typedef void (*_asm_ipc_response_cb) (int eror_code, const char *asm_response_json, void * user_data); + +int _asm_ipc_send(const char *asm_id, const char *asm_request, _asm_ipc_response_cb cb, void *user_data); + +char *_asm_ipc_send_sync(const char *asm_id, const char *asm_req); + +#endif /* __FIDO_ASM_PLUGIN_MGR_H__ */ diff --git a/server/fido_privilege_checker.c b/server/fido_privilege_checker.c new file mode 100644 index 0000000..528c8a0 --- /dev/null +++ b/server/fido_privilege_checker.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include "fido_privilege_checker.h" +#include "fido_logs.h" + +#include +#include +#include + +#define _DISABLE_PRIV_CHECK + +static cynara *__cynara = NULL; + +static guint +_get_client_pid(GDBusMethodInvocation* invoc) +{ + const char *name = NULL; + name = g_dbus_method_invocation_get_sender(invoc); + if (name == NULL) + { + _ERR("g_dbus_method_invocation_get_sender failed"); + return -1; + } + _INFO("sender=[%s]", name); + + + guint pid = -1; + GError *error = NULL; + GVariant *_ret; + + _INFO("calling GetConnectionUnixProcessID"); + + GDBusConnection* conn = g_dbus_method_invocation_get_connection(invoc); + _ret = g_dbus_connection_call_sync(conn, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + g_variant_new("(s)", name), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (_ret != NULL) { + g_variant_get(_ret, "(u)", &pid); + g_variant_unref(_ret); + } + + _INFO("process Id = [%u]", pid); + return pid; +} + +static int +__check_privilege_by_cynara(const char *client, const char *session, const char *user, const char *privilege) +{ + int ret; + char err_buf[128] = {0,}; + + ret = cynara_check(__cynara, client, session, user, privilege); + switch (ret) { + case CYNARA_API_ACCESS_ALLOWED: + _DBG("cynara_check success"); + return FIDO_ERROR_NONE; + + case CYNARA_API_ACCESS_DENIED: + _ERR("cynara_check permission deined, privilege=%s, error = CYNARA_API_ACCESS_DENIED", privilege); + return FIDO_ERROR_PERMISSION_DENIED; + + default: + cynara_strerror(ret, err_buf, sizeof(err_buf)); + _ERR("cynara_check error : %s, privilege=%s, ret = %d", err_buf, privilege, ret); + return FIDO_ERROR_PERMISSION_DENIED; + } +} + +static int +__get_information_for_cynara_check(GDBusMethodInvocation *invocation, char **client, char **user, char **session) +{ + GDBusConnection *gdbus_conn = NULL; + char* sender = NULL; + int ret = -1; + + gdbus_conn = g_dbus_method_invocation_get_connection(invocation); + if(gdbus_conn == NULL) { + _ERR("g_dbus_method_invocation_get_connection failed"); + return -1; + } + + sender = (char*) g_dbus_method_invocation_get_sender(invocation); + if (sender == NULL) { + _ERR("g_dbus_method_invocation_get_sender failed"); + return -1; + } + + ret = cynara_creds_gdbus_get_user(gdbus_conn, sender, USER_METHOD_DEFAULT, user); + if (ret != CYNARA_API_SUCCESS) { + _ERR("cynara_creds_gdbus_get_user failed, ret = %d", ret); + return -1; + } + + ret = cynara_creds_gdbus_get_client(gdbus_conn, sender, CLIENT_METHOD_DEFAULT, client); + if (ret != CYNARA_API_SUCCESS) { + _ERR("cynara_creds_gdbus_get_client failed, ret = %d", ret); + return -1; + } + + guint pid = _get_client_pid(invocation); + _INFO("client Id = [%u]", pid); + + *session = cynara_session_from_pid(pid); + if (*session == NULL) { + _ERR("cynara_session_from_pid failed"); + return -1; + } + return FIDO_ERROR_NONE; +} + +bool +is_allowed_to_call(GDBusMethodInvocation *invocation, const char* privilege) +{ + int ret = -1; + + if (__cynara == NULL) { + ret = cynara_initialize(&__cynara, NULL); + if(ret != CYNARA_API_SUCCESS) { + _ERR("CYNARA Initialization fail"); + return false; + } + } + + char *client = NULL; + char *session = NULL; + char *user = NULL; + + ret = __get_information_for_cynara_check(invocation, &client, &user, &session); + if ( ret != FIDO_ERROR_NONE) { + _ERR("__get_information_for_cynara_check failed"); + g_free(client); + g_free(user); + SAFE_DELETE(session); + + return false; + } + + ret = __check_privilege_by_cynara(client, session, user, privilege); + + /*TODO enable after smack is defined*/ +#ifndef _DISABLE_PRIV_CHECK + if ( ret != FIDO_ERROR_NONE) { + _ERR("__check_privilege_by_cynara failed, ret = %d", ret); + g_free(client); + g_free(user); + SAFE_DELETE(session); + + return false; + } +#endif + g_free(client); + g_free(user); + SAFE_DELETE(session); + + return true; +} diff --git a/server/fido_privilege_checker.h b/server/fido_privilege_checker.h new file mode 100644 index 0000000..b24447d --- /dev/null +++ b/server/fido_privilege_checker.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_PRIVILEGE_CHECKER_H +#define FIDO_PRIVILEGE_CHECKER_H + +#include +#include "fido_internal_types.h" + +#define _FIDO_CLIENT_PRIVILEGE "http://tizen.org/privilege/fido" + +bool is_allowed_to_call(GDBusMethodInvocation *invocation, const char* privilege); + +#endif // FIDO_PRIVILEGE_CHECKER_H diff --git a/server/fido_selection_ui_adaptor.c b/server/fido_selection_ui_adaptor.c new file mode 100644 index 0000000..17ae88b --- /dev/null +++ b/server/fido_selection_ui_adaptor.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fido_selection_ui_adaptor.h" +#include "fido_uaf_types.h" +#include "fido_logs.h" +#include "fido-stub.h" +#include "fido_internal_types.h" + +#define _UI_LAUNCH_RETRY_COUNT 5 +#define _UI_SVC_TERMINATE_TIMEOUT 2000 + +#define _FREEDESKTOP_SERVICE "org.freedesktop.DBus" +#define _FREEDESKTOP_PATH "/org/freedesktop/DBus" +#define _FREEDESKTOP_INTERFACE "org.freedesktop.DBus" + +static GQueue *_ui_q = NULL; +static int __ui_svc_pid = -1; + +static int _process_ui_selection_queue(void); + +typedef struct _ui_response_cb_data { + GList *auth_list; + _ui_response_cb cb; + void *user_data; +} _ui_response_cb_data_t; + +static void +__free_ui_auth_data(gpointer data) +{ + RET_IF_FAIL_VOID(data != NULL); + + _ui_auth_data_t *auth_data = data; + + SAFE_DELETE(auth_data->asm_id); + SAFE_DELETE(auth_data->auth_index); + SAFE_DELETE(auth_data->label); + + SAFE_DELETE(auth_data); +} + +static void +__free_ui_response_cb_data(_ui_response_cb_data_t *data) +{ + RET_IF_FAIL_VOID(data != NULL); + + if (data->auth_list != NULL) + g_list_free_full(data->auth_list, __free_ui_auth_data); + + SAFE_DELETE(data); +} + +static GQueue * +_get_ui_queue(void) +{ + if (_ui_q != NULL) + return _ui_q; + + _ui_q = g_queue_new(); + if (_ui_q == NULL) { + _ERR("Out of memory"); + } + + return _ui_q; +} + +_ui_auth_data_t* +_compose_json_ui_out(const char *response_json) +{ + _INFO("_compose_json_ui_out %s", response_json); + + char *ui_response_json = strdup(response_json); + _ui_auth_data_t *ui_auth_data = NULL; + GError *parse_err = NULL; + JsonParser *parser = NULL; + JsonNode *root = NULL; + JsonObject *obj = NULL; + + parser = json_parser_new(); + if (!parser) { + _ERR("json_parser_new failed"); + goto CATCH; + } + + json_parser_load_from_data(parser, ui_response_json, -1, &parse_err); + if (parse_err != NULL) { + _ERR("json parse failure"); + goto CATCH; + } + + root = json_parser_get_root(parser); + if (!root) { + _ERR("json_parser_get_root() failed"); + goto CATCH; + } + + obj = json_node_get_object(root); + if (!obj) { + _ERR("json_node_get_object() failed"); + goto CATCH; + } + + const char *asm_id = json_object_get_string_member(obj, UI_DATA_ASM_ID); + if (!asm_id) { + _ERR("json_object_get_string_member() failed"); + goto CATCH; + } + + const char *auth_idx = NULL; + auth_idx = json_object_get_string_member(obj, UI_DATA_AUTH_INDEX); + if (!auth_idx) { + _ERR("json_object_get_string_member() failed"); + goto CATCH; + } + + const char *label = NULL; + label = json_object_get_string_member(obj, UI_DATA_LABEL); + if (!label) { + _ERR("json_object_get_string_member() failed"); + goto CATCH; + } + + int att = -1; + att = json_object_get_int_member(obj, UI_DATA_ATT_TYPE); + + ui_auth_data = (_ui_auth_data_t *) calloc(1, sizeof(_ui_auth_data_t)); + if (ui_auth_data == NULL) + { + _ERR("Out of memory"); + goto CATCH; + } + + ui_auth_data->asm_id = strdup(asm_id); + ui_auth_data->auth_index = strdup(auth_idx); + ui_auth_data->label = strdup(label); + ui_auth_data->att_type = att; + +CATCH: + if (parse_err != NULL) { + g_error_free(parse_err); + parse_err = NULL; + } + + if (root != NULL) { + json_node_free(root); + root = NULL; + } + + if (obj != NULL) { + g_object_unref(obj); + obj = NULL; + } + + SAFE_DELETE(ui_response_json); + + return ui_auth_data; +} + +char * +_compose_json_ui_in(GList *auth_list) +{ + _INFO("_compose_json_ui_in"); + + char *json_ui_arr = NULL; + JsonGenerator *generator = NULL; + JsonNode *root_node = NULL; + JsonArray *ui_arr = NULL; + + generator = json_generator_new(); + if(generator == NULL) { + _ERR("json_generator_new is NULL"); + goto CATCH; + } + + root_node = json_node_new(JSON_NODE_ARRAY); + if (root_node == NULL) { + _ERR("json_node_new is NULL"); + goto CATCH; + } + + ui_arr = json_array_new(); + if (ui_arr == NULL) { + _ERR("json_array_new is NULL"); + goto CATCH; + } + + json_node_take_array(root_node, ui_arr); + json_generator_set_root(generator, root_node); + + GList *auth_list_iter = auth_list; + while (auth_list_iter != NULL) { + _ui_auth_data_t *ui_data = (_ui_auth_data_t *)(auth_list_iter->data); + + if (ui_data) { + JsonObject *obj = json_object_new(); + + if (ui_data->asm_id != NULL) + json_object_set_string_member(obj, UI_DATA_ASM_ID, ui_data->asm_id); + + json_object_set_string_member(obj, UI_DATA_AUTH_INDEX, ui_data->auth_index); + if (ui_data->label != NULL) + json_object_set_string_member(obj, UI_DATA_LABEL, ui_data->label); + json_object_set_int_member(obj, UI_DATA_ATT_TYPE, ui_data->att_type); + + json_array_add_object_element(ui_arr, obj); + } + + auth_list_iter = auth_list_iter->next; + } + + json_ui_arr = json_generator_to_data(generator, NULL); + +CATCH: + if (generator != NULL) { + g_object_unref(generator); + generator = NULL; + } + + if (root_node != NULL) { + json_node_free(root_node); + root_node = NULL; + } + + if (ui_arr != NULL) { + json_array_unref(ui_arr); + ui_arr = NULL; + } + + return json_ui_arr; +} + +//static int +//__iterfunc(const aul_app_info *info, void *data) +//{ +// if (strcmp(info->pkg_name, _UI_SVC_PACKAGE) == 0) { +// aul_terminate_pid(info->pid); +// _INFO("After aul_terminate_pid"); +// return false; +// } +// return true; +//} + +static void +__terminate_ui_svc(void) +{ + _INFO("Killing inactive UI Service [%d]", __ui_svc_pid); + + if (__ui_svc_pid > 0) + aul_terminate_pid(__ui_svc_pid); + + __ui_svc_pid = -1; +} + +static gboolean +__timer_expired(gpointer data) +{ + if (g_queue_is_empty(_ui_q) == TRUE) + __terminate_ui_svc(); + + return FALSE; +} + +static void +__start_ui_svc_term_timer(void) +{ + g_timeout_add(_UI_SVC_TERMINATE_TIMEOUT, __timer_expired, NULL); +} + +static int +__launch_svc_ui(bundle *ui_req) +{ + int i = 0; + for (; i < _UI_LAUNCH_RETRY_COUNT; i++) { + if (__ui_svc_pid < 0) + __ui_svc_pid = aul_launch_app(_UI_SVC_PACKAGE, ui_req); + else { + aul_terminate_pid(__ui_svc_pid); + __ui_svc_pid = -1; + + __ui_svc_pid = aul_launch_app(_UI_SVC_PACKAGE, ui_req); + } + + _INFO("fido svc pid = [%d]", __ui_svc_pid); + + if (__ui_svc_pid > 0) + return FIDO_ERROR_NONE; + } + return FIDO_ERROR_UNKNOWN; +} + +static int +_process_ui_selection_queue(void) +{ + _INFO("_process_ui_selection_queue"); + GQueue *q = _ui_q; + RET_IF_FAIL(q, FIDO_ERROR_INVALID_PARAMETER); + + if (g_queue_is_empty(q) == true) + return FIDO_ERROR_NONE; + + _ui_response_cb_data_t *ui_res_data = (_ui_response_cb_data_t *)(g_queue_peek_head(q)); + RET_IF_FAIL(ui_res_data, FIDO_ERROR_INVALID_PARAMETER); + + char *ui_data = _compose_json_ui_in(ui_res_data->auth_list); + if (ui_data == NULL) { + ui_res_data->cb(FIDO_ERROR_OUT_OF_MEMORY, NULL, ui_res_data->user_data); + g_queue_pop_head(q); + return FIDO_ERROR_OUT_OF_MEMORY; + } + + _INFO("Sending to UI SVC"); + _INFO("%s", ui_data); + + bundle *ui_req = bundle_create(); + bundle_add_str(ui_req, _UI_IPC_KEY_REQ, ui_data); + + return __launch_svc_ui(ui_req); +} + +int +_auth_ui_selector_send(GList *auth_list, _ui_response_cb cb, void *user_data) +{ + _INFO("_auth_ui_selector_send"); + RET_IF_FAIL(auth_list, FIDO_ERROR_INVALID_PARAMETER); + + _ui_response_cb_data_t *ui_cb_data = (_ui_response_cb_data_t *) calloc(1, sizeof(_ui_response_cb_data_t)); + RET_IF_FAIL(ui_cb_data, FIDO_ERROR_OUT_OF_MEMORY); + + ui_cb_data->auth_list = auth_list; + ui_cb_data->cb = cb; + ui_cb_data->user_data = user_data; + + GQueue *q = _get_ui_queue(); + if (q == NULL) { + __free_ui_response_cb_data(ui_cb_data); + return FIDO_ERROR_OUT_OF_MEMORY; + } + + g_queue_push_tail(q, ui_cb_data); + _INFO("Q len=[%d]", g_queue_get_length(q)); + + if (g_queue_get_length(q) == 1) + _process_ui_selection_queue(); + + return FIDO_ERROR_NONE; +} + +static inline int +__read_proc(const char *path, char *buf, int size) +{ + int fd = 0; + int ret = 0; + + if (buf == NULL || path == NULL) { + _ERR("path and buffer is mandatory\n"); + return -1; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + _ERR("fd open error(%d)\n", fd); + return -1; + } + + ret = read(fd, buf, size - 1); + if (ret <= 0) { + _ERR("fd read error(%d)\n", fd); + close(fd); + return -1; + } else + buf[ret] = 0; + + close(fd); + + return ret; +} + +static char* +__get_proc_path_of_dbus_caller(GDBusMethodInvocation *invocation) +{ + //pid_t remote_pid = 0; + GError *error = NULL; + GDBusConnection *connection = NULL; + GVariant *response = NULL; + guint32 upid; + const gchar *sender = NULL; + + sender = g_dbus_method_invocation_get_sender (invocation); + if (!sender) { + _ERR("Failed to get sender"); + return NULL; + } + + connection = g_dbus_method_invocation_get_connection(invocation); + if (connection == NULL) { + _ERR("Failed to open connection for the invocation [%s]", error->message); + g_error_free (error); + return NULL; + } + + error = NULL; + response = g_dbus_connection_call_sync (connection, + _FREEDESKTOP_SERVICE, _FREEDESKTOP_PATH, + _FREEDESKTOP_INTERFACE, "GetConnectionUnixProcessID", + g_variant_new ("(s)", sender), ((const GVariantType *) "(u)"), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + + if (response == NULL) { + _ERR("Failed to get caller id [%s]", error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (response, "(u)", &upid); + _INFO("Remote msg-bus peer service=%s pid=%u", sender, upid); + //remote_pid = (pid_t) upid; + + g_variant_unref (response); + + char buf[128]; + int ret = 0; + + snprintf(buf, sizeof(buf), "/proc/%d/cmdline", upid); + ret = __read_proc(buf, buf, sizeof(buf)); + if (ret <= 0) { + _ERR("No proc directory (%d)\n", upid); + return NULL; + } + + _INFO("Caller=[%s]", buf); + + return strdup(buf); +} + +gboolean +_auth_ui_selector_on_ui_response(Fido *object, GDBusMethodInvocation *invocation, int error, const char *ui_resp) +{ + _INFO(""); + + char *caller = __get_proc_path_of_dbus_caller(invocation); + if (caller == NULL) { + _ERR("__get_proc_path_of_dbus_caller failed"); + __start_ui_svc_term_timer(); + return true; + } + + if (strcmp(caller, _UI_SVC_BIN_PATH) != 0) { + _ERR("[%s] is not allowed", caller); + __start_ui_svc_term_timer(); + return true; + } + + _ui_response_cb_data_t *cb_data = (_ui_response_cb_data_t*)(g_queue_pop_head(_ui_q)); + if (cb_data == NULL) { + _ERR("Can not proceed since callback data is NULL"); + goto CATCH; + } + + if (cb_data->cb == NULL) { + _ERR("Can not proceed since callback data's cb part is NULL"); + goto CATCH; + } + + if (error != FIDO_ERROR_NONE) + cb_data->cb(error, NULL, cb_data->user_data); + else { + if (ui_resp == NULL) + cb_data->cb(FIDO_ERROR_PERMISSION_DENIED, NULL, cb_data->user_data); + else { + _INFO("response from server = [%s]", ui_resp); + + _ui_auth_data_t *ui_auth_data = _compose_json_ui_out(ui_resp); + cb_data->cb(FIDO_ERROR_NONE, ui_auth_data, cb_data->user_data); + } + } + +CATCH: + + if (g_queue_is_empty(_ui_q) == false) + _process_ui_selection_queue(); + else { + g_queue_free(_ui_q); + _ui_q = NULL; + __start_ui_svc_term_timer(); + } + + return true; +} diff --git a/server/fido_selection_ui_adaptor.h b/server/fido_selection_ui_adaptor.h new file mode 100644 index 0000000..f2ee329 --- /dev/null +++ b/server/fido_selection_ui_adaptor.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_SELECTION_UI_ADAPTOR_H +#define FIDO_SELECTION_UI_ADAPTOR_H + +#include +#include +#include "fido-stub.h" +#include "fido_internal_types.h" + +gboolean _auth_ui_selector_on_ui_response(Fido *object, GDBusMethodInvocation *invocation, int error, const char *ui_resp); + +typedef void (*_ui_response_cb) (int eror_code, _ui_auth_data_t *selected_auth_data, void *user_data); +int _auth_ui_selector_send(GList *auth_list, _ui_response_cb cb, void *user_data); + +#endif // FIDO_SELECTION_UI_ADAPTOR_H diff --git a/server/fido_server.c b/server/fido_server.c new file mode 100755 index 0000000..297e3e6 --- /dev/null +++ b/server/fido_server.c @@ -0,0 +1,1378 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include +#if !GLIB_CHECK_VERSION (2, 31, 0) +#include +#endif + +#include "fido_privilege_checker.h" +#include "fido_asm_plugin_manager.h" +#include "fido_internal_types.h" +#include "fido_json_handler.h" +#include "fido_keys.h" +#include "fido_app_id_handler.h" +#include "fido_uaf_policy_checker.h" +#include "fido_selection_ui_adaptor.h" +#include "fido_logs.h" +#include "fido_uaf_types.h" +#include "fido-stub.h" + +#define _FIDO_SERVICE_DBUS_PATH "/org/tizen/fido" +static guint owner_id = 0; +//GDBusObjectManagerServer *fido_dbus_mgr = NULL; +static Fido* fido_dbus_obj = NULL; + +//TODO : current assumption is, ASM will handle multiple request queueing + +typedef struct _dbus_info{ + Fido *dbus_obj; + GDBusMethodInvocation *invocation; +}_dbus_info_t; + +typedef struct _discover_cb { + //fido_authenticator_cb cb; + void *user_data; + _dbus_info_t *dbus_info; +} discover_cb_t; + +typedef struct _fido_discover_asm_cb_data { + _fido_discover_asm_cb cb; + void *user_data; +}_fido_discover_asm_cb_data_t; + +typedef enum { + _PROCESS_TYPE_MIN = 0, + _PROCESS_TYPE_AUTH, + _PROCESS_TYPE_REG, + _PROCESS_TYPE_DEREG, + _PROCESS_TYPE_CHECK_POLICY, + _PROCESS_TYPE_MAX +} _process_type_t; + +typedef struct _process_cb_data { + _process_type_t type; + _message_t *uaf_req; + void *asm_in;/* ASM input data, type varies depending on operation name */ + _dbus_info_t *dbus_info; +} _process_cb_data_t; + +static void __process_dereg_queue(_dereg_q_t *dereg_q); + +static char** +__create_empty_json_2d_array(void) +{ + char **asm_resp_json_arr = calloc(1, sizeof(int)); + + char *empty_asm_resp = calloc(1, 128); + snprintf(empty_asm_resp, 127, "%s", _EMPTY_JSON_STRING); + asm_resp_json_arr[0] = empty_asm_resp; + + return asm_resp_json_arr; +} + +static void +__free_2d_string_array(char **arr, int row_count) +{ + RET_IF_FAIL_VOID(arr != NULL); + + int i = 0; + for (; i < row_count; i++) + SAFE_DELETE(arr[i]); + + SAFE_DELETE(arr); +} + +static char* +__dup_string(const char *source) +{ + if (source != NULL) + return strdup(source); + + return NULL; +} + +static void +__free_asm_discover_response_list_item(gpointer data) +{ + RET_IF_FAIL_VOID(data != NULL); + + _free_asm_discover_response((_asm_discover_response_t*)data); +} + +static void +__send_discover_response(Fido *object, GDBusMethodInvocation *invocation, int err, char **asm_resp_2d_arr, int asm_resp_len) +{ + if (asm_resp_2d_arr == NULL + || asm_resp_len <= 0) { + + char **empty_arr = __create_empty_json_2d_array(); + fido_complete_fido_uaf_discover(object, invocation, err, + (const gchar * const*)empty_arr, 0); + + __free_2d_string_array(empty_arr, 1); + return; + } + + fido_complete_fido_uaf_discover(object, invocation, err, + (const gchar * const*)asm_resp_2d_arr, asm_resp_len); + + __free_2d_string_array(asm_resp_2d_arr, asm_resp_len); +} + +void +_asm_get_info_cb(GList *asm_resp_list, void *user_data) +{ + _INFO("_asm_get_info_cb"); + + _dbus_info_t *dbus_info = (_dbus_info_t *)user_data; + if (dbus_info != NULL) { + + if (asm_resp_list != NULL) { + + int str_list_len = g_list_length(asm_resp_list); + char **asm_resp_json_arr = calloc(str_list_len, sizeof(int)); + int data_len = 0; + int i = 0; + + GList *asm_resp_list_iter = g_list_first(asm_resp_list); + while (asm_resp_list_iter != NULL) { + _asm_discover_response_t *disc_resp = (_asm_discover_response_t*)(asm_resp_list_iter->data); + + if (disc_resp->asm_response_json != NULL) { + asm_resp_json_arr[i++] = strdup(disc_resp->asm_response_json); + data_len++; + } + asm_resp_list_iter = g_list_next(asm_resp_list_iter); + } + + __send_discover_response(dbus_info->dbus_obj, dbus_info->invocation, FIDO_ERROR_NONE, + asm_resp_json_arr, data_len); + } + else + __send_discover_response(dbus_info->dbus_obj, dbus_info->invocation, FIDO_ERROR_NOT_SUPPORTED, + NULL, 0); + } + + if (asm_resp_list != NULL) + g_list_free_full(asm_resp_list, __free_asm_discover_response_list_item); +} + +static void +_send_process_response(_process_cb_data_t *cb_data, int tz_err_code, char *uaf_response_json) +{ + _INFO("_send_process_response"); + + /*TODO*/ + _dbus_info_t *dbus_info = (_dbus_info_t *)(cb_data->dbus_info); + if (dbus_info != NULL) + { + if (cb_data->type == _PROCESS_TYPE_CHECK_POLICY) { + _INFO("before fido_complete_fido_uaf_check_policy"); + fido_complete_fido_uaf_check_policy(dbus_info->dbus_obj, dbus_info->invocation, tz_err_code); + goto CATCH; + } + + _INFO("before fido_complete_fido_uaf_process_operation"); + + if (uaf_response_json != NULL) + fido_complete_fido_uaf_process_operation(dbus_info->dbus_obj, dbus_info->invocation, FIDO_ERROR_NONE, + uaf_response_json); + else + fido_complete_fido_uaf_process_operation(dbus_info->dbus_obj, dbus_info->invocation, tz_err_code, _EMPTY_JSON_STRING); + } + +CATCH: + SAFE_DELETE(uaf_response_json); + _free_message(cb_data->uaf_req); + + SAFE_DELETE(cb_data->dbus_info); + + if (cb_data->type == _PROCESS_TYPE_AUTH) + _free_fido_asm_auth_in((_fido_asm_auth_in_t*)(cb_data->asm_in)); + else if (cb_data->type == _PROCESS_TYPE_REG) + _free_fido_asm_reg_in((_fido_asm_reg_in_t*)(cb_data->asm_in)); + else if (cb_data->type == _PROCESS_TYPE_DEREG) + _free_fido_asm_dereg_in((_fido_asm_dereg_in_t*)(cb_data->asm_in)); + else + SAFE_DELETE(cb_data->asm_in); + + SAFE_DELETE(cb_data); +} + +void +_discover_response_intermediate_cb(GList *asm_response_list, void *user_data) +{ + _INFO("_discover_response_intermediate_cb"); + + _fido_discover_asm_cb_data_t *cb_data = (_fido_discover_asm_cb_data_t *)user_data; + + int error = FIDO_ERROR_NONE; + GList *asm_auth_list = NULL; + + if (asm_response_list == NULL) + _ERR("Discover response failed"); + else { + asm_auth_list = _uaf_parser_parse_asm_response_discover(asm_response_list, &error); + } + + (cb_data->cb)(error, 0, asm_auth_list, cb_data->user_data); + + if (asm_response_list != NULL) + g_list_free_full(asm_response_list, __free_asm_discover_response_list_item); +} + +static int +__fido_uaf_discover_internal(_fido_discover_asm_cb callback, void *user_data) +{ + _INFO("__fido_uaf_discover_internal"); + + _fido_discover_asm_cb_data_t *cb_data_inter_mediate = (_fido_discover_asm_cb_data_t *) calloc(1, sizeof(_fido_discover_asm_cb_data_t)); + cb_data_inter_mediate->cb = callback; + cb_data_inter_mediate->user_data = user_data; + + return _asm_plugin_mgr_discover_all(_discover_response_intermediate_cb, cb_data_inter_mediate); +} + +static void +_asm_response_auth_process(int error_code, const char *asm_response_json, void *user_data) +{ + _INFO("_asm_response_auth_process"); + + if (user_data == NULL) + _ERR("user_data is NULL"); + + _process_cb_data_t *cb_data = (_process_cb_data_t*)user_data; + if (cb_data == NULL) { + _ERR("_process_cb_data_t not found"); + return; + } + + _INFO("error_code = [%d]", error_code); + + if (error_code != 0) { + _ERR("ASM response contains error code [%d]", error_code); + _send_process_response((_process_cb_data_t *)user_data, error_code, NULL); + return; + } + + _asm_out_t *asm_out = NULL; + + _INFO("before _uaf_parser_parse_asm_response_auth"); + + int parser_err = 0; + asm_out = _uaf_parser_parse_asm_response_auth(asm_response_json, &parser_err); + if (parser_err != 0 || asm_out == NULL) { + _ERR("_uaf_parser_parse_asm_response_auth failed"); + + int uaf_err_code = _convert_asm_status_code_to_uaf_error(parser_err); + if (uaf_err_code == FIDO_ERROR_NONE) + _send_process_response(cb_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + else + _send_process_response(cb_data, uaf_err_code, NULL); + + _free_asm_out(asm_out); + asm_out = NULL; + + return; + } + + _asm_auth_out_t *asm_auth_out = (_asm_auth_out_t*)(asm_out->response_data); + + _fido_asm_auth_in_t *asm_auth_in = (_fido_asm_auth_in_t *) cb_data->asm_in; + + _message_t *uaf_message = cb_data->uaf_req; + + _op_header_t *header = uaf_message->header; + + char *uaf_response_json = NULL; + + + /* TODO : Add logic to accumulate multiple auth response and form the assertion_list*/ + GList *assertion_list = NULL; + + _auth_reg_assertion_t *asst_data = (_auth_reg_assertion_t*)calloc(1, sizeof(_auth_reg_assertion_t)); + + _INFO("before assertion"); + asst_data->assertion = strdup(asm_auth_out->assertion); + + _INFO("before assertion_schm"); + asst_data->assertion_schm = strdup(asm_auth_out->assertion_scheme); + + assertion_list = g_list_append(assertion_list, asst_data); + + assertion_list = g_list_first(assertion_list); + + + _INFO("before _uaf_composer_compose_uaf_process_response_auth"); + parser_err = _uaf_composer_compose_uaf_process_response_auth(header, asm_auth_in->final_challenge, + assertion_list, &uaf_response_json); + + g_list_free_full(assertion_list, _free_auth_reg_assertion_list_item); + + _free_asm_out(asm_out); + asm_out = NULL; + + if (parser_err != 0) { + _ERR("_uaf_composer_compose_uaf_process_response_auth failed"); + _send_process_response((_process_cb_data_t *)user_data, FIDO_ERROR_INVALID_PARAMETER, NULL); + return; + } + + _send_process_response(cb_data, FIDO_ERROR_NONE, uaf_response_json); +} + +static void +_asm_response_reg_process(int error_code, const char *asm_response_json, void *user_data) +{ + _INFO("_asm_response_reg_process"); + + _process_cb_data_t *cb_data = (_process_cb_data_t*)user_data; + if (cb_data == NULL) + return; + + if (error_code != 0) { + _ERR("ASM response contains error code [%d]", error_code); + + _send_process_response((_process_cb_data_t *)user_data, error_code, NULL); + + return; + } + + _asm_out_t *asm_out = NULL; + int parser_err = 0; + asm_out = _uaf_parser_parse_asm_response_reg(asm_response_json, &parser_err); + if (parser_err != 0 || asm_out == NULL) { + _ERR("_uaf_parser_parse_asm_response_reg failed"); + + int uaf_err_code = _convert_asm_status_code_to_uaf_error(parser_err); + if (uaf_err_code == FIDO_ERROR_NONE) + _send_process_response((_process_cb_data_t *)user_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + else + _send_process_response((_process_cb_data_t *)user_data, uaf_err_code, NULL); + + _free_asm_out(asm_out); + + return; + } + + _asm_reg_out_t *asm_reg_out = (_asm_reg_out_t*)(asm_out->response_data); + + _fido_asm_reg_in_t *asm_reg_in = (_fido_asm_reg_in_t *)(cb_data->asm_in); + + _message_t *uaf_req = cb_data->uaf_req; + _op_header_t *header = uaf_req->header; + + char *uaf_response_json = NULL; + + /* TODO : Add logic to accumulate multiple auth response and form the assertion_list*/ + _auth_reg_assertion_t *ass_data = (_auth_reg_assertion_t*) calloc(1, sizeof(_auth_reg_assertion_t)); + ass_data->assertion = __dup_string(asm_reg_out->assertion); + ass_data->assertion_schm = __dup_string(asm_reg_out->assertion_schm); + + + _free_asm_out(asm_out); + asm_out = NULL; + + GList *ass_list = NULL; + ass_list = g_list_append(ass_list, ass_data); + + parser_err = _uaf_composer_compose_uaf_process_response_reg(header, asm_reg_in->final_challenge, + ass_list, &uaf_response_json); + + g_list_free_full(ass_list, _free_auth_reg_assertion_list_item); + + if (parser_err != 0) { + _ERR("_uaf_composer_compose_uaf_process_response_reg failed"); + _send_process_response((_process_cb_data_t *)user_data, FIDO_ERROR_INVALID_PARAMETER, NULL); + return; + } + + _send_process_response((_process_cb_data_t *)user_data, FIDO_ERROR_NONE, uaf_response_json); +} + +static void +__handle_reg(_process_cb_data_t *cb_data, _matched_auth_data_t *matched_auth) +{ + _INFO(""); + + _message_t *uaf_req = (_message_t *)(cb_data->uaf_req); + + _reg_request_t *uaf_reg_req = (_reg_request_t *)(cb_data->uaf_req->data); + + _fido_asm_reg_in_t *reg_in = (_fido_asm_reg_in_t*) calloc(1, sizeof(_fido_asm_reg_in_t)); + + /*If no app-id mentioned in UAF request*/ + if (cb_data->uaf_req->header->app_id == NULL) { + if (cb_data->uaf_req->facet_id == NULL) { + _ERR("Failed to get app id"); + _send_process_response(cb_data, FIDO_ERROR_UNTRUSTED_FACET_ID, NULL); + _free_fido_asm_reg_in(reg_in); + return; + } + /* app id*/ + cb_data->uaf_req->header->app_id = strdup(cb_data->uaf_req->facet_id); + reg_in->app_id = strdup(cb_data->uaf_req->header->app_id); + } + else { + /* app id*/ + reg_in->app_id = strdup(cb_data->uaf_req->header->app_id); + } + + /* user name */ + if (uaf_reg_req->user_name != NULL) + reg_in->user_name = strdup(uaf_reg_req->user_name); + + _INFO(""); + + char *fc_json = _uaf_composer_compose_final_challenge(reg_in->app_id, uaf_reg_req->challenge, + uaf_req->facet_id, cb_data->uaf_req->channel_binding); + + if (fc_json == NULL) { + _ERR("Failed to compose final challenge"); + _send_process_response(cb_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + _free_fido_asm_reg_in(reg_in); + return; + } + + _INFO(""); + /* Final challenge */ + reg_in->final_challenge = fc_json; + + int auth_idx_int = -1; + sscanf(matched_auth->auth_index, "%d", &auth_idx_int); + + reg_in->attestation_type = matched_auth->att_type; + + _version_t *version = (_version_t *)calloc(1, sizeof(_version_t)); + version->major = _VERSION_MAJOR; + version->minor = _VERSION_MINOR; + + char *asm_req_json = NULL; + + cb_data->asm_in = reg_in; + + _INFO(""); + int ret = _uaf_composer_compose_asm_reg_request(version, auth_idx_int, reg_in, &asm_req_json); + if (ret == 0 && asm_req_json != NULL) + _asm_ipc_send(matched_auth->asm_id, + asm_req_json, _asm_response_reg_process, cb_data); + else + _send_process_response(cb_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + + SAFE_DELETE(asm_req_json); + SAFE_DELETE(version); + +} + +static GList * +__copy_convert_uaf_trans_list(GList *uaf_tr_list) +{ + RET_IF_FAIL(uaf_tr_list != NULL, NULL); + + GList *asm_tr_list = NULL; + + GList *uaf_tr_list_iter = g_list_first(uaf_tr_list); + while (uaf_tr_list_iter != NULL) { + + _auth_transaction_t *uaf_tr = (_auth_transaction_t*)(uaf_tr_list_iter->data); + + _fido_asm_transaction_t *asm_tr = calloc(1, sizeof(_fido_asm_transaction_t)); + + asm_tr->content = __dup_string(uaf_tr->content); + asm_tr->content_type = __dup_string(uaf_tr->content_type); + if (uaf_tr->display_charac != NULL) { + asm_tr->display_charac = calloc(1, sizeof(_fido_asm_display_png_characteristics_descriptor_t)); + + asm_tr->display_charac->bit_depth = uaf_tr->display_charac->bit_depth; + asm_tr->display_charac->color_type = uaf_tr->display_charac->color_type; + asm_tr->display_charac->compression = uaf_tr->display_charac->compression; + asm_tr->display_charac->filter = uaf_tr->display_charac->filter; + asm_tr->display_charac->height = uaf_tr->display_charac->height; + asm_tr->display_charac->interlace = uaf_tr->display_charac->interlace; + asm_tr->display_charac->width = uaf_tr->display_charac->width; + + if (uaf_tr->display_charac->plte != NULL) { + + GList *uaf_plte_iter = g_list_first(uaf_tr->display_charac->plte); + while (uaf_plte_iter != NULL) { + fido_rgb_pallette_entry_s *uaf_plte_entry = (fido_rgb_pallette_entry_s*)(uaf_plte_iter->data); + + fido_rgb_pallette_entry_s *asm_plte_entry = calloc(1, sizeof(fido_rgb_pallette_entry_s)); + asm_plte_entry->r = uaf_plte_entry->r; + asm_plte_entry->g = uaf_plte_entry->g; + asm_plte_entry->b = uaf_plte_entry->b; + + asm_tr->display_charac->plte = g_list_append(asm_tr->display_charac->plte, asm_plte_entry); + + uaf_plte_iter = uaf_plte_iter->next; + } + } + } + + asm_tr_list = g_list_append(asm_tr_list, asm_tr); + + uaf_tr_list_iter = uaf_tr_list_iter->next; + } + + if (asm_tr_list != NULL) { + asm_tr_list = g_list_first(asm_tr_list); + _INFO("Trans list = [%d]", g_list_length(asm_tr_list)); + } + return asm_tr_list; +} + +static GList* +__copy_string_list(GList *src) +{ + _INFO(""); + + RET_IF_FAIL(src != NULL, NULL); + + GList *dest = NULL; + + GList *iter = g_list_first(src); + while (iter != NULL) { + char *str = (char*)(iter->data); + dest = g_list_append(dest, strdup(str)); + + iter = iter->next; + _INFO(""); + } + + _INFO(""); + return dest; +} + +static void +__handle_auth(_process_cb_data_t *cb_data, _matched_auth_data_t *matched_auth) +{ + _INFO("__handle_auth"); + + _auth_request_t *uaf_auth_req = (_auth_request_t*)(cb_data->uaf_req->data); + + _fido_asm_auth_in_t *auth_asm_in = (_fido_asm_auth_in_t*)calloc(1, sizeof(_fido_asm_auth_in_t)); + + if (cb_data->uaf_req->header->app_id == NULL) { + + if (cb_data->uaf_req->facet_id == NULL) { + _ERR("Failed to get app id"); + _send_process_response(cb_data, FIDO_ERROR_PERMISSION_DENIED, NULL); + _free_fido_asm_auth_in(auth_asm_in); + return; + } + cb_data->uaf_req->header->app_id = strdup(cb_data->uaf_req->facet_id); + auth_asm_in->app_id = strdup(cb_data->uaf_req->facet_id); + } + else { + auth_asm_in->app_id = strdup(cb_data->uaf_req->header->app_id); + } + + char *fc_json = _uaf_composer_compose_final_challenge(cb_data->uaf_req->header->app_id, + uaf_auth_req->challenge, cb_data->uaf_req->facet_id, + cb_data->uaf_req->channel_binding); + if (fc_json == NULL) { + _ERR("Failed to compose final challenge"); + _send_process_response(cb_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + + _free_fido_asm_auth_in(auth_asm_in); + return; + } + + /*keyIDs*/ + auth_asm_in->key_ids = __copy_string_list(matched_auth->key_ids); + + /* Final challenge */ + auth_asm_in->final_challenge = fc_json; + + /*Transaction*/ + auth_asm_in->trans_list = __copy_convert_uaf_trans_list(uaf_auth_req->transaction_list); + + + cb_data->asm_in = auth_asm_in; + + char *asm_req_json = NULL; + _version_t *version = (_version_t *)calloc(1, sizeof(_version_t)); + version->major = _VERSION_MAJOR; + version->minor = _VERSION_MINOR; + + int auth_idx_int = -1; + sscanf(matched_auth->auth_index, "%d", &auth_idx_int); + if (auth_idx_int == -1) { + _ERR("ASM in data missing"); + _send_process_response(cb_data, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR, NULL); + + _free_fido_asm_auth_in(auth_asm_in); + SAFE_DELETE(version); + + return; + } + + int ret = _uaf_composer_compose_asm_auth_request(version, auth_idx_int, auth_asm_in, &asm_req_json); + if (ret == 0 && asm_req_json != NULL) { + _asm_ipc_send(matched_auth->asm_id, + asm_req_json, _asm_response_auth_process, cb_data); + } + else { + _send_process_response(cb_data, FIDO_ERROR_INVALID_PARAMETER, NULL); + } + + SAFE_DELETE(version); + SAFE_DELETE(asm_req_json); +} + +static void +_ui_response_callback(int error_code, _ui_auth_data_t *selected_auth_data, void *user_data) +{ + if (selected_auth_data == NULL) { + _ERR("User did not select any Authenticator"); + _send_process_response((_process_cb_data_t *)user_data, error_code, NULL); + free(selected_auth_data); + return; + } + + _INFO("User selected [%s] authenticator index", selected_auth_data->auth_index); + + _process_cb_data_t *cb_data = (_process_cb_data_t*)user_data; + + + _matched_auth_data_t *match_data = (_matched_auth_data_t*)calloc(1, sizeof(_matched_auth_data_t)); + match_data->att_type = selected_auth_data->att_type; + match_data->auth_index = selected_auth_data->auth_index; + match_data->asm_id = strdup(selected_auth_data->asm_id); + + if (cb_data->type == _PROCESS_TYPE_REG) + __handle_reg(cb_data, match_data); + + if (cb_data->type == _PROCESS_TYPE_AUTH) + __handle_auth(cb_data, match_data); + + _free_matched_auth_data(match_data); + +} + +static void +_asm_response_dereg_process(int error_code, const char *asm_response_json, void *user_data) +{ + _dereg_q_t *dereg_q = (_dereg_q_t*)(user_data); + _process_cb_data_t *cb_data = (_process_cb_data_t*)(dereg_q->cb_data); + + if (cb_data == NULL) + return; + + /*Process next dereg*/ + GQueue *q = (GQueue*) (dereg_q->dereg_asm_in_q); + if (g_queue_is_empty(q) == FALSE) + __process_dereg_queue(user_data); + else { + /*ASM does not return success/faliure for dereg*/ + _INFO("Ignoring ASM's response for dereg"); + _send_process_response((_process_cb_data_t *)cb_data, FIDO_ERROR_NONE, NULL); + + _INFO("Deleting dereg_asm_in_q"); + /*Elements were deleted during pop*/ + g_queue_free(dereg_q->dereg_asm_in_q); + dereg_q->dereg_asm_in_q = NULL; + _INFO("After Deleting dereg_asm_in_q"); + } + +} + +static void +__process_dereg_queue(_dereg_q_t *dereg_q) +{ + _INFO("__process_dereg_queue"); + + GQueue *q = dereg_q->dereg_asm_in_q; + if (q == NULL) + return; + + if (g_queue_is_empty(q) == true) { + _INFO("Deleting dereg_asm_in_q"); + g_queue_free(dereg_q->dereg_asm_in_q); + dereg_q->dereg_asm_in_q = NULL; + _INFO("After Deleting dereg_asm_in_q"); + return; + } + + _process_cb_data_t *cb_data = (_process_cb_data_t*)(dereg_q->cb_data); + _message_t *uaf_message = cb_data->uaf_req; + + _matched_auth_dereg_t *dereg_data = (_matched_auth_dereg_t*)(g_queue_pop_head(q)); + + char *asm_req_json = NULL; + + int auth_index_int = _INVALID_INT; + sscanf(dereg_data->auth_index, "%d", &auth_index_int); + + _INFO("Auth index for dereg req = [%d]", auth_index_int); + + int ret = _uaf_composer_compose_asm_dereg_request(uaf_message->header->version, auth_index_int, + dereg_data, &asm_req_json); + + /*TODO : ASM does not return anything for dereg, so do not wait for response, send back + * success always. + */ + if (ret == 0 && asm_req_json != NULL) { + _asm_ipc_send(dereg_data->asm_id, + asm_req_json, _asm_response_dereg_process, dereg_q); + } + else { + _send_process_response(cb_data, FIDO_ERROR_INVALID_PARAMETER, NULL); + } + + _free_matched_auth_dereg(dereg_data); + SAFE_DELETE(asm_req_json); + +} + +static GList* +__get_keyid_list_from_app_reg(GList *app_reg_list) +{ + _INFO("__get_keyid_list_from_app_reg"); + + RET_IF_FAIL(app_reg_list != NULL, NULL); + + GList *key_id_list = NULL; + + GList *app_reg_list_iter = g_list_first(app_reg_list); + while (app_reg_list_iter != NULL) { + + _asm_app_reg_t *app_reg = (_asm_app_reg_t*)(app_reg_list_iter->data); + if (app_reg != NULL) { + + if (app_reg->key_id_list != NULL) { + GList *key_id_list_iter = g_list_first(app_reg->key_id_list); + while (key_id_list_iter != NULL) { + char *key_id = (char*)(key_id_list_iter->data); + if (key_id != NULL) { + key_id_list = g_list_append(key_id_list, strdup(key_id)); + _INFO("[%s]", key_id); + } + + key_id_list_iter = key_id_list_iter->next; + } + } + } + + app_reg_list_iter = app_reg_list_iter->next; + } + + return key_id_list; +} + +static GList * +__get_auth_list_with_keyids(GList *available_authenticators) +{ + _INFO("__get_auth_list_with_keyids"); + + GList *available_authenticators_full = NULL; + + GList *avl_auth_iter = g_list_first(available_authenticators); + while (avl_auth_iter != NULL) { + + fido_authenticator_s *asm_auth = (fido_authenticator_s*)(avl_auth_iter->data); + if (asm_auth != NULL) { + char *get_reg_json = _uaf_composer_compose_get_registrations_request(asm_auth->auth_index); + char *get_reg_resp = _asm_ipc_send_sync(asm_auth->asm_id, get_reg_json); + + if (get_reg_resp != NULL) + _INFO("_asm_ipc_send_sync = [%s]", get_reg_resp); + + _asm_get_reg_out_t *get_reg_out = _uaf_parser_parser_asm_get_reg_response(get_reg_resp); + if (get_reg_out != NULL) { + asm_auth->key_ids = __get_keyid_list_from_app_reg(get_reg_out->app_reg_list); + asm_auth->key_ids = g_list_first(asm_auth->key_ids); + _INFO(" asm_auth->key_ids count = [%d]", g_list_length(asm_auth->key_ids)); + } + available_authenticators_full = g_list_append(available_authenticators_full, asm_auth); + + SAFE_DELETE(get_reg_json); + SAFE_DELETE(get_reg_resp); + _free_asm_get_reg_out(get_reg_out); + + } + avl_auth_iter = avl_auth_iter->next; + } + + return available_authenticators_full; +} + +static void +__free_matched_dereg_auth_data_list_item(gpointer data) +{ + RET_IF_FAIL_VOID(data != NULL); + + _free_matched_auth_dereg((_matched_auth_dereg_t*)data); +} + +static void +_discover_response_cb_for_process(int tz_error_code, int error_code, GList *available_authenticators, void *user_data) +{ + _INFO("_discover_response_cb_for_process [%p]", user_data); + + _process_cb_data_t *cb_data = (_process_cb_data_t*)user_data; + + if (tz_error_code != FIDO_ERROR_NONE) { + _ERR("Failed to get available authenticator info [%d]", tz_error_code); + _send_process_response(cb_data, FIDO_ERROR_NOT_SUPPORTED, NULL); + return; + } + + if (available_authenticators == NULL) { + _ERR("No supported authenticators found"); + _send_process_response(cb_data, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR, NULL); + return; + } + + _INFO("cb_data->type = [%d]", cb_data->type); + + GList *available_authenticators_full = g_list_first(available_authenticators); + + if (cb_data->type == _PROCESS_TYPE_CHECK_POLICY) { + + _INFO("_PROCESS_TYPE_CHECK_POLICY"); + + if (cb_data->uaf_req->header->operation != NULL) + _INFO("operation = [%s]", cb_data->uaf_req->header->operation); + else + _ERR("operation = [NULL]"); + + if ((strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_REG) == 0) + || ((strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_AUTH) == 0))) { + + _policy_t *policy = NULL; + + if (strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_REG) == 0) { + _reg_request_t *uaf_reg_req = (_reg_request_t *)(cb_data->uaf_req->data); + policy = uaf_reg_req->policy; + _INFO("_PROCESS_TYPE_CHECK_POLICY for reg"); + } + else if (strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_AUTH) == 0) { + _auth_request_t *uaf_auth_req = (_auth_request_t *)(cb_data->uaf_req->data); + policy = uaf_auth_req->policy; + _INFO("_PROCESS_TYPE_CHECK_POLICY for auth"); + } + + if (policy->is_keyid_present == true) { + /*Available authenticators' keyIDs can be fetched via GetRegistrations ASM op*/ + _INFO("Need to call GetRegistrations to match policy"); + GList *avl_auth_list_full_temp = __get_auth_list_with_keyids(available_authenticators); + if (avl_auth_list_full_temp != NULL) { + g_list_free(available_authenticators_full); + + available_authenticators_full = g_list_first(avl_auth_list_full_temp); + } + + } + GList *allowed_auth_list = _policy_checker_get_matched_auth_list(policy, available_authenticators_full); + g_list_free_full(available_authenticators_full, _free_asm_auth_list); + + if ((allowed_auth_list != NULL) && g_list_length(allowed_auth_list) > 0) { + + _send_process_response(cb_data, FIDO_ERROR_NONE, NULL); + } + else { + _send_process_response(cb_data, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR, NULL); + } + + if (allowed_auth_list != NULL) + g_list_free_full(allowed_auth_list, _free_matched_auth_data); + + } + else if (strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_DE_REG) == 0) { + + _dereg_request_t *dereg_req = (_dereg_request_t*)(cb_data->uaf_req->data); + + /* _matched_auth_dereg_t list*/ + if (cb_data->uaf_req->header->app_id == NULL) + cb_data->uaf_req->header->app_id = strdup(cb_data->uaf_req->facet_id); + + GList *matched_auth_list = _policy_checker_get_matched_auth_list_dereg(cb_data->uaf_req->header->app_id, dereg_req->auth_info_list, + available_authenticators_full); + g_list_free_full(available_authenticators_full, _free_asm_auth_list); + + if ((matched_auth_list != NULL) && g_list_length(matched_auth_list) > 0) { + + _send_process_response(cb_data, FIDO_ERROR_NONE, NULL); + } + else { + _send_process_response(cb_data, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR, NULL); + } + + if (matched_auth_list != NULL) + g_list_free_full(matched_auth_list, __free_matched_dereg_auth_data_list_item); + + } + + return; + } + if (cb_data->type == _PROCESS_TYPE_DEREG) { + + + _dereg_request_t *dereg_req = (_dereg_request_t*)(cb_data->uaf_req->data); + + if (cb_data->uaf_req->header->app_id == NULL) + cb_data->uaf_req->header->app_id = strdup(cb_data->uaf_req->facet_id); + + /* _matched_auth_dereg_t list*/ + GList *matched_auth_list = _policy_checker_get_matched_auth_list_dereg(cb_data->uaf_req->header->app_id, dereg_req->auth_info_list, + available_authenticators_full); + + g_list_free_full(available_authenticators_full, _free_asm_auth_list); + + if (matched_auth_list == NULL){ + _ERR("No supported authenticators found"); + _send_process_response(cb_data, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR, NULL); + return; + } + + _dereg_q_t *dereg_q = (_dereg_q_t*) calloc(1, sizeof(_dereg_q_t)); + + GList *matched_auth_list_iter = g_list_first(matched_auth_list); + while (matched_auth_list_iter != NULL) { + _matched_auth_dereg_t *dereg_auth_matched = (_matched_auth_dereg_t*) (matched_auth_list_iter->data); + + if (dereg_auth_matched != NULL) { + GQueue *q = dereg_q->dereg_asm_in_q; + + if (q == NULL) + dereg_q->dereg_asm_in_q = g_queue_new(); + + g_queue_push_head(dereg_q->dereg_asm_in_q, dereg_auth_matched); + } + matched_auth_list_iter = matched_auth_list_iter->next; + } + + /*The elements will be deleted while freeing dereg_q->dereg_asm_in_q*/ + g_list_free(matched_auth_list); + + dereg_q->cb_data = cb_data; + + __process_dereg_queue(dereg_q); + + return; + } + + _policy_t *policy = NULL; + + if (cb_data->type == _PROCESS_TYPE_REG) { + _reg_request_t *uaf_reg_req = (_reg_request_t *)(cb_data->uaf_req->data); + policy = uaf_reg_req->policy; + } + else if (cb_data->type == _PROCESS_TYPE_AUTH) { + _auth_request_t *uaf_auth_req = (_auth_request_t *)(cb_data->uaf_req->data); + policy = uaf_auth_req->policy; + } + else { + _send_process_response(cb_data, FIDO_ERROR_UNKNOWN, NULL); + return; + } + + if (policy->is_keyid_present == true) { + /*Available authenticators' keyIDs can be fetched via GetRegistrations ASM op*/ + _INFO("Need to call GetRegistrations to match policy"); + GList *avl_auth_list_full_temp = __get_auth_list_with_keyids(available_authenticators); + if (avl_auth_list_full_temp != NULL) { + g_list_free(available_authenticators_full); + available_authenticators_full = g_list_first(avl_auth_list_full_temp); + } + + } + + GList *allowed_auth_list = _policy_checker_get_matched_auth_list(policy, available_authenticators_full); + g_list_free_full(available_authenticators_full, _free_asm_auth_list); + + if (allowed_auth_list == NULL){ + _ERR("No supported authenticators found"); + _send_process_response(cb_data, FIDO_ERROR_NO_SUITABLE_AUTHENTICATOR, NULL); + + return; + } + + _INFO(""); + allowed_auth_list = g_list_first(allowed_auth_list); + + if (g_list_length(allowed_auth_list) > 1) { + _INFO(""); + + GList *ui_data_list = NULL; + + GList *allowed_auth_list_iter = allowed_auth_list; + while (allowed_auth_list_iter != NULL) { + _matched_auth_data_t *match_data = (_matched_auth_data_t *)(allowed_auth_list_iter->data); + + if (match_data != NULL) { + + _ui_auth_data_t *ui_data = (_ui_auth_data_t*) calloc(1, sizeof(_ui_auth_data_t)); + if (match_data->asm_id != NULL) + ui_data->asm_id = strdup(match_data->asm_id); + else + _ERR("No ASM id found to send to UI!!"); + + ui_data->auth_index = strdup(match_data->auth_index); + ui_data->att_type = match_data->att_type; + + ui_data->label = strdup(match_data->label); + + ui_data_list = g_list_append(ui_data_list, ui_data); + + allowed_auth_list_iter = allowed_auth_list_iter->next; + } + } + + int ret = _auth_ui_selector_send(ui_data_list, _ui_response_callback, cb_data); + if (ret != 0) { + _ERR("Failed to invoke selector UI"); + _send_process_response(cb_data, FIDO_ERROR_NOT_SUPPORTED, NULL); + if (allowed_auth_list != NULL) + g_list_free_full(allowed_auth_list, _free_matched_auth_data); + return; + } + } + else { + _INFO(""); + GList *allowed_auth_list_iter = allowed_auth_list; + _matched_auth_data_t *match_data = (_matched_auth_data_t *)(allowed_auth_list_iter->data); + + if (cb_data->type == _PROCESS_TYPE_REG) + __handle_reg(cb_data, match_data); + + else if (cb_data->type == _PROCESS_TYPE_AUTH) + __handle_auth(cb_data, match_data); + + } + if (allowed_auth_list != NULL) + g_list_free_full(allowed_auth_list, _free_matched_auth_data); + +} + +static int +_handle_process_message(_process_cb_data_t *cb_data) +{ + return __fido_uaf_discover_internal(_discover_response_cb_for_process, cb_data); +} + +static void +__facet_id_cb(int err, const char *facet_id, void *user_data) +{ + _INFO("__facet_id_cb"); + if (facet_id != NULL) + _INFO("[%s]", facet_id); + + _process_cb_data_t *cb_data = (_process_cb_data_t*)user_data; + + if (err != FIDO_ERROR_NONE || facet_id == NULL) { + _send_process_response(cb_data, err, NULL); + return; + } + + cb_data->uaf_req->facet_id = strdup(facet_id); + + int error_code = FIDO_ERROR_NONE; + + if (cb_data->type != _PROCESS_TYPE_CHECK_POLICY) { + + /** + * 1. Extract embedded policy to find the suitable authenticator(s) + * 2. Show UI to let user select one, if (1) gives multiple result. + * 3. Compose ASMRequest in json format + * 4. Send the same to asm + * 5. Send the ASMResponse to application. + */ + + if (strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_REG) == 0) + cb_data->type = _PROCESS_TYPE_REG; + + else if (strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_AUTH) == 0) + cb_data->type = _PROCESS_TYPE_AUTH; + + else if (strcmp(cb_data->uaf_req->header->operation, _UAF_OPERATION_NAME_KEY_DE_REG) == 0) + cb_data->type = _PROCESS_TYPE_DEREG; + + else { + _send_process_response(cb_data, FIDO_ERROR_INVALID_PARAMETER, NULL); + return; + } + } + + error_code = _handle_process_message(cb_data); + + if (error_code != FIDO_ERROR_NONE) { + _send_process_response(cb_data, error_code, NULL); + } +} + +gboolean +_dbus_on_fido_init(Fido *object, GDBusMethodInvocation *invocation) +{ + fido_complete_fido_uaf_init(object, invocation, FIDO_ERROR_NONE); + + return true; +} + +gboolean +_dbus_on_fido_deinit(Fido *object, GDBusMethodInvocation *invocation) +{ + if (is_allowed_to_call(invocation, _FIDO_CLIENT_PRIVILEGE) == false) { + fido_complete_fido_uaf_deinit(object, invocation, FIDO_ERROR_PERMISSION_DENIED); + } + else { + //_auth_ui_selector_deinit(); + fido_complete_fido_uaf_deinit(object, invocation, FIDO_ERROR_NONE); + } + + return true; +} + +gboolean +_dbus_on_fido_discover(Fido *object, GDBusMethodInvocation *invocation) +{ + _INFO("_dbus_on_fido_discover"); + if (is_allowed_to_call(invocation, _FIDO_CLIENT_PRIVILEGE) == false) { + + __send_discover_response(object, invocation, FIDO_ERROR_PERMISSION_DENIED, + NULL, 0); + return true; + } + + _dbus_info_t *dbus_info = (_dbus_info_t *)calloc(1, sizeof(_dbus_info_t)); + dbus_info->dbus_obj = object; + dbus_info->invocation = invocation; + + int ret = _asm_plugin_mgr_discover_all(_asm_get_info_cb, dbus_info); + if (ret != FIDO_ERROR_NONE) { + + _ERR("_asm_ipc_send failed = [%d]", ret); + __send_discover_response(dbus_info->dbus_obj, dbus_info->invocation, FIDO_ERROR_NOT_SUPPORTED, + NULL, 0); + + SAFE_DELETE(dbus_info); + + } + + return true; +} + +gboolean +_dbus_handle_process_or_check_policy(Fido *object, GDBusMethodInvocation *invocation, + const gchar *uaf_request_json, const gchar *channel_binding, + _process_type_t type) +{ + + _INFO("_dbus_handle_process_or_check_policy"); + + _process_cb_data_t *cb_data = (_process_cb_data_t*) calloc(1, sizeof(_process_cb_data_t)); + _dbus_info_t *dbus_info = (_dbus_info_t *)calloc(1, sizeof(_dbus_info_t)); + dbus_info->dbus_obj = object; + dbus_info->invocation = invocation; + cb_data->dbus_info = dbus_info; + cb_data->type = type; + + if (is_allowed_to_call(invocation, _FIDO_CLIENT_PRIVILEGE) == false) { + _send_process_response(cb_data, FIDO_ERROR_PERMISSION_DENIED, NULL); + return true; + } + + if (uaf_request_json == NULL) { + _send_process_response(cb_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + return true; + } + + _INFO("%s", uaf_request_json); + + _message_t *uaf_message = _uaf_parser_parse_message(uaf_request_json, channel_binding); + if (uaf_message == NULL) { + _send_process_response(cb_data, FIDO_ERROR_PROTOCOL_ERROR, NULL); + return true; + } + + + cb_data->uaf_req = uaf_message; + + + int ret = _verify_and_get_facet_id(uaf_message->header->app_id, invocation, __facet_id_cb, cb_data); + if (ret != FIDO_ERROR_NONE) { + _send_process_response(cb_data, FIDO_ERROR_UNTRUSTED_FACET_ID, NULL); + return true; + } + + return true; +} + +gboolean +_dbus_on_fido_uaf_is_supported(Fido *object, GDBusMethodInvocation *invocation, + const gchar *uaf_request_json) +{ + _INFO("_dbus_on_fido_uaf_is_supported"); + + return _dbus_handle_process_or_check_policy(object, invocation, uaf_request_json, NULL, + _PROCESS_TYPE_CHECK_POLICY); +} + +gboolean +_dbus_on_fido_process_operation(Fido *object, GDBusMethodInvocation *invocation, + const gchar *uaf_request_json, const gchar* channel_binding_json) +{ + _INFO("_dbus_on_fido_process_operation"); + + return _dbus_handle_process_or_check_policy(object, invocation, uaf_request_json, + channel_binding_json, _PROCESS_TYPE_MIN); +} + +/*gboolean +_dbus_on_fido_uaf_notify_result(Fido *object, GDBusMethodInvocation *invocation, const gchar *arg_cookie, gint arg_respose_code, + const gchar *uaf_response_json) +{ + fido_complete_fido_uaf_notify_result(object, invocation, 0, 0); + return true; +}*/ + +static void +on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + dlog_print(DLOG_INFO, "FIDO", "on_bus_acquired"); + + _INFO("on_bus_acquired [%s]", name); + + GDBusInterfaceSkeleton* interface = NULL; + fido_dbus_obj = fido_skeleton_new(); + if (fido_dbus_obj == NULL) { + _ERR("fido_dbus_obj NULL!!"); + return; + } + + dlog_print(DLOG_INFO, "FIDO", "G_DBUS_INTERFACE_SKELETON"); + + interface = G_DBUS_INTERFACE_SKELETON(fido_dbus_obj); + if (!g_dbus_interface_skeleton_export(interface, connection, _FIDO_SERVICE_DBUS_PATH, NULL)) { + _ERR("export failed!!"); + return; + } + + dlog_print(DLOG_INFO, "FIDO", "g_signal_connect"); + + _INFO("connecting fido signals start"); + + g_signal_connect(fido_dbus_obj, "handle_fido_uaf_init", + G_CALLBACK(_dbus_on_fido_init), NULL); + + g_signal_connect(fido_dbus_obj, "handle_fido_uaf_deinit", + G_CALLBACK(_dbus_on_fido_deinit), NULL); + + g_signal_connect(fido_dbus_obj, "handle_fido_uaf_discover", + G_CALLBACK(_dbus_on_fido_discover), NULL); + + g_signal_connect(fido_dbus_obj, "handle_fido_uaf_check_policy", + G_CALLBACK(_dbus_on_fido_uaf_is_supported), NULL); + + g_signal_connect(fido_dbus_obj, "handle_fido_uaf_process_operation", + G_CALLBACK(_dbus_on_fido_process_operation), NULL); + +// g_signal_connect(fido_dbus_obj, "handle_fido_uaf_notify_result", +// G_CALLBACK(_dbus_on_fido_uaf_notify_result), NULL); + + g_signal_connect(fido_dbus_obj, "handle_ui_response", + G_CALLBACK(_auth_ui_selector_on_ui_response), NULL); + + if (_asm_plugin_mgr_init() != FIDO_ERROR_NONE) { + _ERR("Falied to init ASM plugin manager"); + dlog_print(DLOG_INFO, "FIDO", "_asm_plugin_mgr_init failed"); + exit(1); + } + + +} + +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + _INFO("on_name_acquired"); + +} + +static void +on_name_lost (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + _INFO("on_name_lost"); + _asm_plugin_mgr_destroy(); + exit (1); +} + +static bool +__initialize_dbus(void) +{ + _INFO("__initialize_dbus Enter"); + + owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + _FIDO_DBUS_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, + NULL); + + _INFO("owner_id=[%d]", owner_id); + + if(owner_id == 0) { + _INFO("gdbus own failed!!"); + return false; + } + + _INFO("g_bus_own_name SUCCESS"); + return true; +} + +static void +__initialize(void) +{ +#if !GLIB_CHECK_VERSION(2,35,0) + g_type_init(); +#endif + + if (__initialize_dbus() == false) { + _ERR("DBUS Initialization Failed"); + exit(1); + } +} + +int +main(void) +{ + GMainLoop *mainloop = NULL; + + dlog_print(DLOG_INFO, "FIDO", "start"); + + _INFO("Starting FIDO SVC"); + + mainloop = g_main_loop_new(NULL, FALSE); + + __initialize(); + + g_main_loop_run(mainloop); + + _INFO("Ending FIDO SVC"); + return 0; +} diff --git a/server/fido_uaf_policy_checker.c b/server/fido_uaf_policy_checker.c new file mode 100644 index 0000000..b077abe --- /dev/null +++ b/server/fido_uaf_policy_checker.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include + +#include "fido_keys.h" +#include "fido_logs.h" +#include "fido_uaf_policy_checker.h" +#include "fido_json_handler.h" + +//static _fido_asm_proxy_t* +//__dup_asm_proxy(const _fido_asm_proxy_t *src) +//{ +// _fido_asm_proxy_t *dest = calloc(1, sizeof(_fido_asm_proxy_t)); +// dest->bin_path = strdup(src->bin_path); +// dest->dbus_info = strdup(src->dbus_info); +// dest->dbus_interface_name = strdup(src->dbus_interface_name); +// dest->dbus_method_name = strdup(src->dbus_method_name); +// dest->dbus_obj_path = strdup(src->dbus_obj_path); +// dest->vendor = strdup(src->vendor); + +// dest->dbus_proxy = src->dbus_proxy; + +// return dest; +//} + +static gint +_int_cmp(gconstpointer a, gconstpointer b) +{ + int int1 = GPOINTER_TO_INT(a); + int int2 = GPOINTER_TO_INT(b); + return (int1 - int2); +} + +bool +_policy_checker_is_matched(_match_criteria_t *match_criteria, fido_authenticator_s *auth_info) +{ + _INFO("_policy_checker_is_matched"); + + /* -1 means the int value is not present, so we should ignore that. */ + + /* 1. If any AAID is mentioned in match_criteria, then atleast one AAID should match */ + GList *aaid_list = match_criteria->aaid_list; + + if (aaid_list && + (g_list_length(aaid_list)) && + (auth_info->aaid) && + (strlen(auth_info->aaid) > 0)) { + aaid_list = g_list_first(aaid_list); + if (g_list_find_custom(aaid_list, auth_info->aaid, (GCompareFunc)strcmp) == NULL) { + _ERR("AAID match failed"); + return false; + } + } + + + /* 2. If any Vendor ID is mentioned in match_criteria, then atleast one Vendor ID should match */ + GList *vendor_list = match_criteria->vendor_list; + + if (vendor_list && auth_info->aaid) { + char *auth_aaid = strdup(auth_info->aaid); + char *auth_vendor = strtok(auth_aaid, "#"); + + if (vendor_list && + (g_list_length(vendor_list)) && + auth_vendor && + (strlen(auth_vendor) > 0)) { + vendor_list = g_list_first(vendor_list); + if (g_list_find_custom(vendor_list, auth_vendor, (GCompareFunc)strcmp) == NULL) { + _ERR("Vendor ID match failed"); + + SAFE_DELETE(auth_aaid); + return false; + } + } + SAFE_DELETE(auth_aaid); + } + + _INFO("keyid matching"); + + /* 3. If any Key ID is mentioned in match_criteria, then atleast one Key ID should match */ + GList *key_id_list = match_criteria->key_id_list; + + if (key_id_list != NULL) { + + if (auth_info->key_ids == NULL) { + _ERR("keyID match failed"); + return false; + } + + GList *auth_key_ids = auth_info->key_ids; + + GList *common_key_id_list = NULL; + + key_id_list = g_list_first(key_id_list); + auth_key_ids = g_list_first(auth_key_ids); + + _INFO("match_criteria keyid count = [%d]", g_list_length(key_id_list)); + _INFO("auth info keyid count = [%d]", g_list_length(auth_key_ids)); + + GList *key_id_iter = g_list_first(key_id_list); + while (key_id_iter != NULL) { + char *key_id = (char*) (key_id_iter->data); + if (key_id) { + if (g_list_find_custom(auth_key_ids, key_id, (GCompareFunc)strcmp) != NULL) { + _INFO("keyid matched [%s]", key_id); + common_key_id_list = g_list_append(common_key_id_list, strdup(key_id)); + } + } + key_id_iter = key_id_iter->next; + } + + if (common_key_id_list == NULL) { + _ERR("keyID match failed"); + return false; + } + + common_key_id_list = g_list_first(common_key_id_list); + + /*Set common keyIds in match*/ + g_list_free_full(match_criteria->key_id_list, free); + match_criteria->key_id_list = common_key_id_list; + + _INFO("keyID matched count [%d]", g_list_length(match_criteria->key_id_list)); + + } + + _INFO("User verification matching"); + + /* 4. User verification match */ + if (match_criteria->user_verification != -1) { + if ((match_criteria->user_verification == auth_info->user_verification) + || + ( + ((auth_info->user_verification & _USER_VER_METHOD_ALL) == 0) + && + ((match_criteria->user_verification & _USER_VER_METHOD_ALL) == 0) + && + ((auth_info->user_verification & match_criteria->user_verification) != 0) + ) + ) + _INFO("User verification match passed"); + else { + _ERR("User verification match failed"); + return false; + } + } + + /* 5. Key protection field bit matching */ + if ((match_criteria->key_protection != -1) && auth_info->key_protection) { + if (((match_criteria->key_protection) && (auth_info->key_protection)) == 0) { + _ERR("Key protection match failed"); + return false; + } + } + + /* 6. Matcher Protection field bit matching */ + if ((match_criteria->matcher_protection != -1) && auth_info->matcher_protection) { + if (((match_criteria->matcher_protection) && (auth_info->matcher_protection)) == 0) { + _ERR("Matcher protection match failed"); + return false; + } + } + + /* 7. Attachment hint field bit matching */ + if ((match_criteria->attachement_hint != -1) && auth_info->attachment_hint) { + if (((match_criteria->attachement_hint) && (auth_info->attachment_hint)) == 0) { + _ERR("Attachment hint match failed"); + return false; + } + } + + /* 8. TC Display field bit matching */ + if ((match_criteria->tc_display != -1) && auth_info->tc_display) { + if (((match_criteria->tc_display) && (auth_info->tc_display)) == 0) { + _ERR("Attachment hint match failed"); + return false; + } + } + + /* 9. If any algo is mentioned in match_criteria, then atleast one algo should match */ + GList *match_algo_list = match_criteria->auth_algo_list; + if (match_algo_list && (g_list_length(match_algo_list)) + && (auth_info->authentication_algorithm)) { + match_algo_list = g_list_first(match_algo_list); + if (g_list_find_custom(match_algo_list, GINT_TO_POINTER(auth_info->authentication_algorithm), (GCompareFunc)_int_cmp) == NULL) { + _ERR("Algorithm match failed"); + return false; + } + } + + /* 10. If any assertion scheme is mentioned in match_criteria, then atleast one assertion scheme should match */ + GList *assertion_list = match_criteria->assertion_scheme_list; + if (assertion_list && (g_list_length(assertion_list)) + && (auth_info->assertion_scheme) && (strlen(auth_info->assertion_scheme) > 0)) { + assertion_list = g_list_first(assertion_list); + if (g_list_find_custom(assertion_list, auth_info->assertion_scheme, (GCompareFunc)strcmp) == NULL) + { + _ERR("Assertion scheme match failed"); + return false; + } + } + + /* 11. If any attestation type is mentioned in match_criteria, then atleast one attestation type should match */ + GList *attestation_type_list = match_criteria->attestation_type_list; + if (attestation_type_list && (g_list_length(attestation_type_list)) + && (auth_info->attestation_types)) { + attestation_type_list = g_list_first(attestation_type_list); + if (g_list_find_custom(attestation_type_list, GINT_TO_POINTER(auth_info->attestation_types), (GCompareFunc)_int_cmp) == NULL) { + _ERR("Attestation type match failed"); + return false; + } + } + + /* TODO : 12. Auth version */ + + /* TODO : 13. Extension */ + + _INFO("_policy_checker_is_matched true"); + + return true; +} + +int +_get_attestation_type(_match_criteria_t *match_criteria, fido_authenticator_s *auth_info) +{ + _INFO("_get_attestation_type"); + + if (match_criteria && match_criteria->attestation_type_list) { + + GList *match_att_list_iter = g_list_first(match_criteria->attestation_type_list); + while (match_att_list_iter != NULL) { + + int match_att_type = GPOINTER_TO_INT(match_att_list_iter->data); + + if (auth_info && auth_info->attestation_types) { + + GList *auth_att_list_iter = g_list_first(auth_info->attestation_types); + while (auth_att_list_iter != NULL) { + + int auth_att_type = GPOINTER_TO_INT(auth_att_list_iter->data); + + if (match_att_type == auth_att_type) { + _INFO("_get_attestation_type end [%d]", match_att_type); + return match_att_type; + } + } + } + match_att_list_iter = match_att_list_iter->data; + } + } + else { + if (auth_info->attestation_types != NULL) { + GList *att_type_iter = g_list_first(auth_info->attestation_types); + + /*Returning first attestation type in case policy does not mandate any*/ + while (att_type_iter != NULL) { + int auth_att_type = GPOINTER_TO_INT(att_type_iter->data); + _INFO("Returning first attestation type in case policy does not mandate any [%d]", auth_att_type); + return auth_att_type; + } + } + } + + _ERR("_get_attestation_type end"); + return -1; +} + +static char * +__get_verification_method_string(unsigned long int ver_method) +{ + char *ver_str = calloc(1, 128); + + switch (ver_method) { + + case _USER_VER_METHOD_PRESENCE: + snprintf(ver_str, 127, "%s", "Presence Authenticator"); + break; + + case _USER_VER_METHOD_FINGERPRINT: + snprintf(ver_str, 127, "%s", "Fingerprint Authenticator"); + break; + + case _USER_VER_METHOD_PASSCODE: + snprintf(ver_str, 127, "%s", "Passcode Authenticator"); + break; + + case _USER_VER_METHOD_VOICE_PRINT: + snprintf(ver_str, 127, "%s", "Voice Print Authenticator"); + break; + + case _USER_VER_METHOD_FACE_PRINT: + snprintf(ver_str, 127, "%s", "Face Print Authenticator"); + break; + + case _USER_VER_METHOD_LOCATION: + snprintf(ver_str, 127, "%s", "Location Authenticator"); + break; + + case _USER_VER_METHOD_EYE_PRINT: + snprintf(ver_str, 127, "%s", "Eye Print Authenticator"); + break; + + case _USER_VER_METHOD_PATTERN: + snprintf(ver_str, 127, "%s", "Pattern Authenticator"); + break; + + case _USER_VER_METHOD_HAND_PRINT: + snprintf(ver_str, 127, "%s", "Hand Print Authenticator"); + break; + +// case _USER_VER_METHOD_NONE: +// snprintf(ver_str, "%s", ""); +// break; + + case _USER_VER_METHOD_ALL: + snprintf(ver_str, 127, "%s", "All Authenticator"); + break; + + default: + snprintf(ver_str, 127, "%s", "Other Type"); + break; + } + + return ver_str; +} + +static GList* +__copy_string_list(GList *src) +{ + RET_IF_FAIL(src != NULL, NULL); + + GList *dest = NULL; + + GList *iter = g_list_first(src); + while (iter != NULL) { + char *str = (char*)(iter->data); + dest = g_list_append(dest, strdup(str)); + + iter = iter->next; + } + + return dest; +} + +/* Returns _matched_auth_data_t list*/ +GList * +_policy_checker_get_matched_auth_list(_policy_t *policy, GList *auth_list) +{ + _INFO("_policy_checker_get_matched_auth_list"); + + if (policy == NULL) + _INFO("policy is NULL"); + + if (auth_list == NULL) + _INFO("auth_list is NULL"); + + RET_IF_FAIL(policy != NULL, NULL); + RET_IF_FAIL(auth_list != NULL, NULL); + + // _match_criteria_t *match_criteria_or = NULL; + GList *allowed_list = NULL; + GList *disallowed_list = policy->disallowed_list; + GList *accepted_list = policy->accepted_list; + + if (accepted_list != NULL) + _INFO("accepted_list count = [%d]", g_list_length(accepted_list)); + + if (disallowed_list != NULL) + _INFO("allowed_list count = [%d]", g_list_length(disallowed_list)); + + GList *accepted_list_iter = g_list_first(accepted_list); + while (accepted_list_iter != NULL) { + + GList *accepted_list_internal = (GList *) accepted_list_iter->data; + GList *accepted_list_internal_iter = g_list_first(accepted_list_internal); + while (accepted_list_internal_iter != NULL) { + _match_criteria_t *match_info = (_match_criteria_t *) accepted_list_internal_iter->data; + + GList *auth_list_iter = g_list_first(auth_list); + while (auth_list_iter != NULL) { + fido_authenticator_s *authenticator = (fido_authenticator_s*) (auth_list_iter->data); + + if (_policy_checker_is_matched(match_info, authenticator)) { + _INFO("[%s] is matched from allowed list", authenticator->aaid); + + /*Disallowed list can be NULL, which means put all which are matching with accepted list*/ + + if (disallowed_list != NULL) { + + GList *disallowed_list_iter = g_list_first(disallowed_list); + while (disallowed_list_iter != NULL) { + _match_criteria_t *disallowed_match_info = (_match_criteria_t *) disallowed_list_iter->data; + + if (!_policy_checker_is_matched(disallowed_match_info, authenticator)) { + _INFO("[%s] is not in disallowed list", authenticator->aaid); + _matched_auth_data_t *matched_auth_data = (_matched_auth_data_t*) calloc(1, sizeof(_matched_auth_data_t)); + RET_IF_FAIL(matched_auth_data, NULL); + + /*TODO : ASM must send auth index*/ + if (authenticator->auth_index != NULL) + matched_auth_data->auth_index = strdup(authenticator->auth_index); + else + _ERR("auth index missing"); + + matched_auth_data->att_type = _get_attestation_type(match_info, authenticator); + + if (authenticator->title != NULL) + matched_auth_data->label = strdup(authenticator->title); + else { + _ERR("title missing, putting ver method"); + /*If label is null, set verification method name instead*/ + matched_auth_data->label = __get_verification_method_string(authenticator->user_verification); + } + + + if (authenticator->asm_id != NULL) + matched_auth_data->asm_id = strdup(authenticator->asm_id); + else + _ERR("Authenticator does not have any ASM ID!!"); + + matched_auth_data->key_ids = __copy_string_list(match_info->key_id_list); + + allowed_list = g_list_append(allowed_list, matched_auth_data); + } + disallowed_list_iter = disallowed_list_iter->next; + } + } + else { + _INFO("[%s] adding since no disallowed list", authenticator->aaid); + _matched_auth_data_t *matched_auth_data = (_matched_auth_data_t*) calloc(1, sizeof(_matched_auth_data_t)); + RET_IF_FAIL(matched_auth_data, NULL); + + matched_auth_data->auth_index = strdup(authenticator->auth_index); + matched_auth_data->att_type = _get_attestation_type(match_info, authenticator); + if (authenticator->title != NULL) + matched_auth_data->label = strdup(authenticator->title); + else { + _ERR("title missing, putting ver method"); + /*If label is null, set verification method name instead*/ + matched_auth_data->label = __get_verification_method_string(authenticator->user_verification); + } + + if (authenticator->asm_id != NULL) + matched_auth_data->asm_id = strdup(authenticator->asm_id); + else + _ERR("Authenticator does not have any ASM ID!!"); + + matched_auth_data->key_ids = __copy_string_list(match_info->key_id_list); + + allowed_list = g_list_append(allowed_list, matched_auth_data); + } + } + auth_list_iter = auth_list_iter->next; + } + accepted_list_internal_iter = accepted_list_internal_iter->next; + } + accepted_list_iter = accepted_list_iter->next; + } + + if (allowed_list != NULL) + allowed_list = g_list_first(allowed_list); + + return allowed_list; +} + +/* Returns _matched_auth_dereg_t list */ +GList* +_policy_checker_get_matched_auth_list_dereg(const char *app_id, GList *input_auth_list, GList *available_auth_list) +{ + _INFO(""); + + RET_IF_FAIL(app_id, NULL); + RET_IF_FAIL(input_auth_list, NULL); + RET_IF_FAIL(available_auth_list, NULL); + + _INFO(""); + + GList *matched_auth_dereg_list = NULL; + + GList *input_auth_list_iter = g_list_first(input_auth_list); + while (input_auth_list_iter != NULL) { + _dereg_auth_info_t *dereg_auth_info = (_dereg_auth_info_t*) (input_auth_list_iter->data); + + GList *available_auth_list_iter = g_list_first(available_auth_list); + while (available_auth_list_iter != NULL) { + fido_authenticator_s *authenticator = (fido_authenticator_s*) (available_auth_list_iter->data); + + if (dereg_auth_info->aaid != NULL) + _INFO("Input AAID = [%s]", dereg_auth_info->aaid); + + if (authenticator->aaid != NULL) + _INFO("Authenticator AAID = [%s]", authenticator->aaid); + + if (dereg_auth_info->aaid && authenticator->aaid && !strcmp(dereg_auth_info->aaid, authenticator->aaid)) { + _matched_auth_dereg_t *matched_auth_dereg = (_matched_auth_dereg_t*) calloc(1, sizeof(_matched_auth_dereg_t)); + RET_IF_FAIL(matched_auth_dereg, NULL); + + matched_auth_dereg->auth_index = strdup(authenticator->auth_index); + matched_auth_dereg->app_id = strdup(app_id); + matched_auth_dereg->key_id = strdup(dereg_auth_info->key_id); + if (authenticator->asm_id != NULL) + matched_auth_dereg->asm_id = strdup(authenticator->asm_id); + else + _ERR("Authenticator does not have any ASM ID!!"); + + _INFO(""); + matched_auth_dereg_list = g_list_append(matched_auth_dereg_list, matched_auth_dereg); + } + available_auth_list_iter = available_auth_list_iter->next; + } + input_auth_list_iter = input_auth_list_iter->next; + } + + return matched_auth_dereg_list; +} diff --git a/server/fido_uaf_policy_checker.h b/server/fido_uaf_policy_checker.h new file mode 100644 index 0000000..ce9f8b8 --- /dev/null +++ b/server/fido_uaf_policy_checker.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#ifndef FIDO_UAF_POLICY_CHECKER_H +#define FIDO_UAF_POLICY_CHECKER_H + +#include +#include +#include "fido_json_handler.h" +#include "fido_internal_types.h" + +bool _policy_checker_is_matched(_match_criteria_t *match_criteria, fido_authenticator_s *auth_info); + +/* Returns _matched_auth_data_t list*/ +GList * _policy_checker_get_matched_auth_list(_policy_t *policy, GList *auth_list); + +/* Returns _matched_auth_dereg_t list*/ +GList * _policy_checker_get_matched_auth_list_dereg(const char *app_id, GList *input_auth_list, GList *available_auth_list); + +#endif // FIDO_UAF_POLICY_CHECKER_H diff --git a/test/Dummy_ASM_DBUS/CMakeLists.txt b/test/Dummy_ASM_DBUS/CMakeLists.txt new file mode 100644 index 0000000..743700a --- /dev/null +++ b/test/Dummy_ASM_DBUS/CMakeLists.txt @@ -0,0 +1,39 @@ +SET(ASM_DAEMON dummyasm-service) + +INCLUDE(FindPkgConfig) +pkg_check_modules(ASM_PKGS REQUIRED + dlog + glib-2.0 + gio-unix-2.0 + capi-base-common + vconf + json-glib-1.0 + capi-appfw-application +) + +FOREACH(flag ${ASM_PKGS_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/common) + +ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_SOURCE_DIR}/common/dummy-asm-stub.c ${CMAKE_SOURCE_DIR}/common/dummy-asm-stub.h +WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/common/ +COMMAND gdbus-codegen --interface-prefix org.tizen. --generate-c-code dummy-asm-stub ${CMAKE_SOURCE_DIR}/common/dbus_interfaces/dummyasm.xml +COMMENT "Generating Dummy ASM GDBus stubs........................") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror") +SET(CMAKE_LDFLAGS "-Wl,-zdefs") + +SET(DUMMY_ASM_SRCS + dummy_asm_server.c +) + +ADD_EXECUTABLE(${ASM_DAEMON} ${DUMMY_ASM_SRCS} ${CMAKE_SOURCE_DIR}/common/dummy-asm-stub.c) +ADD_DEPENDENCIES(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/common/dummy-asm-stub.h) +ADD_DEPENDENCIES(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/common/dummy-asm-stub.c) + +TARGET_LINK_LIBRARIES(${ASM_DAEMON} ${ASM_PKGS_LDFLAGS}) + +INSTALL(TARGETS ${ASM_DAEMON} DESTINATION bin) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/test/Dummy_ASM_DBUS/dummy_asm.json DESTINATION /usr/lib/fido/asm/) diff --git a/test/Dummy_ASM_DBUS/dummy_asm.json b/test/Dummy_ASM_DBUS/dummy_asm.json new file mode 100644 index 0000000..a34e200 --- /dev/null +++ b/test/Dummy_ASM_DBUS/dummy_asm.json @@ -0,0 +1,8 @@ +{ + "vendor" : "Dummy Corp", + "bin_path" : "/usr/bin/dummyasm-service", + "dbus_info" : "org.tizen.dummyasm", + "dbus_obj_path" : "/org/tizen/dummyasm", + "dbus_interface_name" : "org.tizen.dummyasm", + "dbus_method_name" : "asm_request" +} diff --git a/test/Dummy_ASM_DBUS/dummy_asm_server.c b/test/Dummy_ASM_DBUS/dummy_asm_server.c new file mode 100644 index 0000000..37734d6 --- /dev/null +++ b/test/Dummy_ASM_DBUS/dummy_asm_server.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#if !GLIB_CHECK_VERSION (2, 31, 0) +#include +#endif + +#include +#include "fido_internal_types.h" +#include "fido_logs.h" + +#include "dummy-asm-stub.h" + +#define _DUMMY_ASM_SERVICE_DBUS_PATH "/org/tizen/dummyasm" + +#define _GET_INFO_RESPONSE "{\"responseData\":{\"Authenticators\":[{\"aaid\":\"0001#8001\",\"asmVersions\":[{\"major\":1,\"minor\":0}],\"assertionScheme\":\"UAFV1TLV\",\"title\":\"UAF PIN 1\",\"attestationTypes\":[15879],\"tcDisplayContentType\":\"text/plain\",\"description\":\"Pretty long description\",\"supportedExtensionIDs\":[\"abc\"],\"icon\":\"data:image/png;base64,iVBORw0KGgoAAA\",\"isRoamingAuthenticator\":false,\"isSecondFactorOnly\":false,\"isUserEnrolled\":true,\"keyProtection\":1,\"matcherProtection\":1,\"hasSettings\":true,\"tcDisplay\":1,\"authenticatorIndex\":1,\"authenticationAlgorithm\":1,\"attachmentHint\":1,\"userVerification\":4},{\"aaid\":\"DDDD#C001\",\"asmVersions\":[{\"major\":1,\"minor\":0}],\"assertionScheme\":\"UAFV1TLV\",\"title\":\"UAF PIN 2\",\"attestationTypes\":[15879],\"tcDisplayContentType\":\"text/plain\",\"description\":\"Pretty long description\",\"supportedExtensionIDs\":[\"abc\"],\"icon\":\"data:image/png;base64,iVBORw0KGgoAAA\",\"isRoamingAuthenticator\":false,\"isSecondFactorOnly\":false,\"isUserEnrolled\":true,\"keyProtection\":1,\"matcherProtection\":1,\"hasSettings\":true,\"tcDisplay\":1,\"authenticatorIndex\":2,\"authenticationAlgorithm\":1,\"attachmentHint\":1,\"userVerification\":4}]},\"statusCode\":0}" + +#define _REG_RESPONSE "{\"responseData\":{\"assertion\":\"AT7gAgM-sQALLgkAMDAwMSM4MDAxDi4HAAABAQEAAAEKLiAAbuzkawu9cagRfQWDaOHkQAraLfwuBlCX5WEbQn-2vCQJLiAA1eVp7JIQlwm6YF0YEmGZdNCA27qZoIcZGC0Uaw71bR8NLggAAQAAAAEAAAAMLkEABDvrbVayiXwIsfShzUc2ALT8K3pZKykYGvpD7nU5Jy4sEXEKsepcRfZebCH7RHLwbchz6AmrK-3o1RAbauiuZMcHPicCBi5AAE3tsSOmUITLnQdbRTXdIe2R27E3e3JarZ8MT-9qcZug7__AM5ZUrXqyzSMhRCz9yHEhaeRMyRctxcD18uimqikFLt8BMIIB2zCCAYICCQDDAwxEtwee0TAJBgcqhkjOPQQBMHsxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCUEExEDAOBgNVBAoMB05OTCxJbmMxDTALBgNVBAsMBERBTjExEzARBgNVBAMMCk5OTCxJbmMgQ0ExHDAaBgkqhkiG9w0BCQEWDW5ubEBnbWFpbC5jb20wHhcNMTQxMjE4MTYwMzEyWhcNMjQxMjE1MTYwMzEyWjByMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVBhbG8gQWx0bzEbMBkGA1UECgwSTm9rIE5vayBMYWJzLCBJbmMuMSUwIwYJKoZIhvcNAQkBFhZub2tub2tjZXJ0c0Bub2tub2suY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhNa9EIVUCSqfiALGZXM1Zc32gFJfTpGFHIQD5OciVVs4HAl9o1mQOA9WPKhAWH_2dEubn0fQSi1sq4EaOReesjAJBgcqhkjOPQQBA0gAMEUCIHeQm_CRb_joYNff0v9OIzt3FKHvlCZh6ErUldOqUW-UAiEA2kNe-dEqXki2ikfMq79SO7ernvtSZ8X99PuhmMVjxT0\",\"assertionScheme\":\"UAFV1TLV\"},\"statusCode\":0}" + +#define _AUTH_RESPONSE "{\"responseData\":{\"assertion\":\"Aj7WAAQ-jgALLgkAMDAwMSM4MDAxDi4FAAABAQEADy4gAPyMxESI2aTWj7ETwRifnwh3EBOiZdCJDPeFTZuit-ivCi4gABsFkal_ID2-Q2jC0Mtblw4_ApXVeaogzzD-iE3erYUuEC4AAAkuIADV5WnskhCXCbpgXRgSYZl00IDbupmghxkYLRRrDvVtHw0uBAACAAAABi5AAGewExLjMHW0S6iVoHqGzGS8-qGmLfc35WdBSawTDx0rF7sbXUpQQ9LkK4LM-Fu3YgmpEEBXT254dIXbJzr4_oE\",\"assertionScheme\":\"UAFV1TLV\"},\"statusCode\":0}" + +#define _DEREG_RESPONSE "{\"statusCode\" : 0}" + +#define _GET_REGISTRATIONS_RESPONSE "{\"responseData\":{\"appRegs\":[{\"appID\":\"https://qa-egypt.noknoktest.com:443/UAFSampleProxy/uaf/facets.uaf\",\"keyIDs\":[\"1eVp7JIQlwm6YF0YEmGZdNCA27qZoIcZGC0Uaw71bR8\"]}]},\"statusCode\":0}" + +#define _FREEDESKTOP_SERVICE "org.freedesktop.DBus" +#define _FREEDESKTOP_PATH "/org/freedesktop/DBus" +#define _FREEDESKTOP_INTERFACE "org.freedesktop.DBus" + +#define _FIDO_SERVICE_PATH "/usr/bin/fido-service" + +static guint owner_id = 0; + +static Dummyasm* __dbus_obj = NULL; + +static inline int +__read_proc(const char *path, char *buf, int size) +{ + int fd = 0; + int ret = 0; + + if (buf == NULL || path == NULL) { + _ERR("path and buffer is mandatory\n"); + return -1; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + _ERR("fd open error(%d)\n", fd); + return -1; + } + + ret = read(fd, buf, size - 1); + if (ret <= 0) { + _ERR("fd read error(%d)\n", fd); + close(fd); + return -1; + } else + buf[ret] = 0; + + close(fd); + + return ret; +} + +static char* +__get_proc_path_of_dbus_caller(GDBusMethodInvocation *invocation) +{ + //pid_t remote_pid = 0; + GError *error = NULL; + GDBusConnection *connection = NULL; + GVariant *response = NULL; + guint32 upid; + const gchar *sender = NULL; + + sender = g_dbus_method_invocation_get_sender (invocation); + if (!sender) { + _ERR("Failed to get sender"); + return NULL; + } + + connection = g_dbus_method_invocation_get_connection(invocation); + if (connection == NULL) { + _ERR("Failed to open connection for the invocation [%s]", error->message); + g_error_free (error); + return NULL; + } + + error = NULL; + response = g_dbus_connection_call_sync (connection, + _FREEDESKTOP_SERVICE, _FREEDESKTOP_PATH, + _FREEDESKTOP_INTERFACE, "GetConnectionUnixProcessID", + g_variant_new ("(s)", sender), ((const GVariantType *) "(u)"), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + + if (response == NULL) { + _ERR("Failed to get caller id [%s]", error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (response, "(u)", &upid); + _INFO("Remote msg-bus peer service=%s pid=%u", sender, upid); + //remote_pid = (pid_t) upid; + + g_variant_unref (response); + + char buf[128]; + int ret = 0; + + snprintf(buf, sizeof(buf), "/proc/%d/cmdline", upid); + ret = __read_proc(buf, buf, sizeof(buf)); + if (ret <= 0) { + _ERR("No proc directory (%d)\n", upid); + return NULL; + } + + _INFO("Caller=[%s]", buf); + + return strdup(buf); +} + +static char* +__get_request_type(const char *asm_req_json) +{ + if (asm_req_json == NULL) + return NULL; + + JsonParser *parser = json_parser_new(); + RET_IF_FAIL(parser != NULL, NULL); + + GError *parse_err = NULL; + json_parser_load_from_data(parser, asm_req_json, -1, &parse_err); + RET_IF_FAIL(parse_err == NULL, NULL); + + JsonNode *root = json_parser_get_root(parser); + RET_IF_FAIL(root != NULL, NULL); + + JsonObject *root_obj = json_node_get_object(root); + + const char *req_type = json_object_get_string_member(root_obj, "requestType"); + + return strdup(req_type); + +} + +gboolean +_dbus_on_asm_request(Dummyasm *object, GDBusMethodInvocation *invocation, const gchar *uaf_request_json) +{ + _INFO("_dbus_on_asm_request"); + + char *caller_path = __get_proc_path_of_dbus_caller(invocation); + if (caller_path == NULL) { + _ERR("Failed to get caller path"); + dummyasm_complete_asm_request(object, invocation, -1, NULL); + return true; + } + + if (strcmp(caller_path, _FIDO_SERVICE_PATH) != 0) { + _ERR("Only fido-service is allowed to call ASM"); + dummyasm_complete_asm_request(object, invocation, -1, NULL); + return true; + } + + char *req_type = __get_request_type(uaf_request_json); + if (req_type == NULL){ + dummyasm_complete_asm_request(object, invocation, -1, NULL); + return true; + } + + _INFO("request type=[%s]", req_type); + + if (strcmp(req_type, "GetInfo") == 0){ + dummyasm_complete_asm_request(object, invocation, 0, _GET_INFO_RESPONSE); + } + if (strcmp(req_type, "Register") == 0){ + dummyasm_complete_asm_request(object, invocation, 0, _REG_RESPONSE); + } + if (strcmp(req_type, "Authenticate") == 0){ + dummyasm_complete_asm_request(object, invocation, 0, _AUTH_RESPONSE); + } + if (strcmp(req_type, "Deregister") == 0){ + dummyasm_complete_asm_request(object, invocation, 0, _DEREG_RESPONSE); + } + if (strcmp(req_type, "GetRegistrations") == 0) { + dummyasm_complete_asm_request(object, invocation, 0, _GET_REGISTRATIONS_RESPONSE); + } + + return true; +} + +static void +on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + _INFO("on_bus_acquired"); + + GDBusInterfaceSkeleton* interface = NULL; + __dbus_obj = dummyasm_skeleton_new(); + if (__dbus_obj == NULL) { + return; + } + + interface = G_DBUS_INTERFACE_SKELETON(__dbus_obj); + if (!g_dbus_interface_skeleton_export(interface, connection, _DUMMY_ASM_SERVICE_DBUS_PATH, NULL)) { + return; + } + + _INFO("before g_signal_connect"); + g_signal_connect(__dbus_obj, "handle_asm_request", + G_CALLBACK(_dbus_on_asm_request), NULL); + +} + +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + _INFO("on_name_acquired"); +} + +static void +on_name_lost (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + _INFO("on_name_lost"); + exit (1); +} + +static bool _initialize_dbus() +{ + _INFO("_initialize_dbus"); + owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + "org.tizen.dummyasm", + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, + NULL); + + if(owner_id == 0) { + _INFO("owner_id is 0"); + return false; + } + + + return true; +} + +static void +_initialize(void) +{ +#if !GLIB_CHECK_VERSION(2,35,0) + g_type_init(); +#endif + + if (_initialize_dbus() == false) { + /* because dbus's initialize failed, we cannot continue any more. */ + exit(1); + } +} + +int +main(void) +{ + GMainLoop *mainloop = NULL; + + mainloop = g_main_loop_new(NULL, FALSE); + + _initialize(); + + g_main_loop_run(mainloop); + + + return 0; +} diff --git a/test/FIDOSample/.cproject b/test/FIDOSample/.cproject new file mode 100644 index 0000000..06219c0 --- /dev/null +++ b/test/FIDOSample/.cproject @@ -0,0 +1,557 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/FIDOSample/.exportMap b/test/FIDOSample/.exportMap new file mode 100644 index 0000000..43e310e --- /dev/null +++ b/test/FIDOSample/.exportMap @@ -0,0 +1,4 @@ +{ + global: main; + local: *; +}; diff --git a/test/FIDOSample/.project b/test/FIDOSample/.project new file mode 100644 index 0000000..d420404 --- /dev/null +++ b/test/FIDOSample/.project @@ -0,0 +1,43 @@ + + + FIDOSample + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + org.tizen.nativecore.apichecker.core.builder + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.tizen.nativecore.apichecker.core.tizenCppNature + + + + 1432525397806 + + 26 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-*/.tpk + + + + diff --git a/test/FIDOSample/.rds_delta b/test/FIDOSample/.rds_delta new file mode 100644 index 0000000..612925b --- /dev/null +++ b/test/FIDOSample/.rds_delta @@ -0,0 +1,6 @@ +#delete +#add +#modify +author-signature.xml +signature1.xml +bin/fidosample diff --git a/test/FIDOSample/.sdk_delta.info b/test/FIDOSample/.sdk_delta.info new file mode 100644 index 0000000000000000000000000000000000000000..800f1fa1456446d8fb667f7a6565c1103f6a3211 GIT binary patch literal 3538 zcmaJ^-EZ7P5Fh96LUL_FLIJfBfk?cd(wL-$k~dVTLajsvqC6n+VEOF5J12McVf&!% zGZf{G{~)D6feQLTfuzs?JpvS3Ncbp}uM+Wu_zU&X#-v0ft2bK9XCSuShDcGvd& zxyLpO$lK5o4%^q8kvp5hP0z0eUCv_Xkqd%z7J67b<6X&&yqeFEeaS}W%`M~N+jBy5 zwN#)XvuXQYl|```H?_TLw%-MEK(IbWpzU^C55ft)f*rR*W*%rZu+&Hz(=O5222v>{ z8r$KYVoc>yCN#iz;3-%7v6jVEt7T;Ywc#0c1_>)P16GToX}hyEz<_G=2o1b ziM_j;>q}Q2O>xBzw8%m6L!MvYJ>TQCBlmgs@R|UBkZS(7xQzT(JvWGCVM=&s>PQMJ zJ(X(yxAZh@H|<$g_0lSqG2A;MKrcX#is!e8Hb}4;X~nbHQTW$1{Cn^vsPK}H%;qeQ zOON@NG&pML_8_d8v3H31W_J@4Q|6>OIpOV?-idUqv!m+oDC}G(+&oTH2w9}(K~>+2 z0>jlYg9f8^#r48<-p%d0`m#VBgO>TlyK)q?Lx<&V24_pf>Pz zL>rmwSO{?vj!eP{jc^iW$=sQwOUiaICJ!`vost!U`n{%ITc0}xT~R=y)giida?)}F zKMsRN#SSeG&z2p=UW96E`TQ96i7wl1o8Q5NOz00pV;Lq~&u*|V*TPSlg`bJWGb~i? zCxXz6Q73tBT-A)M5#5$yq}8wwHn5jm8((QQE)(67VIvCsTD}wfo|3Wnl4z3?gv_e6 zC?T*~D>8l191`$==Am0eoMfeI%U8r*(O z^fwy%3egR?&<cz*$6CeFWH4B4zWS@McmcX7o~1!4^(!Ht8>o^sns18g%Zy zUwFv5bnuZU3-@uM;Z^wmJq3pTp=7NeosL~j4)IX&pXkCyKr+7 z1kvply95j{if}LXsS|LePGyqr)=1Of=iQ{}>Pk)(X^2l{xDy^XXV7+FSzb`}-|k3p zd^C~5XPRLY4Xb5Qylu}43Sd%-AMtwcxgEBQ3&1G}gg%X6W*=?^e_ey0QHMLPVV?n7 zW)wHOINW*YH#9V6rvD%AJlbiEh6VZI&V#}S<Di~hm4OL zsw!1v;IWbgBfkK!u98KAhI#3xQ)jN*iy+7_;#WrQfb^*{Omq=LK{6omjwBDo!ii}C i!Prd?q|c>$5bI=koKU|h(w_$M=T>(RK!Z`9tk8d#GFtQi literal 0 HcmV?d00001 diff --git a/test/FIDOSample/.sign/.manifest.tmp b/test/FIDOSample/.sign/.manifest.tmp new file mode 100644 index 0000000..4172b97 --- /dev/null +++ b/test/FIDOSample/.sign/.manifest.tmp @@ -0,0 +1,14 @@ +bin/fidosample__DEL__cQydzVGXaqxCtCMUHVsORDV8JNjErEzMdsV0NBqLjTM= +lib/libfido.so__DEL__P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= +lib/libfido.so.0__DEL__P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= +lib/libfido.so.0.0.1__DEL__P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= +res/auth_req.json__DEL__FGdxCabhGQXxZ5gkxsFI4jR5ZOxn4ZXDReerTH0Bm4E= +res/dereg_req.json__DEL__jX5V0X77th7FzuRnTCqo31VTnusBJTVU8Zz4nKSlQYs= +res/images/grid_image/1_raw.png__DEL__IJNLOq/2eGlWpHGmr+9Mr8bWDbnm0RohlK0cMHO8jZU= +res/images/grid_image/2_raw.png__DEL__S9L9E5QpM5gu7cRg8B4Y+030ULCkfPBJA4gMdIHuyCw= +res/images/horz_scrollbar.png__DEL__ZJMOojE8pcti4mJJDD/iNw8d0k139TVGwzwEpGNbNyQ= +res/images/iu.png__DEL__iLwO5Bzet3XJ6+hLP5KGoIsFcgDFFICC19Pk+JGz4is= +res/reg_req.json__DEL__VVAmN7Zvyj11MUk8/3f+YVfpSh8TK1iZCQmUUTl68D0= +shared/res/fidosample.png__DEL__1d0oEZHqPn+QzNzGIHwj9ODby6x9ggFs9uOsav6jPNs= +tizen-manifest.xml__DEL__lpZcIwMWbCWgkT+mRmx6DdJlsq3wr+rXPssOdJEbRPI= +author-signature.xml__DEL__lpGJZnRZJh1VLsq1P4tx2rnjqn6GshHqgmxx+NaGCTk= diff --git a/test/FIDOSample/.sign/author-signature.xml b/test/FIDOSample/.sign/author-signature.xml new file mode 100644 index 0000000..38409cb --- /dev/null +++ b/test/FIDOSample/.sign/author-signature.xml @@ -0,0 +1,106 @@ + + + + + + +cQydzVGXaqxCtCMUHVsORDV8JNjErEzMdsV0NBqLjTM= + + + +P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= + + + +P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= + + + +P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= + + + +FGdxCabhGQXxZ5gkxsFI4jR5ZOxn4ZXDReerTH0Bm4E= + + + +jX5V0X77th7FzuRnTCqo31VTnusBJTVU8Zz4nKSlQYs= + + + +IJNLOq/2eGlWpHGmr+9Mr8bWDbnm0RohlK0cMHO8jZU= + + + +S9L9E5QpM5gu7cRg8B4Y+030ULCkfPBJA4gMdIHuyCw= + + + +ZJMOojE8pcti4mJJDD/iNw8d0k139TVGwzwEpGNbNyQ= + + + +iLwO5Bzet3XJ6+hLP5KGoIsFcgDFFICC19Pk+JGz4is= + + + +VVAmN7Zvyj11MUk8/3f+YVfpSh8TK1iZCQmUUTl68D0= + + + +1d0oEZHqPn+QzNzGIHwj9ODby6x9ggFs9uOsav6jPNs= + + + +lpZcIwMWbCWgkT+mRmx6DdJlsq3wr+rXPssOdJEbRPI= + + + + + + +lpo8tUDs054eLlBQXiDPVDVKfw30ZZdtkRs1jd7H5K8= + + + +Nk/gxrB8EQzeGZzVzoShWf/pYdIkX+39TG7MAGkqtRBfeZPPr9+HV7sU47lYwzwGaVhw5VD4sSFg +Je27t7tKhfUHuTaD4FxITZRJPPALPEztKGOEEtf7sDKVZXafSv2/WNlC4Ogg7jVKPLJ6yxxYJkDf +Y6UN6bU7t60HPB4FoNg= + + + + +MIIClTCCAX2gAwIBAgIGAU2fJWlKMA0GCSqGSIb3DQEBBQUAMFYxGjAYBgNVBAoMEVRpemVuIEFz +c29jaWF0aW9uMRowGAYDVQQLDBFUaXplbiBBc3NvY2lhdGlvbjEcMBoGA1UEAwwTVGl6ZW4gRGV2 +ZWxvcGVycyBDQTAeFw0xMjExMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMBExDzANBgNVBAMMBmF1 +dGhvcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2VQLCgvKZSz4D3K5fzI8xDObQhn0CZmD +f2rQdfPgc0WbaKRHgOaQ4WZ5xxyqtEmVxXRU0W7KeylUfbxaDzibmqtq4lV2eCZ7XLW1nW4OwXil +SSFTkNjgYI4HTmwO2YzRP5Y+uw3Ljl30o7YxkhpO2b7w4OJASxAMB9/Em1n1R20CAwEAAaMyMDAw +DAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcN +AQEFBQADggEBAJx+sGPyiDI8km5hGA29XkvOcOn41XJRMHv7s28MHIvg5j8qkQNJneq8sc7ilMNo +0V1Zize3+1XtpdAAI4xPsA6DUGzCX002lieRefwUVKvCv4ETknkuZ4OdjkQrrBGHBGzCV0QWv6o4 +FX0Ep2XoMLHiRSI4ATutUYc9+uehQPuWkzrRSR3SbvEaS2hu3GoFCl7Enc6Y7Ebfn1LgEW13i6hO +sbKhFc0lyHYyk+2MnhpB/SpQszRv0zOs1j6aVy8afozaBP2kS+/OgJ4XYaaNVreLIoRg1GmZhYzF +NJ4p4t7Z83GuS0SjxnfVVNNT19utuDJX8ay5334I+v7fPvVlN8g= + + +MIIDOTCCAiGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMRowGAYDVQQKDBFUaXplbiBBc3NvY2lh +dGlvbjEaMBgGA1UECwwRVGl6ZW4gQXNzb2NpYXRpb24xHjAcBgNVBAMMFVRpemVuIERldmVsb3Bl +cnMgUm9vdDAeFw0xMjAxMDEwMDAwMDBaFw0yNzAxMDEwMDAwMDBaMFYxGjAYBgNVBAoMEVRpemVu +IEFzc29jaWF0aW9uMRowGAYDVQQLDBFUaXplbiBBc3NvY2lhdGlvbjEcMBoGA1UEAwwTVGl6ZW4g +RGV2ZWxvcGVycyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANVGhRGmMIUyBA7o +PCz8Sxut6z6HNkF4oDIuzuKaMzRYPeWodwe9O0gmqAkToQHfwg2giRhE5GoPld0fq+OYMMwSasCu +g8dwODx1eDeSYVuOLWRxpAmbTXOsSFi6VoWeyaPEm18JBHvZBsU5YQtgZ6Kp7MqzvQg3pXOxtajj +vyHxiatJl+xXrHgcXC1wgyG3buty7u/Fi2mvKXJ0PRJcCjjK81dqe/Vr20sRUCrbk02zbm5ggFt/ +jIEhV8wbFRQpliobc7J4dSTKhFfrqGM8rdd54LYhD7gSI1CFSe16pUXfcVR7FhJztRaiGLnCrwBE +dyTZ248+D4L/qR/D0axb3jcCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC +AQEAnOXXQ/1O/QTDHyrmQDtFziqPY3xWlJBqJtEqXiT7Y+Ljpe66e+Ee/OjQMlZe8gu21/8cKklH +95RxjopMWCVedXDUbWdvS2+CdyvVW/quT2E0tjqIzXDekUTYwwhlPWlGxvfj3VsxqSFq3p8Brl04 +1Gx5RKAGyKVsMfTLhbbwSWwApuBUxYfcNpKwLWGPXkysu+HctY03OKv4/xKBnVWiN8ex/Sgesi0M ++OBAOMdZMPK32uJBTeKFx1xZgTLIhk45V0hPOomPjZloiv0LSS11eyd451ufjW0iHRE7WlpR6EvI +W6TFyZgMpQq+kg4hWl2SBTf3s2VI8Ygz7gj8TMlClg== + + + + + \ No newline at end of file diff --git a/test/FIDOSample/.sign/signature1.xml b/test/FIDOSample/.sign/signature1.xml new file mode 100644 index 0000000..b7770f0 --- /dev/null +++ b/test/FIDOSample/.sign/signature1.xml @@ -0,0 +1,108 @@ + + + + + + +lpGJZnRZJh1VLsq1P4tx2rnjqn6GshHqgmxx+NaGCTk= + + + +cQydzVGXaqxCtCMUHVsORDV8JNjErEzMdsV0NBqLjTM= + + + +P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= + + + +P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= + + + +P2ULaW6DujYXBTB+zl0+20pyk4TjC/Ns6/agEF+uIXk= + + + +FGdxCabhGQXxZ5gkxsFI4jR5ZOxn4ZXDReerTH0Bm4E= + + + +jX5V0X77th7FzuRnTCqo31VTnusBJTVU8Zz4nKSlQYs= + + + +IJNLOq/2eGlWpHGmr+9Mr8bWDbnm0RohlK0cMHO8jZU= + + + +S9L9E5QpM5gu7cRg8B4Y+030ULCkfPBJA4gMdIHuyCw= + + + +ZJMOojE8pcti4mJJDD/iNw8d0k139TVGwzwEpGNbNyQ= + + + +iLwO5Bzet3XJ6+hLP5KGoIsFcgDFFICC19Pk+JGz4is= + + + +VVAmN7Zvyj11MUk8/3f+YVfpSh8TK1iZCQmUUTl68D0= + + + +1d0oEZHqPn+QzNzGIHwj9ODby6x9ggFs9uOsav6jPNs= + + + +lpZcIwMWbCWgkT+mRmx6DdJlsq3wr+rXPssOdJEbRPI= + + + + + + +u/jU3U4Zm5ihTMSjKGlGYbWzDfRkGphPPHx3gJIYEJ4= + + + +R08hPToKjQBKyVXqEKXuXaVYQk6JguHXCUQ/CLB3X1aS1ObBO48mrpptk6nJnnuguhMn7rlyiIcn +1e4QJnOnZ4yZzlTT0sPQ7AcVJBGeI8uX8p4RFwhpVhuZm8LWYrpN5BhIUqSPAFIQafeSOPkFfmFr +jaVnxuK+lNDT75vMXi8= + + + + +MIICmzCCAgQCCQDXI7WLdVZwiTANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMCS1IxDjAMBgNV +BAgMBVN1d29uMQ4wDAYDVQQHDAVTdXdvbjEWMBQGA1UECgwNVGl6ZW4gVGVzdCBDQTEiMCAGA1UE +CwwZVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTEkMCIGA1UEAwwbVGl6ZW4gUHVibGljIERpc3Ry +aWJ1dG9yIENBMB4XDTEyMTAyOTEzMDMwNFoXDTIyMTAyNzEzMDMwNFowgZMxCzAJBgNVBAYTAktS +MQ4wDAYDVQQIDAVTdXdvbjEOMAwGA1UEBwwFU3V3b24xFjAUBgNVBAoMDVRpemVuIFRlc3QgQ0Ex +IjAgBgNVBAsMGVRpemVuIERpc3RyaWJ1dG9yIFRlc3QgQ0ExKDAmBgNVBAMMH1RpemVuIFB1Ymxp +YyBEaXN0cmlidXRvciBTaWduZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALtMvlc5hENK +90ZdA+y66+Sy0enD1gpZDBh5T9RP0oRsptJv5jjNTseQbQi0SZOdOXb6J7iQdlBCtR343RpIEz8H +mrBy7mSY7mgwoU4EPpp4CTSUeAuKcmvrNOngTp5Hv7Ngf02TTHOLK3hZLpGayaDviyNZB5PdqQdB +hokKjzAzAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAvGp1gxxAIlFfhJH1efjb9BJK/rtRkbYn9+Ez +GEbEULg1svsgnyWisFimI3uFvgI/swzr1eKVY3Sc8MQ3+Fdy3EkbDZ2+WAubhcEkorTWjzWz2fL1 +vKaYjeIsuEX6TVRUugHWudPzcEuQRLQf8ibZWjbQdBmpeQYBMg5x+xKLCJc= + + +MIICtDCCAh2gAwIBAgIJAMDbehElPNKvMA0GCSqGSIb3DQEBBQUAMIGVMQswCQYDVQQGEwJLUjEO +MAwGA1UECAwFU3V3b24xDjAMBgNVBAcMBVN1d29uMRYwFAYDVQQKDA1UaXplbiBUZXN0IENBMSMw +IQYDVQQLDBpUVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTEpMCcGA1UEAwwgVGl6ZW4gUHVibGlj +IERpc3RyaWJ1dG9yIFJvb3QgQ0EwHhcNMTIxMDI5MTMwMjUwWhcNMjIxMDI3MTMwMjUwWjCBjzEL +MAkGA1UEBhMCS1IxDjAMBgNVBAgMBVN1d29uMQ4wDAYDVQQHDAVTdXdvbjEWMBQGA1UECgwNVGl6 +ZW4gVGVzdCBDQTEiMCAGA1UECwwZVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTEkMCIGA1UEAwwb +VGl6ZW4gUHVibGljIERpc3RyaWJ1dG9yIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDe +OTS/3nXvkDEmsFCJIvRlQ3RKDcxdWJJp625pFqHdmoJBdV+x6jl1raGK2Y1sp2Gdvpjc/z92yzAp +bE/UVLPh/tRNZPeGhzU4ejDDm7kzdr2f7Ia0U98K+OoY12ucwg7TYNItj9is7Cj4blGfuMDzd2ah +2AgnCGlwNwV/pv+uVQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBACqJ +KO33YdoGudwanZIxMdXuxnnD9R6u72ltKk1S4zPfMJJv482CRGCI4FK6djhlsI4i0Lt1SVIJEed+ +yc3qckGm19dW+4xdlkekon7pViEBWuyHw8OWv3RXtTum1+PGHjBJ2eYY4ZKIpz73U/1NC16sTB/0 +VhfnkHwPltmrpYVe + + + + + \ No newline at end of file diff --git a/test/FIDOSample/.tproject b/test/FIDOSample/.tproject new file mode 100644 index 0000000..801d1ed --- /dev/null +++ b/test/FIDOSample/.tproject @@ -0,0 +1,11 @@ + + + + + mobile-2.4 + + + + + + diff --git a/test/FIDOSample/edje/images/00_controlbar_icon_artists.png b/test/FIDOSample/edje/images/00_controlbar_icon_artists.png new file mode 100644 index 0000000000000000000000000000000000000000..85dd55ce9a153c96e200c6da12b0cdd79027248c GIT binary patch literal 3131 zcmV-B48-$^P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0004INklS#e$OF<|1mz2i}mGypm`zBN6FNUs^C_V8C8Pyq0n`&Vf^*A=^u zIrX0FS}oXZ9exoR06bk;_A-VFR;0leB+nE7YDku`2CEw7!b3{{t=rA$NQwq?IcZ04 z)gn^=TUL@ZGh_VK*#YOxN(a?k$;$63T#l@4JY9WomN6u^3)dQaqs9REOm46N#yV@X zDR;~&pj0g*6zo~)<2LmuWB!CbhJ^Yd;Lw+mO{PdSN)riop9-u%M%_e%?Y9bcauK6d zodnF~-J25XW2p-LS?wWNuGAgQTo>4^4R%xzj}t2y0DJ*BO)prIG}!%qYzI^7X8^N> V$N?ZCZ=(PJ002ovPDHLkV1iSK$hZIi literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/00_controlbar_icon_dialer.png b/test/FIDOSample/edje/images/00_controlbar_icon_dialer.png new file mode 100644 index 0000000000000000000000000000000000000000..5dbb9fe9b4c318fae8207ae8682b9ef4b1cb7e78 GIT binary patch literal 2950 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 literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/00_controlbar_icon_favorites.png b/test/FIDOSample/edje/images/00_controlbar_icon_favorites.png new file mode 100644 index 0000000000000000000000000000000000000000..663b6fac9e1f23eb87d527b15bf96ad1f49d7d06 GIT binary patch literal 3170 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 IM6N<$f~oJ=p#T5? literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/00_controlbar_icon_playlist.png b/test/FIDOSample/edje/images/00_controlbar_icon_playlist.png new file mode 100644 index 0000000000000000000000000000000000000000..cb77f2b7425f1d32883e0846d2b6a38aa3839af7 GIT binary patch literal 2960 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 literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/core_button_add.png b/test/FIDOSample/edje/images/core_button_add.png new file mode 100644 index 0000000000000000000000000000000000000000..d2b5db5b2174536a33c1a35512e83eddd2427a97 GIT binary patch literal 1004 zcmaJ=&rj1(94{EbED}sKs2t3rB%WB`Yv~3n6dda&OYB0%5~e4*_Kg*2Uu_?*a53>< zVl;U0KL8J&IC%A7`~hnG3-n-&F_8m_dMClxu?-K-Chhyt&*$^~zVG+*9?TW4_r(Td z9LM$LXSE_5uSD;e9`>C;J6mkHOtWP=PpY(T_?Syuq=G@-F_v%<8`k>m4|tN}PVsiB zOw0NW#UzekL>M7-JjUj@$?4ED%oR*Q1uxmI%Kv=vk_Wb>@(T$a>0Soc?AZ+;&uQ^r zrcx=0Bq&L7hKL92E;Yiq8w|G;G#r?|?NOV!AW}3cWR0pk%k=mNj@OoTgJzjn!C+{3 zP!v#fq!v)u{||MXHaeh1e3I`!g@e+%hhY&1WX(5O$;M618TS?&TA^q6a?G06e%O+ncH&A~2hajg^XXh&{j1;=BNHSF7Wu$A+P0~$wG?9REMj(Sb5)j1cj zBNwt{VAR;Z8r|Ar?un*t+pb)V(-z6|vgV>i!5_b;C literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/core_button_delete.png b/test/FIDOSample/edje/images/core_button_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..37d3e5f685a1f2066c02e2a211e18449313df3a5 GIT binary patch literal 978 zcmaJ=&ui2`7)>jP6iaUvJ;;!Pr*38@yJ^k1aoujRHegEGE_Cr^Hko!~n@pO_x@kQK zJqS|J|G^4+>ObH?L8N#W4}w>((vugVPPV(-9$W*H`N4bdd*3(TyjWeiKRtD0N|K~$ zd)aJ=`DQ+@To(U3=;*bWu5+u!*VqQ{xe1l3K5J88hwdhAP}kqx`9jN*bV&}HE#7h- z5RZk5n`4wLj0Ibg%9Sj3y)DW?n{Eb?A^&>+K?Z?u$m^PeoVZ3i!SY^0*Y;ML-rkm{ z`*P(jC}%_ngp|7=3%8?`WQN?=C1RZ)LmBiTe9Mr}OtqXR*bQ`Sv9ad8`Sd8nAw66$i6G#T3-R&lk%I7>S$2DLR! z!C*azeAY|*c*h}jlyW!nsBIduP*8%vCu-HKmzJukwS-lSt)i}JxN73kf>pFsyjUA@ zP3Cn&8u205Kj#+5a`RRQV-eY;N$`aF^@N3>pE3!?dqHFM23&u<7d(~=g&CM%?1hUS z9*OSBm!q~7n^EJ_NOXH5+S>Xtmx?D*x6NuZ``-R@dRqB(PrCJdV)AhI)x+}RlXssF zXJ^8L-;*cLrcQ7&|MTts@$DTOz5I535kU?nCa+4`n`<9utglb=S7uu)=F!rl{l8L~ BGMoSa literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/core_color_picker_palette.png b/test/FIDOSample/edje/images/core_color_picker_palette.png new file mode 100644 index 0000000000000000000000000000000000000000..497cc75b77d24261f1378e7ef2c7d96c58325c9f GIT binary patch literal 1041 zcmbVLJ#W)M7`9Xip^6TSR17C~;Vbr?9e=8!a&3o3YD!5XH4+Q1eMwAfpKD);8;J#p zp$ifVKLA+yTp2(DhAv1I1BhS1fYgCMz&VWzL)3wj?E8A3_j&I9*k50}F*iFu%W>RX zW5sE)`AYGfJ;VN=KOWp>(*^2w=mzQ1p_gLL3dj})jmYca7WRU@-2=SHaWmbp-JzZ4 zs_BzR@Cq9tj}nIFxW%PB@%(K}!4~d?ag9HE_nrq~P~$h1CTu1)?uRR*6mN{y+Wu(U zHv)d?I#|q2<{-k<19`L)XJ%gG$9_$=E{;VWj7{ivjXxIEX|4mCq!=gytoTqxK&=X> z3XQ694M-3{5lJG{DhQg2WLw48sti zBuY|+SyZyUn0k37&K61!4$k~EOlU}API3t79XZh$ZlwcOS(}@a0rpCOPhAb)Gjzj!Ggk#!p zYCO9Uf-o>)Rfh;^Rj5f&)e+L6F6*+PKnLoo;y9&`Y1q1sY}b&HTV;tru57r-axBT! zmt||&L9oO&;*5H+k4xT=@lLStRIF*I*rOzE6S7lQz471Bc zdX8V~;5594gL+CLFpjSoPT|)qSCdp(*Hu??WrPf^YTF88;$5|_)D?b$4gM!)A`>GP z#qm$Elt-)ri{(k_v&~8K;Fxtx%39;iYIL8qmDO;pcK+kn7c|Ggb2G0WF8zG+=~4ad td0qZJ{~V157jI1;hp!I5-hF!Y1NZIwvlmB?clV1XZMbXB%jG){{s6PjL?r+K literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/core_icon_brightness.png b/test/FIDOSample/edje/images/core_icon_brightness.png new file mode 100644 index 0000000000000000000000000000000000000000..f7dfb2971a87154195dc324fb45b141e32a74192 GIT binary patch literal 1432 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i1|)m0dc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlv}+D_=m^v6nO9trn3tRivo{lHFI2B9UcFY%MX8A;`9&f5`8lu@5Rj2y zl3$#WU!dR|Y^rCd5T2Qrl3!j7iXMn>T~doO%TiO^it=+6z~O6^iN$^sGb2-H3lkSt zQ&(eGV?#qnOJ{ReO9L}wCqow#6DK1jsNNKE!b~6N7=2LUKuRnyAz%swG2uxc$bn~` z)I4C0DFS8(AQ0DmUGM$arZCx*>c6Ow8%+L`$z3I%# z?B)NOU(~<2vGBCeMa7LJ9?N|%u1sD&BPVI|l(6K>9oOG4kN>mh@7_vd>zQ)$+4pXL z|Gn>i_5JU&H8qwl`;>KA_{>fAg4Vq@NB-Gt4m!5u>5?S9+`zj6D>5Pl&ha-qyTKvV zV#xgEs=qYj>nr;?wls>H-aE(8|L-|d{+0iHAr&>TJS!((SpPuq!_g*t#zuvzQ!RFl z%jBYkF0)o{(CW?CDi&^ibYz0_te)uWmySI;qUU4i>vVcc>5fyPi8g*b(av4joBr|b z%;VoN^T4m&N$WQ>DOqyfo}*YCo#s`p^ymWXo2>5~zvUW^^N9cE;<)*Fmh-{vL-Xew zhfQ1+#}lB##JA87OI=2MHrUh&Fid%Oxl!tC-4ak)>FMg{vd$@?2>{j3 B3q$|_ literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/grid_image/1_raw.jpg b/test/FIDOSample/edje/images/grid_image/1_raw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94deef3c786a58575366edd33b024dc18d6f49a0 GIT binary patch literal 9594 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 literal 0 HcmV?d00001 diff --git a/test/FIDOSample/edje/images/horz_scrollbar.jpg b/test/FIDOSample/edje/images/horz_scrollbar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab27b96a257d22c696326c74c00279c8454d0db6 GIT binary patch literal 719515 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μ4&V9d1 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

$QT#?_g4m+Wavs6&3Ek+TyNYO4`e zxbbAZpLTNK_%z?R!ZJtFZX?rh2C{#jT4sA`8CwhH?N}b8?D3wmY_-%XxmB4jEh93V$ec`pm-3Y^W0dqIiQ%P6f>JrmIHdq~ z>IOV#^$n+0Jz1c&ZFt-f>Hh0p&h|A-T#qjsRf)s?IZ4l1i#FxBnQ@5DP;^O#>e&eo zGj#F?ly8y1Jb$`qlF{i=k(_&q2!RTVRBo>loh`b;-F?Nr%8sSe z-2&Ghg4kX^>c=qO^o^np0~~PQ(%P z$E}Xr?CvopxZl>Zo=F-c8cASz_OC>^d6%-LdEx9hZO|mps?uT>-jT>sC8hMH#H~lN zi2ZRFme%HAw*+m+u=TA-*#d;en0gJjteI5dE^CKM%yq2CF*#y~mnzOv)a$0}l!YqE zT71HW{{UQGPqEvOPxl`HfIItq(z9DK2X%3w0Wl>afsY3X9AsXP)&}(izBAN`o=t)OEb;<@RGKVF7AV$<<@f5_%jK?tY_eJVuX=jx*Q+y(@ZS{KYXNB%0Di%N`9^ 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%0D~QKA@BXR=vIp6@HSgcBZ?dW2D|L#^QbUrn9eNvW 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