diff -Nru nitrokey-app-1.3.2/CMakeLists.txt nitrokey-app-1.4.1/CMakeLists.txt --- nitrokey-app-1.3.2/CMakeLists.txt 2018-12-12 12:23:09.000000000 +0000 +++ nitrokey-app-1.4.1/CMakeLists.txt 2020-08-06 10:07:14.000000000 +0000 @@ -2,8 +2,8 @@ cmake_policy(SET CMP0043 OLD) # cmake --help-policy CMP0043 PROJECT(NitrokeyApp LANGUAGES CXX) -SET(PROJECT_VERSION "1.3.2") -set(LIBNK_MIN_VERSION 3.3) +SET(PROJECT_VERSION "1.4.1") +set(LIBNK_MIN_VERSION 3.5) include(GNUInstallDirs) @@ -36,7 +36,7 @@ #add CMake build info ADD_DEFINITIONS(-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}") -ADD_DEFINITIONS(-DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER_ID}, ${CMAKE_CXX_COMPILER}, built on: ${CMAKE_SYSTEM} ") +ADD_DEFINITIONS(-DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER_ID}, ${CMAKE_CXX_COMPILER}, built on: ${CMAKE_SYSTEM_NAME} ") ADD_DEFINITIONS(-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}") diff -Nru nitrokey-app-1.3.2/data/com.nitrokey.nitrokey-app.appdata.xml nitrokey-app-1.4.1/data/com.nitrokey.nitrokey-app.appdata.xml --- nitrokey-app-1.3.2/data/com.nitrokey.nitrokey-app.appdata.xml 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/data/com.nitrokey.nitrokey-app.appdata.xml 2020-08-06 10:07:14.000000000 +0000 @@ -17,10 +17,13 @@ Qt - + + nitrokey-app + usb:v20A0p4108d* + usb:v20A0p4109d* nitrokey-app.desktop https://www.nitrokey.com/ @@ -29,7 +32,7 @@ https://www.nitrokey.com/start - https://github.com/Nitrokey/nitrokey-app/blob/master/images/icon/nitrokey-app-icon-128-black.png + https://raw.githubusercontent.com/Nitrokey/nitrokey-app/master/images/icon/nitrokey-app-icon-128-black.png diff -Nru nitrokey-app-1.3.2/debian/changelog nitrokey-app-1.4.1/debian/changelog --- nitrokey-app-1.3.2/debian/changelog 2020-03-23 06:20:42.000000000 +0000 +++ nitrokey-app-1.4.1/debian/changelog 2020-08-06 10:08:55.000000000 +0000 @@ -1,8 +1,21 @@ -nitrokey-app (1.3.2-1build1) focal; urgency=medium +nitrokey-app (1.4.1-1) unstable; urgency=medium - * No-change rebuild for libgcc-s1 package name change. + * New upstream release. + * debian/control: + - Update to Debian policy 4.5.0, no changes needed. + - Clean up Build-Depends. (Closes: #967655) + * debian/compat: Update to compat version 13. - -- Matthias Klose Mon, 23 Mar 2020 07:20:42 +0100 + -- Jan Luca Naumann Thu, 06 Aug 2020 12:08:55 +0200 + +nitrokey-app (1.4.0-1~exp1) experimental; urgency=medium + + * New upstream release. + * debian/control: + - Update to Debian policy 4.4.0, no changes needed. + * debian/compat: Update to compat version 12. + + -- Jan Luca Naumann Sat, 28 Sep 2019 18:25:48 +0200 nitrokey-app (1.3.2-1) unstable; urgency=medium diff -Nru nitrokey-app-1.3.2/debian/compat nitrokey-app-1.4.1/debian/compat --- nitrokey-app-1.3.2/debian/compat 2017-12-28 18:46:47.000000000 +0000 +++ nitrokey-app-1.4.1/debian/compat 2020-08-06 10:08:55.000000000 +0000 @@ -1 +1 @@ -11 +13 diff -Nru nitrokey-app-1.3.2/debian/control nitrokey-app-1.4.1/debian/control --- nitrokey-app-1.3.2/debian/control 2018-12-12 12:24:37.000000000 +0000 +++ nitrokey-app-1.4.1/debian/control 2020-08-06 10:08:55.000000000 +0000 @@ -4,19 +4,18 @@ Maintainer: Jan Luca Naumann Build-Depends: bash-completion, cmake (>=3.1.0), - debhelper (>= 11~), - libgtk2.0-dev, - libnotify-dev, + debhelper (>= 13~), libusb-1.0-0-dev, udev, - qt5-qmake, qtbase5-dev, + qt5-qmake, qttools5-dev, libqt5svg5-dev, - qtchooser, + libqt5concurrent5, libhidapi-dev, - libnitrokey-dev (>=3.3) -Standards-Version: 4.3.0 + pkg-config, + libnitrokey-dev (>=3.5) +Standards-Version: 4.5.0 Homepage: https://github.com/Nitrokey/nitrokey-app Vcs-Git: https://salsa.debian.org/janluca-guest/nitrokey-app-debian.git Vcs-Browser: https://salsa.debian.org/janluca-guest/nitrokey-app-debian diff -Nru nitrokey-app-1.3.2/debian/copyright nitrokey-app-1.4.1/debian/copyright --- nitrokey-app-1.3.2/debian/copyright 2018-12-12 12:24:37.000000000 +0000 +++ nitrokey-app-1.4.1/debian/copyright 2019-09-29 19:16:35.000000000 +0000 @@ -29,13 +29,17 @@ License: Expat Files: libnitrokey/* -Copyright: 2015-2018 Szczepan Zalega +Copyright: 2015-2019 Nitrokey UG License: LGPL-3.0 Files: libnitrokey/libnitrokey/hidapi/hidapi.h Copyright: 2009, Alan Ott, Signal 11 Software License: Hidapi-BSD +Files: data/com.nitrokey.nitrokey-app.appdata.xml +Copyright: 2015-2019 Nitrokey UG +License: CC0-1.0 + Files: debian/* Copyright: 2016-2018 Jan Luca Naumann License: GPL-3.0+ @@ -155,3 +159,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: CC0-1.0 + On Debian systems, the complete text of the CC0 1.0 can be found in + "/usr/share/common-licenses/CC0-1.0". diff -Nru nitrokey-app-1.3.2/i18n/nitrokey_de_DE.ts nitrokey-app-1.4.1/i18n/nitrokey_de_DE.ts --- nitrokey-app-1.3.2/i18n/nitrokey_de_DE.ts 2018-12-12 12:23:09.000000000 +0000 +++ nitrokey-app-1.4.1/i18n/nitrokey_de_DE.ts 2019-09-28 16:20:07.000000000 +0000 @@ -29,7 +29,7 @@ Hidden Volume: - Versteckte Volumen: + Verstecktes Volumen: <span style="color:#c80636">Warning</span> @@ -210,7 +210,7 @@ Unfortunately you have no more trials left. Please use 'Reset User PIN' option from menu to reset password - Leider sind keine Eingaben mehr möglich. Bitte nutzen Sie die Option "Reset Benutzer-PIN" im Menü um Ihre PIN zurückzusetzen + Leider sind keine Eingaben mehr möglich. Bitte nutzen Sie die Option "Benutzer-PIN zurücksetzen" im Menü um Ihre PIN zurückzusetzen Unfortunately you have no more trials left. Please check instruction how to reset Admin password. @@ -702,7 +702,7 @@ Forget user PIN after 10 minutes (if unchecked user PIN will remain in memory until application exits) - Vergiss die Benutzer-PIN nach 10 Minuten (wenn nicht ausgewählt wird die Benutzer-PIN im Speicher abgelegt bis die Anwendung geschlossen wird) + Benutzer-PIN nach 10 Minuten vergessen (wenn nicht ausgewählt wird die Benutzer-PIN im Speicher abgelegt bis die Anwendung geschlossen wird) Command execution failed. Please try again. @@ -1532,7 +1532,7 @@ <html><head/><body><p>When you select &quot;OK&quot; the device enters the <br/>firmware update mode. There is no way back!<br/>Please read the <a href="https://www.nitrokey.com/en/doc/firmware-update-storage"><span style=" text-decoration: underline; color:#0000ff;">documentation </span></a>how to <br/>update the firmware.</p><p>Continue entering the firmware update mode?</p><p><br/></p></body></html> - <html><head/><body><p>Wenn Sie mit &quot;OK&quot; bestätigen wird der Nitrokey <br/>in den Firmware-Aktualisierungs-Modus versetzt. Dies lässt sich nicht rückgängig machen!<br/>Bitte lesen Sie die <a href="https://www.nitrokey.com/en/doc/firmware-update-storage"><span style=" text-decoration: underline; color:#0000ff;">Dokumentation </span></a>um die <br/>Firmware zu aktualisieren.</p><p>Mit Firmware-Aktualisierungs-Modus fortfahren?</p><p><br/></p></body></html> + <html><head/><body><p>Wenn Sie mit &quot;OK&quot; bestätigen wird der Nitrokey <br/>in den Firmware-Aktualisierungs-Modus versetzt. Dies lässt sich nicht rückgängig machen!<br/>Bitte lesen Sie die <a href="https://www.nitrokey.com/en/doc/firmware-update-storage"><span style=" text-decoration: underline; color:#0000ff;">Dokumentation </span></a>um die <br/>Firmware zu aktualisieren.</p><p>Weiter in den Firmware-Update-Modus wechseln?</p><p><br/></p></body></html> @@ -1755,7 +1755,7 @@ Slot under which hidden volume information will be stored - Slot in dem Informationen des versteckten Volumens gespeichert werden + Eintrag in dem Informationen des versteckten Volumens gespeichert werden Use this as hidden volume size unit diff -Nru nitrokey-app-1.3.2/i18n/nitrokey_fr.ts nitrokey-app-1.4.1/i18n/nitrokey_fr.ts --- nitrokey-app-1.3.2/i18n/nitrokey_fr.ts 2018-06-26 15:47:20.000000000 +0000 +++ nitrokey-app-1.4.1/i18n/nitrokey_fr.ts 2019-09-28 16:20:07.000000000 +0000 @@ -1,6 +1,6 @@ - + AboutDialog @@ -79,7 +79,7 @@ Logo - + Logo User: @@ -133,7 +133,7 @@ (hidden) - + (caché) Not active @@ -173,7 +173,7 @@ Cannot open dialog: - + Impossible d'ouvrir le dialogue : @@ -871,7 +871,7 @@ <html><head/><body><p><span style=" font-weight:600; color:#a40000;">Entered OTP 'Secret Key' string is longer than supported by this device</span></p></body></html> Label shown when the OTP secret key is too long - + Étiquette affichée lorsque la clé secrète OTP est trop longue secret is not passing validation. @@ -879,87 +879,87 @@ Provided secret hex string is invalid. Please check input and try again. - + La chaîne hexadécimale secrète n'est pas valide. Veuillez vérifier les données saisies et réessayer. Details: - + Détails : Wrong Pin. Please try again. - + Mauvais Pin. Veuillez réessayer. Factory reset was successful. - + La réinitialisation d'usine a réussi. WARNING: This Storage firmware version is old. Application may be unresponsive and unlocking encrypted volume may not work. Please update the firmware to the latest version. Guide should be available at: <br/><a href='https://www.nitrokey.com/en/doc/firmware-update-storage'>www.nitrokey.com/en/doc/firmware-update-storage</a>. - + AVERTISSEMENT : Cette version du micrologiciel de stockage est ancienne. L'application peut ne pas répondre et le déverrouillage du volume chiffré peut ne pas fonctionner. Veuillez mettre à jour le firmware avec la dernière version. Le guide devrait être disponible à l'adresse : Nitrokey App - + Application Nitrokey Overview - + Vue d'ensemble Unlock Encrypted Volume - + Déverrouiller Volume Chiffré Unlock Hidden Volume - + Déverrouiller Volume Caché Lock Device - + Dispositif de verrouillage Help - + Aide Quit - + Quitter Copy secret to clipboard - + Copier le secret dans le presse-papiers Copy to clipboard - + Copier dans le presse-papiers Settings - + Paramètres General - + Général Show first-run message - + Afficher le message de première exécution Show warning when no partitions could be detected on Encrypted Volume (Linux only) - + Afficher un avertissement lorsqu'aucune partition n'a pu être détectée sur le volume chiffré (Linux uniquement) Show message about device's connection / disconnection - + Afficher le message concernant la connexion / déconnexion de l'appareil Show main window when device connects - + Afficher la fenêtre principale lorsque l'appareil se connecte Hide main window when device disconnects - + Masquer la fenêtre principale lorsque l'appareil se déconnecte Do not quit when the main window is closed @@ -1456,15 +1456,15 @@ &Set unencrypted volume read-write - &Rendre le volume déchiffré accessible en lecture et en écriture + &Rendre le volume déchiffré accessible en lecture-écriture &Set encrypted volume read-only - + &Définir le volume chiffré en lecture seule &Set encrypted volume read-write - + &Définir le volume chiffré en lecture-écriture &Setup hidden volume @@ -1512,11 +1512,11 @@ &Help - + &Aide &Overview - + &Vue d'ensemble @@ -1574,14 +1574,14 @@ Clear all application's settings - + Effacer tous les paramètres de l'application securitydialog Dialog - + Dialogue <html><head/><body><p align="center"><span style=" font-size:12pt; font-weight:600;">Security Information</span></p><p>Please read the following carefully.</p><p><span style=" font-weight:600;">PIN Protection</span></p><p>Nitrokey is protected by both a user PIN and an admin PIN. Your user PIN can unlock the encrypted storage, password safe, smart card and (if enabled) One-Time Passwords (OTP). OTPs aren't PIN-protected by default because they are only used as a secondary factor. The smart card is unlocked whenever the user PIN is entered, regardless of the function for which the PIN is entered. The admin PIN can be used to configure settings and to add or change entries. You must change the default PINs and keep them confidential. If the user PIN and admin PIN are entered incorrectly three times each, or if the smart card has been reset to factory settings, all your sensitive data will be permanently lost.</p><p><span style=" font-weight:600;">Physical Protection</span></p><p>All sensitive data is encrypted and secured against physical attacks. This does not apply to One-Time Passwords (OTP) because they are only used as a secondary factor.</p><p><span style=" font-weight:600;">Hidden Volumes</span></p><p>Hidden volumes require that the mass storage be initialised with random data. Hidden volumes are protected by both a user PIN and a separate password which can be different for each hidden volume. Without knowing both the user PIN and password, the hidden volume cannot be found and its existence can therefore neither be proven nor disproven. The password for the hidden volume must be strong and long enough to withstand a brute force attack. The hidden volumes are however stored on a flash storage with integrated wear levelling, meaning that information could potentially be leaked to a sophisticated attacker, thereby revealing the existence of hidden volumes.</p></body></html> diff -Nru nitrokey-app-1.3.2/i18n/nitrokey_pl.ts nitrokey-app-1.4.1/i18n/nitrokey_pl.ts --- nitrokey-app-1.3.2/i18n/nitrokey_pl.ts 2018-12-12 12:23:09.000000000 +0000 +++ nitrokey-app-1.4.1/i18n/nitrokey_pl.ts 2019-09-28 16:20:07.000000000 +0000 @@ -17,7 +17,7 @@ Firmware version: - Wersja firmware: + Wersja firmware: Card serial number: @@ -25,7 +25,7 @@ <html><head/><body><p><span style=" font-size:10pt; font-style:italic;">Copyright %1 by NitrokeyUG. </span></p><p><span style=" font-size:10pt; font-style:italic;">This software is licensed under the </span><a href="https://www.gnu.org/licenses/"><span style=" font-size:10pt; font-style:italic; text-decoration: underline; color:#c80636;">GNU General Public License v3</span></a><span style=" font-size:10pt; font-style:italic;">.</span></p><p><a href="https://nitrokey.com"><span style=" text-decoration: underline; color:#c80636;">www.nitrokey.com</span></a></p></body></html> - <html><head/><body><p><span style=" font-size:10pt; font-style:italic;">Copyright %1 by NitrokeyUG. </span></p><p><span style=" font-size:10pt; font-style:italic;">Licencja na to oprogramowanie udzielana jest na podstawie </span><a href="https://www.gnu.org/licenses/"><span style=" font-size:10pt; font-style:italic; text-decoration: underline; color:#c80636;">GNU General Public License v3.</span></a><span style=" font-size:10pt; font-style:italic;"> Tłumaczenie polskiej wersji aplikacji: Grzegorz Trzciński.</span></p><p><a href="https://nitrokey.com"><span style=" text-decoration: underline; color:#c80636;">www.nitrokey.com</span></a></p></body></html> + <html><head/><body><p><span style=" font-size:10pt; font-style:italic;">Copyright %1 by NitrokeyUG. </span></p><p><span style=" font-size:10pt; font-style:italic;">Licencja na to oprogramowanie udzielana jest na podstawie </span><a href="https://www.gnu.org/licenses/"><span style=" font-size:10pt; font-style:italic; text-decoration: underline; color:#c80636;">GNU General Public License v3</span></a><span style=" font-size:10pt; font-style:italic;">.</span></p><p><a href="https://nitrokey.com"><span style=" text-decoration: underline; color:#c80636;">www.nitrokey.com</span></a></p></body></html> <html><head/><body><p><a href="https://www.nitrokey.com/start"><span style=" text-decoration: underline; color:#c80636;">Instructions and help</span></a></p></body></html> @@ -46,8 +46,8 @@ Stick is not secure! Select Init keys. - Pamięć USB nie jest zabezpieczona! -Inicjalizuj urządzenie. + Pamięć USB nie jest bezpieczna! +Wybierz przyciski Init. New SD card found @@ -71,7 +71,7 @@ Password retry counters: - Liczniki prób ponownego podania hasła: + Pozostała liczba prób ponownego podania hasła: Admin: @@ -87,7 +87,7 @@ Detailed Status - Szczegółowy status + Status szczegółowy OK @@ -157,7 +157,7 @@ Licenses and 3rd-party components - Licencje i komponenty firm trzecich + Licencje i oprogramowanie firm trzecich *** Clearing data in progress *** @@ -194,7 +194,7 @@ DialogChangePassword Change user PIN - Zmiana kodu PIN użytkownika + Zmień kod PIN użytkownika Show PIN @@ -250,11 +250,11 @@ Current password is not correct. Please retry. - Aktualne hasło jest niepoprawne. Proszę spróbować ponownie. + Wprowadzone hasło jest niepoprawne. Spróbuj ponownie. New password is set - Nowe hasło zostało ustawione + Hasło zostało zmienione The minimum length of the old password is @@ -278,7 +278,7 @@ The new password entries are not the same - Nowe hasło nie jest takie samo w obu polach + Nowe hasło nie jest identyczne Current PIN or password @@ -290,7 +290,7 @@ <html><head/><body><p><span style=" font-style:italic;">Nitrokey prevents against brute force password guessing attacks by allowing a maximum of 3 incorrect PIN attempts. Therefore a PIN of %1 digits is sufficient. The PIN must be between %1 and %2 characters.</span></p></body></html> - <html><head/><body><p><span style=" font-style:italic;">Nitrokey zapobiega odgadywaniu ataków przy użyciu metody Brute Force, pozwalając na maksymalnie 3 nieprawidłowe próby podania kodu PIN, w związku z tym wystarczy kod PIN składający się z %1cyfr. Kod PIN musi zawierać od %1 do %2 znaków.</span></p></body></html> + <html><head/><body><p><span style=" font-style:italic;">Nitrokey zapobiega odgadywaniu haseł przy użyciu metody Brute Force, pozwalając na maksymalnie 3 nieprawidłowe próby podania kodu PIN, w związku z tym wystarczy kod PIN składający się z %1cyfr. Kod PIN musi zawierać od %1 do %2 znaków.</span></p></body></html> New PIN: @@ -314,11 +314,11 @@ The Firmware password doesn’t have a retry counter, and therefore doesn’t prevent against password guessing attacks. A secure and complex password should be created with the use of: lower and upper case letters, numbers and special characters; with a length between %2 and %3 characters.<br/>Default firmware password is: '%1'. - Hasło firmware nie posiada licznika ponownych prób, dlatego nie zapobiega odgadywania hasła metodą Brute Force. Hasło bezpieczne i złożone należy tworzyć za pomocą: małych i dużych liter, cyfr i znaków specjalnych; o długości od %2 do %3 znaków. <br/>Domyślnym hasłem firmware jest: '%1'. + Hasło firmware nie posiada licznika ponownych prób, dlatego nie zapobiega odgadywaniu hasła metodami Brute Force. Hasło bezpieczne i złożone należy tworzyć za pomocą: małych i dużych liter, cyfr i znaków specjalnych; o długości od %2 do %3 znaków. <br/>Domyślnym hasłem firmware jest: '%1'. WARNING! If you lose your Firmware password, Nitrokey can’t be updated or reset! - WARNING! W przypadku utraty hasła do firmware'u nie można zaktualizować ani zresetować Nitrokey'a! + OSTRZEŻENIE! W przypadku utraty hasła do firmware'u Nitrokey nie można zaktualizować ani zresetować Nitrokey'a! @@ -360,15 +360,15 @@ Secret key - Klucz tajny + Hasło - <html><head/><body><p>The secret is provided by your service provider you may want to login or can be configured in your local application which you may want to login to.</p></body></html> - <html><head/><body><p>Klucz tajny jest dostarczany przez usługodawcę, do którego chcesz się zalogować lub który można skonfigurować w aplikacji lokalnej, do której możesz się zalogować.</p></body></html> + <html><head/><body><p>The secret key is provided by your service provider you may want to login or can be configured in your local application which you may want to login to.</p></body></html> + <html><head/><body><p>Hasło jest dostarczane przez usługodawcę, do którego usług chcesz się zalogować lub który można skonfigurować w aplikacji lokalnej, do której możesz się zalogować.</p></body></html> Secret Key: - Klucz tajny: + Hasło: ******************************** @@ -376,19 +376,19 @@ Secret copied to clipboard - Klucz tajny skopiowano do schowka + Hasło skopiowano do schowka <html><head/><body><p>Hide or show the secret.</p></body></html> - <html><head/><body><p>Ukryj lub pokaż tajemnicę.</p></body></html> + <html><head/><body><p>Ukryj lub pokaż klucz tajny.</p></body></html> Hide secret - Ukryj klucz tajny + Ukryj hasło Generate random secret - Wygeneruj losowy klucz tajny + Wygeneruj losowe hasło Input format: @@ -400,7 +400,7 @@ Note: 2<sup>nd</sup> aren't protected against physical attacks. Change all OTP secrets in case you loose the Nitrokey. - Uwaga: Dwuskładnikowe uwierzytelnianie nie jest odporne na ataki fizyczne. Zmień wszystkie klucze tajne OTP w przypadku utraty klucza Nitrokey. + Uwaga: Dwuskładnikowe uwierzytelnianie nie jest odporne na ataki fizyczne. Zmień wszystkie klucze tajne OTP w przypadku utraty Nitrokey. Parameters @@ -408,11 +408,11 @@ Set to zero - Ustawione na zero + Ustaw wartość zero Set to random - Ustawionie na losowe + Generuj losową wartość 6 digits @@ -424,7 +424,7 @@ Moving factor seed: - + Wartość czynnika randomizacji: HOTP length: @@ -500,7 +500,7 @@ Do nothing - Nie rób nic + Nic nie rób Send HOTP1 @@ -512,7 +512,7 @@ Password Safe - Bank Haseł + Sejf Haseł Password: @@ -532,7 +532,7 @@ Generate random password - Generuj hasło losowe + Generuj losowe hasło Characters left: @@ -544,23 +544,23 @@ <html><head/><body><p>Password Safe fields support UTF8 data. It means that you can use your national characters here. Please remember however that non-English characters could take more space (up to 4 characters). The counters next to each field are to inform how much more standard English characters can given field accept.</p></body></html> - <html><head/><body><p>Pola haseł obsługują dane UTF8. Oznacza to, że można tu używać znaków narodowych. Pamiętaj jednak, że znaki nieangielskie mogą zajmować więcej miejsca (do 4 znaków). Liczniki znajdujące się obok każdego pola informują o tym, o ile więcej standardowych znaków angielskich może być wpisanych w danym polu.</p></body></html> + <html><head/><body><p>Pola Password Safe obsługują dane UTF8. Oznacza to, że można tu używać znaków narodowych. Pamiętaj jednak, że znaki nieangielskie mogą zajmować więcej miejsca (do 4 znaków). Liczniki znajdujące się obok każdego pola informują o tym, o ile więcej standardowych znaków angielskich może być akceptowanych w danym polu.</p></body></html> Unlock password safe - Odblokuj bank haseł + Odblokuj Sejf Haseł Nitrokey disconnected - Klucz Nitrokey odłączony + Klucz Nitrokey został odłączony Nitrokey Pro connected - Klucz Nitrokey Pro podłączony + Klucz Nitrokey Pro został podłączony Nitrokey Storage connected - Klucz Nitrokey Storage podłączony + Klucz Nitrokey Storage został podłączony Counter value not copied - there was an error in conversion. Setting counter value to 0. Please retry. @@ -568,7 +568,7 @@ TOTP length: - Długość TOTP: + Długość TOTP: Wrong PIN. Please try again. @@ -580,7 +580,7 @@ Factory reset was successful. - Przywrócenie ustawień fabrycznych powiodło się. + Przywrócenie ustawień fabrycznych zakończone powodzeniem. Device has been locked @@ -624,7 +624,7 @@ Slot - Slot + Slot Can't clear slot. @@ -668,13 +668,13 @@ Nitrokey connected - Klucz Nitrokey został podłączony + Nitrokey został podłączony Warning: Encrypted volume is not secure, Select "Initialize storage with random data" Ostrzeżenie: Zaszyfrowany wolumin nie jest bezpieczny, -Wybierz opcję "Inicjalizacja przy użyciu losowych danych" +Wybierz opcję "Zainicjuj urządzenie przy użyciu losowych danych" TOTP slot @@ -682,11 +682,11 @@ HOTP slot - Slot HOTP + SLot HOTP Can't unlock password safe. - Nie można odblokować banku haseł. + Nie można odblokować Sejfu Haseł. Wrong user password. @@ -694,7 +694,7 @@ Password safe [%1] - Bank haseł [%1] + Sejf Haseł [%1] Protect OTP by user PIN (will be requested on first use each session) @@ -702,7 +702,7 @@ Forget user PIN after 10 minutes (if unchecked user PIN will remain in memory until application exits) - Zapomnij kodu PIN użytkownika po 10 minutach (jeśli opcja nie jest zaznaczona, kod PIN użytkownika pozostanie w pamięci do momentu zamknięcia aplikacji) + Zapomnij kod PIN użytkownika po 10 minutach (jeśli opcja nie jest zaznaczona, kod PIN użytkownika pozostanie w pamięci do momentu zamknięcia aplikacji) Command execution failed. Please try again. @@ -718,7 +718,7 @@ Your secret is invalid. Please change the secret. - Twoje tajne hasło jest nieważne. Proszę je zmienić. + Twoje hasło jest nieprawidłowe. Proszę je zmienić. Slot successfully written. @@ -742,11 +742,11 @@ The secret is provided by your service provider you may want to login or can be configured in your local application which you may want to login to. - Tajne hasło jest dostarczane przez usługodawcę, do którego chcesz się zalogować lub którego można skonfigurować w aplikacji lokalnej, do której chcesz się zalogować. + Hasło jest dostarczane przez usługodawcę, do którego usług chcesz się zalogować lub którego można skonfigurować w aplikacji lokalnej, do której chcesz się zalogować. OTP secret key - Tajny klucz OTP + Klucz OTP Note: 2nd factors aren't protected against physical attacks. Change all OTP secrets in case you loose the Nitrokey. @@ -754,7 +754,7 @@ After generating a random secret, you would need to copy it into your application or service where you want to login to. - Po wygenerowaniu tajnego hasła, musisz skopiować je do aplikacji lub usługi, do której chcesz się zalogować. + Po wygenerowaniu hasła, musisz skopiować je do aplikacji lub usługi, do której chcesz się zalogować. Example: "ZR3M5I..." @@ -774,15 +774,15 @@ Entered OTP 'Secret Key' string is longer than supported by this device - Wpisany tajny klucz OTP jest dłuższy niż obsługiwane przez to urządzenie + Wpisany klucz OTP jest dłuższy niż obsługiwane przez to urządzenie Label shown when the OTP secret key is too long - Etykieta jest wyświetlana, gdy tajny klucz OTP jest zbyt długi + Etykieta jest wyświetlana, gdy klucz OTP jest zbyt długi HOTP moving factor seed - + HOTP wartości czynnika randomizacji Set HOTP counter to zero @@ -822,15 +822,15 @@ Erase Password Safe slot - Usuń hasło z banku haseł + Usuń Sejf Haseł ze slotu Password Safe slot number - Numer hasła w banku haseł + Numer slotu Sejfu Haseł Unlock Password Safe - Odblokuj bank haseł + Odblokuj Sejf Haseł The Nitrokey App is available as an icon in the tray bar. @@ -838,23 +838,23 @@ The secret string you have entered is invalid. Please reenter it. - Wprowadzony tajny klucz jest nieprawidłowy. Wprowadź go ponownie. + Wprowadzony ciąg znaków jest nieprawidłowy. Wprowadź go ponownie. <Select Password Safe slot> - <Wybierz slot banku haseł> + <Wybierz slot Sejfu Haseł Password safe unlocked - Bank haseł odblokowany + Sejf Haseł został odblokowany AES keys not initialized. Please provide Admin PIN. - Klucze AES nie są zainicjowane. Podaj kod PIN administratora. + Klucze AES nie są zainicjowane. Podaj kod PIN administratora Keys generated. Please unlock Password Safe again. - Klucze zostały pomyślnie wygenerowane. Ponownie odblokuj bank haseł. + Klucze zostały pomyślnie wygenerowane. Ponownie odblokuj Sejf Haseł. Wrong admin password. @@ -870,7 +870,7 @@ Locking device - Zabezpieczanie urządzenia + Blokowanie urządzenia Connecting device @@ -879,15 +879,16 @@ <html><head/><body><p><span style=" font-weight:600; color:#a40000;">Entered OTP 'Secret Key' string is longer than supported by this device</span></p></body></html> Label shown when the OTP secret key is too long - <html><head/><body><p><span style=" font-weight:600; color:#a40000;">Wpisany tajny klucz OTP jest dłuższy niż obsługiwany przez to urządzenie.</span></p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#a40000;">Wpisany klucz tajny OTP jest dłuższy niż obsługiwany przez to urządzenie.</span></p></body></html> + secret is not passing validation. - Klucz tajny nie przeszedł pomyślnie procesu sprawdzenia. + Hasło nie przeszło pomyślnie procesu sprawdzenia. Provided secret hex string is invalid. Please check input and try again. - Wprowadzony heksadecymalny klucz tajny jest błędny. Sprawdź dane i spróbuj ponownie. + Wprowadzone heksadecymalne hasło jest nieprawidłowe. Sprawdź wprowadzone dane i spróbuj ponownie. Details: @@ -895,7 +896,7 @@ WARNING: This Storage firmware version is old. Application may be unresponsive and unlocking encrypted volume may not work. Please update the firmware to the latest version. Guide should be available at: <br/><a href='https://www.nitrokey.com/en/doc/firmware-update-storage'>www.nitrokey.com/en/doc/firmware-update-storage</a>. - OSTRZEŻENIE: Ta wersja oprogramowania układowego pamięci masowej jest nieaktualna. Aplikacja może nie odpowiadać, a odblokowanie zaszyfrowanego woluminu może nie działać. Zaktualizuj oprogramowanie sprzętowe do najnowszej wersji. Poradnik jest dostępny na stronie internetowej: <br/><a href='https://www.nitrokey.com/en/doc/firmware-update-storage'>www.nitrokey.com/en/doc/firmware-update-storage</a>. + OSTRZEŻENIE: Ta wersja firmware jest nieaktualna. Aplikacja może nie odpowiadać, a odblokowanie zaszyfrowanego woluminu może nie działać. Zaktualizuj firmware do najnowszej wersji. Poradnik jest dostępny na stronie internetowej: <br/><a href='https://www.nitrokey.com/en/doc/firmware-update-storage'>www.nitrokey.com/en/doc/firmware-update-storage</a>. Nitrokey App @@ -923,11 +924,11 @@ Quit - Wyjście + Wyjdź Copy secret to clipboard - Kopiuj tajny klucz do schowka + Kopiuj hasło do schowka Copy to clipboard @@ -943,31 +944,31 @@ Show first-run message - Pokaż wiadomość startową + Pokaż informację przy pierwszym uruchomieniu Show warning when no partitions could be detected on Encrypted Volume (Linux only) - Wyświetlaj ostrzeżenia, gdy na zaszyfrowanym woluminie nie można wykryć partycji (tylko Linux) + Pokaż ostrzeżenie, gdy na zaszyfrowanym woluminie nie można wykryć partycji(tylko Linux) Show message about device's connection / disconnection - Wyświetlaj komunikat o podłączeniu/odłączeniu urządzenia + Pokaż komunikat o podłączeniu/odłączeniu urządzenia Show main window when device connects - Pokazuj okno główne programu, gdy urządzenie próbuje się podłączyć + Pokaż okno główne programu, gdy urządzenie próbuje się podłączyć Hide main window when device disconnects - Ukrywaj okno główne, gdy urządzenie próbuje się rozłączyć + Ukryj okno główne, gdy urządzenie próbuje się rozłączyć Do not quit when the main window is closed - Po kliknięciu na przycisk zamknij minimalizuj do paska systemowego i zezwól na pracę w tle + Po naciśnięciu (X) zminimalizuj program do zasobnika systemowego <html><head/><body><p>Translation file (needs restart)</p></body></html> - <html><head/><body><p>Język (wymaga ponownego uruchomienia)</p></body></html> + <html><head/><body><p>Plik tłumaczenia (wymaga ponownego uruchomienia)</p></body></html> Translation file (needs restart) @@ -1003,15 +1004,15 @@ Time to store OTP secrets in clipboard (in seconds): - Czas przechowywania haseł OTP w schowku (w sekundach): + Czas przechowywania tajnych haseł OTP w schowku (w sekundach): Time to store Password Safe secrets in clipboard (in seconds): - Czas przechowywania hasła z banku haseł w schowku (w sekundach): + Czas przechowywania haseł z Sejfu Haseł w schowku (w sekundach): TIme to store Password Safe secrets in clipboard (in seconds): - Czas przechowywania hasła z banku haseł w schowku (w sekundach): + Czas przechowywania haseł z Sejfu Haseł w schowku (w sekundach): You can find application’s tray icon in system tray in the right down corner of your screen (Windows) or in the upper right (Linux, MacOS). @@ -1023,7 +1024,7 @@ Would you like to show this message again? - Chcesz ponownie pokazywać tą wiadomość? + Chcesz ponownie pokazać tę wiadomość? Device lock detected, please remove and insert the device again. @@ -1031,11 +1032,11 @@ 1. Close the application 2. Reinsert the device 3. Wait 30 seconds and start application - Wykryto blokadę urządzenia, usuń je i włóż ponownie. + Wykryto blokadę urządzenia, wyciągnij je i włóż ponownie. Jeśli problem wystąpi ponownie, należy: -1. Zamknąć aplikację +1. Zamknąć aplikację. 2. Włożyć urządzenie ponownie. -3. Odczekać 30 sekund i uruchomić aplikację +3. Odczekać 30 sekund i uruchomić aplikację. Warning: Application could not detect any partition on the Encrypted Volume. Please use graphical GParted or terminal fdisk/parted tools for this. @@ -1055,7 +1056,7 @@ Would you like to quit now? - Na pewno chcesz wyjść? + Czy chcesz zamknąć program? Debug file location (will be overwritten) @@ -1067,17 +1068,13 @@ Communication error. Please reinsert the device. - Błąd komunikacji.Włóż urządzenie ponownie. + Błąd komunikacji. Ponownie włóż urządzenie. Warning: Encrypted volume is not secure, Select "Initialize device" option from context menu. OSTRZEŻENIE: Zaszyfrowany wolumin nie jest bezpieczny, -wybierz "Inicjalizuj urządzenie" z menu kontekstowego. - - - Note: 2<sup>nd</sup> factors aren't protected against physical attacks. Change all OTP secrets in case you loose the Nitrokey. - Uwaga: Dwuskładnikowe uwierzytelnianie nie jest odporne na ataki fizyczne. Zmień wszystkie klucze tajne OTP w przypadku utraty klucza Nitrokey. +wybierz "Zainicjalizuj urządzenie" z menu kontekstowego. @@ -1104,17 +1101,17 @@ Your PIN is too long! Use not more than 30 characters. - Kod PIN jest za długi! Należy używać nie więcej niż 30 znaków. + Kod PIN jest za długi! Należy użyć nie więcej niż 30 znaków. Your PIN is too short. Use at least 6 characters. - Kod PIN jest zbyt krótki. Należy używać co najmniej 6 znaków. + Kod PIN jest zbyt krótki. Należy użyć co najmniej 6 znaków. Warning: Default PIN is used. Please change the PIN. Ostrzeżenie: Używany jest domyślny kod PIN. -Zmień kod PIN. +Zalecana jest zmiana kodu PIN na inny. Tries left: %1 @@ -1150,7 +1147,7 @@ Enter Firmware Password: - Wprowadź hasło do firmware'u: + Wprowadź hasło do firmware'u Enter password for hidden volume @@ -1161,8 +1158,8 @@ Wprowadź hasło dla ukrytego woluminu: - Would you like to so now? - Czy chcesz to teraz zrobić? + Would you like to do it now? + Czy chcesz zrobić to teraz? Please enter the new PIN/password @@ -1195,15 +1192,15 @@ Enabling encrypted volume - Uruchamianie szyfrowanego woluminu + Uruchamianie zaszyfrowanego woluminu Encrypted volume enabled - Szyfrowany wolumin uruchomiony + Zaszyfrowany wolumin uruchomiony Could not enable encrypted volume. - Nie można uruchomić szyfrowanego woluminu. + Nie można uruchomić zaszyfrowanego woluminu. Wrong password. @@ -1273,11 +1270,11 @@ Device set in update mode - Urządzenie ustawione w trybie do aktualizacji + Urządzenie ustawione w trybie "do aktualizacji" Device could not be set in update mode. - Urządzenie nie mogło być ustawione w trybie do aktualizacji. + Urządzenie nie mogło być ustawione w trybie "do aktualizacji". Firmware exported @@ -1285,11 +1282,11 @@ Could not export firmware. - Nie można wyeksportować firmware. + Nie można wyeksportować firmware'u. WARNING: Generating new AES keys will destroy the encrypted volumes, hidden volumes, and password safe! Continue? - OSTRZEŻENIE: Wygenerowanie nowych kluczy AES spowoduje zniszczenie zaszyfrowanych woluminów, ukrytych woluminów i usunięcie danych z banku haseł! Kontynuować? + OSTRZEŻENIE: Wygenerowanie nowych kluczy AES spowoduje zniszczenie zaszyfrowanych woluminów, ukrytych woluminów i danych w Sejfie Haseł! Kontynuować? Generating new AES keys @@ -1301,7 +1298,7 @@ Keys could not be generated. - Nie udało się wygenerować kluczy. + Nie udało się wygenerować kluczy AES. Could not clear SD card. @@ -1329,19 +1326,19 @@ Cannot set unencrypted volume read-write - Nie udało się ustawić niezaszyfrowanego woluminu jako tylko do odczytu + Nie udało się ustawić niezaszyfrowanego woluminu jako do odczytu i zapisu Unencrypted volume set read-write - Niezaszyfrowany wolumin ustawiony jako tylko do odczytu + Niezaszyfrowany wolumin ustawiony jako do odczytu i zapisu Cannot set encrypted volume read-only - Nie można ustawić szyfrowanego woluminu jako tylko do odczytu + Nie można ustawić zaszyfrowanego woluminu jako tylko do odczytu Encrypted volume set read-only - Zaszyfrowany wolumin ustawiono jako tylko do odczytu + Zaszyfrowany wolumin ustawiono jako do odczytu i zapisu Cannot set encrypted volume read-write @@ -1380,11 +1377,11 @@ Nitrokey is not connected! - Klucz Nitrokey nie jest podłączony! + Nitrokey nie jest podłączony! Unlock password safe - Odblokowanie banku haseł + Odblokowanie Sejfu Haseł &OTP @@ -1408,7 +1405,7 @@ &Quit - &Wyjście + &Wyjdź &Help @@ -1420,7 +1417,7 @@ &OTP and Password safe - &OTP i bank haseł + &OTP i Password Safe &Unlock encrypted volume @@ -1448,19 +1445,19 @@ &Export firmware to file - &Eksport firmware do pliku + &Eksportuj firmware do pliku &Destroy encrypted data - &Niszczenie zaszyfrowanych danych + &Zniszcz zaszyfrowane dane &Initialize device - &Inicjalizacja urządzenia + &Inicjalizuj urządzenie &Initialize storage with random data - &Inicjalizacja pamięci masowej z losowymi danymi + &Inicjalizuj pamięć masową z losowymi danymi &Set unencrypted volume read-only @@ -1484,11 +1481,11 @@ &Disable 'initialize storage with random data' warning - &Wyłączenie ostrzeżenia o 'inicjalizacji pamięci masowej losowymi danymi' + &Wyłącz ostrzeżenia o 'inicjalizacji pamięci masowej losowymi danymi' &Lock stick hardware - &Zablokuj sprzętowo dysk USB + &Zablokuj dysk USB &Reset User PIN @@ -1516,11 +1513,11 @@ Special Configure - Konfiguracja specjalna + Ustawienia zaawansowane Long operation in progress: %1% - Długa operacja w toku: %1% + Operacja w toku: %1% &Overview @@ -1535,7 +1532,7 @@ <html><head/><body><p>When you select &quot;OK&quot; the device enters the <br/>firmware update mode. There is no way back!<br/>Please read the <a href="https://www.nitrokey.com/en/doc/firmware-update-storage"><span style=" text-decoration: underline; color:#0000ff;">documentation </span></a>how to <br/>update the firmware.</p><p>Continue entering the firmware update mode?</p><p><br/></p></body></html> - <html><head/><body><p>W momencie wyboru &quot; OK&quot; urządzenie wchodzi w tryb do aktualizacji oprogramowania <br/>. Nie ma od tego odwrotu!<br/>Przeczytaj <a href="https://www.nitrokey.com/en/doc/firmware-update-storage"><span style=" text-decoration: underline; color:#0000ff;">dokumentację </span></a>aby <br/>zaktualizować firmware.</p><p>Kontynuować przejście w tryb do aktualizacji firmware?'?</p><p><br/></p></body></html> + <html><head/><body><p>W momencie wyboru &quot; OK&quot; urządzenie przechodzi w tryb do aktualizacji oprogramowania <br/>. Operacja ta jest nieodwracalna!<br/>Przeczytaj <a href="https://www.nitrokey.com/en/doc/firmware-update-storage"><span style=" text-decoration: underline; color:#0000ff;">dokumentację </span></a>aby <br/>zaktualizować firmware.</p><p>Kontynuować przejście w tryb do aktualizacji firmware?'?</p><p><br/></p></body></html> @@ -1546,15 +1543,15 @@ Enable debug messages - Włączanie komunikatów o debugowaniu + Włącz komunikaty o debugowaniu Save debug log to file with name <log-file-name> (experimental) - Zapisywanie logu debugowania do pliku o nazwie <nazwa logu> (funkcja eksperymentalna) + Zapisz log debugowania do pliku o nazwie <nazwa logu> (funkcja eksperymentalna) Save debug log to App's window (experimental) - Zapisywanie logu debugowania w oknie aplikacji (funkcja eksperymentalna) + Zapisz log debugowania w oknie aplikacji (funkcja eksperymentalna) Set delay between commands sent to device (in ms) to <delay> @@ -1574,11 +1571,11 @@ Load translation file with given name and store this choice in settings file. - Wczytaj plik z tłumaczeniem o podanej nazwie i zapisz ten wybór w pliku ustawień. + Wczytaj plik z tłumaczeniem o podanej nazwie i zapisz ten wybór w pliku ustawień Set debug level, 0-4 - Ustawianie poziomu debugowania, 0-4 + Ustaw poziom szczegółowości debugowania, 0-4 Clear all application's settings @@ -1593,7 +1590,7 @@ <html><head/><body><p align="center"><span style=" font-size:12pt; font-weight:600;">Security Information</span></p><p>Please read the following carefully.</p><p><span style=" font-weight:600;">PIN Protection</span></p><p>Nitrokey is protected by both a user PIN and an admin PIN. Your user PIN can unlock the encrypted storage, password safe, smart card and (if enabled) One-Time Passwords (OTP). OTPs aren't PIN-protected by default because they are only used as a secondary factor. The smart card is unlocked whenever the user PIN is entered, regardless of the function for which the PIN is entered. The admin PIN can be used to configure settings and to add or change entries. You must change the default PINs and keep them confidential. If the user PIN and admin PIN are entered incorrectly three times each, or if the smart card has been reset to factory settings, all your sensitive data will be permanently lost.</p><p><span style=" font-weight:600;">Physical Protection</span></p><p>All sensitive data is encrypted and secured against physical attacks. This does not apply to One-Time Passwords (OTP) because they are only used as a secondary factor.</p><p><span style=" font-weight:600;">Hidden Volumes</span></p><p>Hidden volumes require that the mass storage be initialised with random data. Hidden volumes are protected by both a user PIN and a separate password which can be different for each hidden volume. Without knowing both the user PIN and password, the hidden volume cannot be found and its existence can therefore neither be proven nor disproven. The password for the hidden volume must be strong and long enough to withstand a brute force attack. The hidden volumes are however stored on a flash storage with integrated wear levelling, meaning that information could potentially be leaked to a sophisticated attacker, thereby revealing the existence of hidden volumes.</p></body></html> - <html><head/><body><p align="center"><span style=" font-size:12pt; font-weight:600;">Informacje na temat bezpieczeństwa</span></p><p>Prosimy o uważne zapoznanie się z poniższymi informacjami.</p><p><span style=" font-weight:600;">Ochrona kodu PIN</span></p><p>Nitrokey jest chroniony zarówno kodem PIN użytkownika, jak i kodem PIN administratora. Kod PIN użytkownika może odblokować zaszyfrowany nośnik, sejf z hasłami, kartę inteligentną i (jeśli jest włączone) hasła jednorazowe (OTP). Hasła jednorazowe nie są domyślnie chronione kodem PIN, ponieważ są używane tylko jako drugi poziom zabezpieczeń. Karta inteligentna jest odblokowywana po wprowadzeniu kodu PIN użytkownika, niezależnie od funkcji, którą dana karta spełnia. Za pomocą kodu PIN administratora można konfigurować ustawienia oraz dodawać lub zmieniać wpisy. Należy obowiązkowo zmienić domyślne kody PIN i zadbać o ich bezpieczne przechowywanie. W przypadku trzykrotnego nieprawidłowego wprowadzenia kodu PIN użytkownika i kodu PIN administratora lub w przypadku przywrócenia ustawień fabrycznych karty inteligentnej, wszystkie wrażliwe dane zostaną trwale utracone.</p><p><span style=" font-weight:600;">Ochrona fizyczna</span></p><p>Wszystkie dane wrażliwe są szyfrowane i zabezpieczone przed atakami fizycznymi. Nie dotyczy to haseł jednorazowych (OTP), ponieważ są one używane tylko jako drugi poziom zabezpieczeń.</p><p><span style=" font-weight:600;">Ukryte woluminy</span></p><p>Ukryte woluminy wymagają inicjalizacji pamięci masowej losowymi danymi. Woluminy ukryte są chronione zarówno kodem PIN użytkownika, jak i oddzielnym hasłem, które może być różne dla każdego ukrytego woluminu. Nie znając jednocześnie kodu PIN użytkownika i hasła, nie można zamontować ukrytego woluminu, w związku z tym nie można udowodnić ani obalić jego istnienia. Hasło do ukrytego woluminu musi być silne i wystarczająco długie, aby wytrzymać brutalny atak siłowy. Ukryte woluminy są jednakże przechowywane w pamięci flash z funkcją zintegrowanego wyrównywania zużycia, co oznacza, że pewne informacje mogą zostać potencjalnie ujawnione zaawansowanemu podmiotowi atakującemu, ukazując w ten sposób istnienie ukrytych woluminów.</p></body></html> + <html><head/><body><p align="center"><span style=" font-size:12pt; font-weight:600;">Informacje na temat bezpieczeństwa</span></p><p>Prosimy o uważne zapoznanie się z poniższymi informacjami.</p><p><span style=" font-weight:600;">Ochrona kodu PIN</span></p><p>Nitrokey jest chroniony zarówno kodem PIN użytkownika, jak i kodem PIN administratora. Kod PIN użytkownika może odblokować zaszyfrowany nośnik, Password Safe, kartę inteligentną i (jeśli są włączone) hasła jednorazowe (OTP). Hasła jednorazowe nie są domyślnie chronione kodem PIN, ponieważ są używane tylko jako drugi poziom zabezpieczeń. Karta inteligentna jest odblokowywana po wprowadzeniu kodu PIN użytkownika, niezależnie od funkcji, którą ta karta spełnia. Za pomocą kodu PIN administratora można konfigurować ustawienia oraz dodawać lub zmieniać wpisy. Należy obowiązkowo zmienić domyślne kody PIN i zadbać o ich bezpieczne przechowywanie. W przypadku trzykrotnego nieprawidłowego wprowadzenia kodu PIN użytkownika i kodu PIN administratora lub w przypadku przywrócenia ustawień fabrycznych karty inteligentnej, wszystkie dane zostaną trwale utracone.</p><p><span style=" font-weight:600;">Ochrona fizyczna</span></p><p>Wszystkie dane wrażliwe są szyfrowane i zabezpieczone przed atakami fizycznymi. Nie dotyczy to haseł jednorazowych (OTP), ponieważ są one używane tylko jako drugi poziom zabezpieczeń.</p><p><span style=" font-weight:600;">Ukryte woluminy</span></p><p>Ukryte woluminy wymagają inicjalizacji pamięci masowej losowymi danymi. Woluminy ukryte są chronione zarówno kodem PIN użytkownika, jak i oddzielnym hasłem, które może być różne dla każdego ukrytego woluminu. Nie znając jednocześnie kodu PIN użytkownika i hasła, nie można zamontować ukrytego woluminu, w związku z tym nie można udowodnić ani obalić jego istnienia. Hasło do ukrytego woluminu musi być silne i wystarczająco długie, aby wytrzymać brutalny atak siłowy. Ukryte woluminy są jednakże przechowywane w pamięci flash z funkcją zintegrowanego wyrównywania zużycia, co oznacza, że pewne informacje mogą zostać potencjalnie ujawnione zaawansowanemu podmiotowi atakującemu, ukazując w ten sposób istnienie ukrytych woluminów.</p></body></html> OK @@ -1612,7 +1609,7 @@ <html><head/><body><p><span style=" font-weight:600;">You should understand the properties of hidden volumes before proceeding. It can destroy your encrypted data! <br/>Please read </span><a href="https://www.nitrokey.com/documentation/hidden-volumes"><span style=" font-weight:600; text-decoration: underline; color:#0000ff;">these instructions</span></a><span style=" font-weight:600;"> first.</span></p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Zanim przejdziesz do kolejnego etapu, powinieneś w pełni rozumieć właściwości ukrytych woluminów. W przeciwnym razie narażasz się na zniszczenie zaszyfrowanych danych! <br/>Przeczytaj artykuł: </span><a href="https://www.nitrokey.com/documentation/hidden-volumes"><span style=" font-weight:600; text-decoration: underline; color:#0000ff;">niniejsza instrukcja</span></a><span style=" font-weight:600;"> przed kontynuowaniem.</span></p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Zanim przejdziesz do kolejnego etapu, powinieneś w pełni rozumieć właściwości ukrytych woluminów. W przeciwnym razie narażasz się na zniszczenie zaszyfrowanych danych! <br/>Przeczytaj </span><a href="https://www.nitrokey.com/documentation/hidden-volumes"><span style=" font-weight:600; text-decoration: underline; color:#0000ff;">niniejszą instrukcję</span></a><span style=" font-weight:600;"> przed kontynuowaniem.</span></p></body></html> <html><head/><body><p>1. You may want to copy some innocuous files to the encrypted data.<br/>2. Configure hidden volumes in this dialogue. <br/>3. Once you configured a hidden volume you must not use/write to the encryption volume anymore. Otherwise it may destroy the data in your hidden volume.</p></body></html> @@ -1648,7 +1645,7 @@ Hidden Volume settings - Ustawienia woluminów ukrytych + Ustawienia ukrytych woluminów Hidden volume slot 1 @@ -1676,11 +1673,11 @@ Your password is too short. Use at least 8 characters. - Twoje hasło jest zbyt krótkie. Należy używać co najmniej 8 znaków. + Hasło jest zbyt krótkie. Użyj co najmniej 8 znaków. The passwords are not identical - Hasła nie są identyczne w obu polach + Wprowadzone hasła nie są identyczne! Wrong size of hidden volume @@ -1708,23 +1705,23 @@ Very Weak - Bardzo słaby + Bardzo słabe Weak - Słaby + Słabe Medium - Średni + Średnie Strong - Silny + Silne Very Strong - Bardzo silny + Bardzo silne The unwritten area available for hidden volume @@ -1738,19 +1735,19 @@ Start hidden volume at %1 of the encrypted storage: - Rozpocznij ukryty wolumin od %1 zaszyfrowanej pamięci masowej: + Rozpocznij tworzenie ukrytego woluminu od %1 zaszyfrowanej pamięci masowej: End hidden volume at %1 of the encrypted storage: - Zakończ ukryty wolumin w %1 zaszyfrowanej pamięci masowej: + Zakończ tworzenie ukrytego woluminu w %1 zaszyfrowanej pamięci masowej: Hidden volume password - Hasło ukrytego woluminu + Hasło do ukrytego woluminu Please use shift+tab key shortcut for instructions - Instrukcje można uzyskać za pomocą skrótu klawiszowego shift+TAB + Aby uzyskać instrukcje użyj skrótu klawiszowego Shift+Tab Hidden volume password (repeated) @@ -1777,7 +1774,7 @@ <html><head/><body><p>When you select &quot;OK&quot; the stick lock the firmware and close the hardware debug port.This disables any external hardware access to the data in the device (processor).</p><p>There is no way back! </p><p>After this you can't update the firmware.</p></body></html> - <html><head/><body><p>Po wybraniu &quot;OK&quot; dysk USB zablokuje firmware i zamknie port debugowania.Wyłącza to wszelki zewnętrzny dostęp sprzętowy do danych w urządzeniu (procesor).</p><p>Nie ma drogi powrotnej! </p><p>Dodatkowo zablokowana zostaje możliwość aktualizacji firmware.</p></body></html> + <html><head/><body><p>Po wybraniu &quot;OK&quot; program zablokuje firmware i zamknie port debugowania. Wyłącza to wszelki zewnętrzny dostęp sprzętowy do danych w urządzeniu.</p><p>Operacja jest nieodwracalna!</p><p>Dodatkowo zablokowana zostanie możliwość aktualizacji firmware.</p></body></html> diff -Nru nitrokey-app-1.3.2/images/new/icon_unsafe.svg nitrokey-app-1.4.1/images/new/icon_unsafe.svg --- nitrokey-app-1.3.2/images/new/icon_unsafe.svg 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/images/new/icon_unsafe.svg 2019-09-28 16:20:07.000000000 +0000 @@ -0,0 +1,56 @@ + + + +image/svg+xml + + + + + \ No newline at end of file diff -Nru nitrokey-app-1.3.2/libnitrokey/build/.gitignore nitrokey-app-1.4.1/libnitrokey/build/.gitignore --- nitrokey-app-1.3.2/libnitrokey/build/.gitignore 2017-12-28 14:01:52.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/build/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -* diff -Nru nitrokey-app-1.3.2/libnitrokey/CMakeLists.txt nitrokey-app-1.4.1/libnitrokey/CMakeLists.txt --- nitrokey-app-1.3.2/libnitrokey/CMakeLists.txt 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/CMakeLists.txt 2019-09-28 16:22:11.000000000 +0000 @@ -21,7 +21,7 @@ ENDIF() ENDIF() -project(libnitrokey LANGUAGES C CXX VERSION 3.3.0) +project(libnitrokey LANGUAGES C CXX VERSION 3.5.0) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -66,7 +66,9 @@ NitrokeyManager.cc NK_C_API.h NK_C_API.cc - DeviceCommunicationExceptions.cpp) + DeviceCommunicationExceptions.cpp + ${CMAKE_CURRENT_BINARY_DIR}/version.cc + ) set(BUILD_SHARED_LIBS ON CACHE BOOL "Build all libraries as shared") add_library(nitrokey ${SOURCE_FILES}) @@ -95,7 +97,7 @@ OPTION(ERROR_ON_WARNING "Stop compilation on warning found (not supported for MSVC)" OFF) if (NOT MSVC) - set(COMPILE_FLAGS "-Wall -Wno-unused-function -Wcast-qual -Woverloaded-virtual") + set(COMPILE_FLAGS "-Wall -Wno-unused-function -Wcast-qual -Woverloaded-virtual -Wsign-compare -Wformat -Wformat-security") IF(NOT APPLE) if (ERROR_ON_WARNING) set(COMPILE_FLAGS "${COMPILE_FLAGS} -Werror") @@ -115,6 +117,25 @@ ENDIF() +OPTION(ADD_GIT_INFO "Add information about source code version from Git repository" TRUE) +# generate version.h +IF(ADD_GIT_INFO) +execute_process( + COMMAND git describe --always --abbrev=4 HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE PROJECT_VERSION_GIT_RETURN_CODE + OUTPUT_VARIABLE PROJECT_VERSION_GIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET +) +ENDIF() +IF((NOT ${ADD_GIT_INFO}) OR (${PROJECT_VERSION_GIT_RETURN_CODE})) + SET(PROJECT_VERSION_GIT "v${PROJECT_VERSION}") +ENDIF() +MESSAGE(STATUS "Setting Git library version to: " ${PROJECT_VERSION_GIT} ) +configure_file("version.cc.in" "version.cc" @ONLY) + + file(GLOB LIB_INCLUDES "libnitrokey/*.h" "NK_C_API.h") install (FILES ${LIB_INCLUDES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) install (TARGETS nitrokey DESTINATION ${CMAKE_INSTALL_LIBDIR}) @@ -135,7 +156,7 @@ ENDIF() install(FILES - ${CMAKE_SOURCE_DIR}/data/41-nitrokey.rules + ${CMAKE_CURRENT_SOURCE_DIR}/data/41-nitrokey.rules DESTINATION ${CMAKE_INSTALL_UDEVRULESDIR} ) ENDIF() @@ -150,7 +171,7 @@ IF(COMPILE_OFFLINE_TESTS OR COMPILE_TESTS) find_package(PkgConfig) IF(PKG_CONFIG_FOUND) - pkg_check_modules(CATCH2 catch) + pkg_check_modules(CATCH2 catch2) ENDIF() if (CATCH2_FOUND) @@ -167,34 +188,38 @@ IF(COMPILE_OFFLINE_TESTS) add_executable (test_offline unittest/test_offline.cc) target_link_libraries (test_offline ${EXTRA_LIBS} nitrokey catch) + SET_TARGET_PROPERTIES(test_offline PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} ) #run with 'make test' or 'ctest' include (CTest) add_test (runs test_offline) + + add_executable(test_minimal unittest/test_minimal.c) + target_link_libraries(test_minimal ${EXTRA_LIBS} nitrokey) + add_test(minimal test_minimal) ENDIF() IF (COMPILE_TESTS) - #needs connected PRO device for success - #warning: it may delete data on the device - add_executable (test_C_API unittest/test_C_API.cpp) - target_link_libraries (test_C_API ${EXTRA_LIBS} nitrokey catch) + #needs connected Pro/Storage devices for success + #WARNING: it may delete data on the device - add_executable (test2 unittest/test2.cc) - target_link_libraries (test2 ${EXTRA_LIBS} nitrokey catch) - - add_executable (test3 unittest/test3.cc) - target_link_libraries (test3 ${EXTRA_LIBS} nitrokey catch) - - add_executable (test_HOTP unittest/test_HOTP.cc) - target_link_libraries (test_HOTP ${EXTRA_LIBS} nitrokey catch) - - add_executable (test1 unittest/test.cc) - target_link_libraries (test1 ${EXTRA_LIBS} nitrokey catch) - - add_executable (test_issues unittest/test_issues.cc) - target_link_libraries (test_issues ${EXTRA_LIBS} nitrokey catch) - - add_executable (test_multiple_devices unittest/test_multiple_devices.cc) - target_link_libraries (test_multiple_devices ${EXTRA_LIBS} nitrokey catch) + SET(TESTS + unittest/test_C_API.cpp + unittest/test2.cc + unittest/test3.cc + unittest/test_HOTP.cc + unittest/test1.cc + unittest/test_issues.cc + unittest/test_multiple_devices.cc + unittest/test_strdup.cpp + unittest/test_safe.cpp + ) + + foreach(testsourcefile ${TESTS} ) + get_filename_component(testname ${testsourcefile} NAME_WE ) + add_executable(${testname} ${testsourcefile} ) + target_link_libraries(${testname} ${EXTRA_LIBS} nitrokey catch ) + SET_TARGET_PROPERTIES(${testname} PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} ) + endforeach(testsourcefile) ENDIF() @@ -208,3 +233,12 @@ "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set (CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") include (CPack) + +# Build Doxygen documentation for the C API +find_package(Doxygen) +if (DOXYGEN_FOUND) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) + add_custom_target(doc ${DOXYGEN_EXECUTABLE} Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating C API documentation with Doxygen" VERBATIM) +endif(DOXYGEN_FOUND) diff -Nru nitrokey-app-1.3.2/libnitrokey/command_id.cc nitrokey-app-1.4.1/libnitrokey/command_id.cc --- nitrokey-app-1.3.2/libnitrokey/command_id.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/command_id.cc 2019-09-28 16:22:11.000000000 +0000 @@ -71,6 +71,10 @@ return "CHANGE_USER_PIN"; case CommandID::CHANGE_ADMIN_PIN: return "CHANGE_ADMIN_PIN"; + case CommandID::FIRMWARE_UPDATE: + return "FIRMWARE_UPDATE"; + case CommandID::FIRMWARE_PASSWORD_CHANGE: + return "FIRMWARE_PASSWORD_CHANGE"; case CommandID::ENABLE_CRYPTED_PARI: return "ENABLE_CRYPTED_PARI"; @@ -173,10 +177,10 @@ return "NEW_AES_KEY"; case CommandID::WRITE_TO_SLOT_2: return "WRITE_TO_SLOT_2"; - break; case CommandID::SEND_OTP_DATA: return "SEND_OTP_DATA"; - break; + case CommandID::WINK: + return "WINK"; } return "UNKNOWN"; } diff -Nru nitrokey-app-1.3.2/libnitrokey/data/41-nitrokey_old.rules nitrokey-app-1.4.1/libnitrokey/data/41-nitrokey_old.rules --- nitrokey-app-1.3.2/libnitrokey/data/41-nitrokey_old.rules 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/data/41-nitrokey_old.rules 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,56 @@ +# +# Copyright (c) 2015-2019 Nitrokey UG +# +# This file is part of libnitrokey. +# +# libnitrokey is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# any later version. +# +# libnitrokey is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with libnitrokey. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0 +# + +# Here rules in old style should be provided. Matching devices should be added to 'plugdev' group, +# and with mode set to "0660". +# File prefix number should be lower than 73, to be correctly processed by the Udev. +# Recommended udev version: < 188. +# +ACTION!="add|change", GOTO="u2f_end" + +# Nitrokey U2F +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", MODE="0660", GROUP+="plugdev" +# Nitrokey FIDO U2F +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", MODE="0660", GROUP+="plugdev" + +LABEL="u2f_end" + + +SUBSYSTEM!="usb", GOTO="gnupg_rules_end" +ACTION!="add", GOTO="gnupg_rules_end" + +# USB SmartCard Readers +## Crypto Stick 1.2 +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev" +## Nitrokey Pro +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4108", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev" +## Nitrokey Storage +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4109", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev" +## Nitrokey Start +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4211", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev" +## Nitrokey HSM +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev" + +LABEL="gnupg_rules_end" + + +# Nitrokey Storage dev Entry +KERNEL=="sd?1", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4109", SYMLINK+="nitrospace" diff -Nru nitrokey-app-1.3.2/libnitrokey/data/41-nitrokey.rules nitrokey-app-1.4.1/libnitrokey/data/41-nitrokey.rules --- nitrokey-app-1.3.2/libnitrokey/data/41-nitrokey.rules 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/data/41-nitrokey.rules 2019-09-28 16:22:11.000000000 +0000 @@ -1,20 +1,52 @@ +# +# Copyright (c) 2015-2019 Nitrokey UG +# +# This file is part of libnitrokey. +# +# libnitrokey is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# any later version. +# +# libnitrokey is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with libnitrokey. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0 +# + +# Here rules in new style should be provided. Matching devices should be tagged with 'uaccess'. +# File prefix number should be lower than 73, to be correctly processed by the Udev. +# Recommended udev version: >= 188. +# +ACTION!="add|change", GOTO="u2f_end" + # Nitrokey U2F -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0" +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess" +# Nitrokey FIDO U2F +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess" + +LABEL="u2f_end" + SUBSYSTEM!="usb", GOTO="gnupg_rules_end" ACTION!="add", GOTO="gnupg_rules_end" # USB SmartCard Readers ## Crypto Stick 1.2 -ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", GROUP+="plugdev", TAG+="uaccess" +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess" ## Nitrokey Pro -ATTR{idVendor}=="20a0", ATTR{idProduct}=="4108", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", GROUP+="plugdev", TAG+="uaccess" +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4108", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess" ## Nitrokey Storage -ATTR{idVendor}=="20a0", ATTR{idProduct}=="4109", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", GROUP+="plugdev", TAG+="uaccess" +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4109", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess" ## Nitrokey Start -ATTR{idVendor}=="20a0", ATTR{idProduct}=="4211", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", GROUP+="plugdev", TAG+="uaccess" +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4211", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess" ## Nitrokey HSM -ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", GROUP+="plugdev", TAG+="uaccess" +ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess" LABEL="gnupg_rules_end" diff -Nru nitrokey-app-1.3.2/libnitrokey/device.cc nitrokey-app-1.4.1/libnitrokey/device.cc --- nitrokey-app-1.3.2/libnitrokey/device.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/device.cc 2019-09-28 16:22:11.000000000 +0000 @@ -20,7 +20,9 @@ */ #include +#include #include +#include #include #include #include @@ -36,11 +38,42 @@ using namespace nitrokey::device; using namespace nitrokey::log; +using namespace nitrokey::misc; using namespace std::chrono; +const uint16_t nitrokey::device::NITROKEY_VID = 0x20a0; +const uint16_t nitrokey::device::NITROKEY_PRO_PID = 0x4108; +const uint16_t nitrokey::device::NITROKEY_STORAGE_PID = 0x4109; + +Option nitrokey::device::product_id_to_model(uint16_t product_id) { + switch (product_id) { + case NITROKEY_PRO_PID: + return DeviceModel::PRO; + case NITROKEY_STORAGE_PID: + return DeviceModel::STORAGE; + default: + return {}; + } +} + std::atomic_int Device::instances_count{0}; std::chrono::milliseconds Device::default_delay {0} ; +std::ostream& nitrokey::device::operator<<(std::ostream& stream, DeviceModel model) { + switch (model) { + case DeviceModel::PRO: + stream << "Pro"; + break; + case DeviceModel::STORAGE: + stream << "Storage"; + break; + default: + stream << "Unknown"; + break; + } + return stream; +} + Device::Device(const uint16_t vid, const uint16_t pid, const DeviceModel model, const milliseconds send_receive_delay, const int retry_receiving_count, const milliseconds retry_timeout) @@ -69,8 +102,10 @@ LOG(std::string(__FUNCTION__) + std::string(m_model == DeviceModel::PRO ? "PRO" : "STORAGE"), Loglevel::DEBUG_L2); LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2); - LOG(std::string("Disconnection: handle already freed: ") + std::to_string(mp_devhandle == nullptr) + " ("+m_path+")", Loglevel::DEBUG_L1); - if(mp_devhandle == nullptr) return false; + if(mp_devhandle == nullptr) { + LOG(std::string("Disconnection: handle already freed: ") + std::to_string(mp_devhandle == nullptr) + " ("+m_path+")", Loglevel::DEBUG_L1); + return false; + } hid_close(mp_devhandle); mp_devhandle = nullptr; @@ -169,14 +204,20 @@ return status; } -std::vector Device::enumerate(){ - //TODO make static - auto pInfo = hid_enumerate(m_vid, m_pid); +std::vector Device::enumerate(){ + auto pInfo = hid_enumerate(NITROKEY_VID, 0); auto pInfo_ = pInfo; - std::vector res; + std::vector res; while (pInfo != nullptr){ - std::string a (pInfo->path); - res.push_back(a); + auto deviceModel = product_id_to_model(pInfo->product_id); + if (deviceModel.has_value()) { + std::string path(pInfo->path); + std::wstring serialNumberW(pInfo->serial_number); + std::wstring_convert> converter; + std::string serialNumber = converter.to_bytes(serialNumberW); + DeviceInfo info = { deviceModel.value(), path, serialNumber }; + res.push_back(info); + } pInfo = pInfo->next; } @@ -187,6 +228,17 @@ return res; } +std::shared_ptr Device::create(DeviceModel model) { + switch (model) { + case DeviceModel::PRO: + return std::make_shared(); + case DeviceModel::STORAGE: + return std::make_shared(); + default: + return {}; + } +} + bool Device::could_be_enumerated() { LOG(__FUNCTION__, Loglevel::DEBUG_L2); std::lock_guard lock(mex_dev_com); @@ -241,14 +293,14 @@ } Stick10::Stick10(): - Device(0x20a0, 0x4108, DeviceModel::PRO, 100ms, 5, 100ms) + Device(NITROKEY_VID, NITROKEY_PRO_PID, DeviceModel::PRO, 100ms, 5, 100ms) { setDefaultDelay(); } Stick20::Stick20(): - Device(0x20a0, 0x4109, DeviceModel::STORAGE, 40ms, 55, 40ms) + Device(NITROKEY_VID, NITROKEY_STORAGE_PID, DeviceModel::STORAGE, 40ms, 55, 40ms) { setDefaultDelay(); } diff -Nru nitrokey-app-1.3.2/libnitrokey/Doxyfile.in nitrokey-app-1.4.1/libnitrokey/Doxyfile.in --- nitrokey-app-1.3.2/libnitrokey/Doxyfile.in 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/Doxyfile.in 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,17 @@ +# For better readability, the documentation and default settings are removed +# from this file. For more information on the Doxygen configuration, generate +# a new Doxyfile using `doxygen -g` or have a look at the Doxygen manual at +# http://www.doxygen.nl/manual/config.html +# +# This file is processed by CMake. To generate the documentation, run `make +# doc` in the build directory. + +PROJECT_NAME = "@CMAKE_PROJECT_NAME@" +PROJECT_NUMBER = "@PROJECT_VERSION@" +PROJECT_BRIEF = +OUTPUT_DIRECTORY = doc +STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@ +JAVADOC_AUTOBRIEF = YES +OPTIMIZE_OUTPUT_FOR_C = YES +WARN_NO_PARAMDOC = YES +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/NK_C_API.h diff -Nru nitrokey-app-1.3.2/libnitrokey/.gitignore nitrokey-app-1.4.1/libnitrokey/.gitignore --- nitrokey-app-1.3.2/libnitrokey/.gitignore 2017-12-28 14:01:52.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/.gitignore 2019-09-28 16:22:11.000000000 +0000 @@ -2,6 +2,7 @@ *.log *.o unittest/build/ +unittest/.pytest_cache/ *.pyc core .cache/ diff -Nru nitrokey-app-1.3.2/libnitrokey/.idea/vcs.xml nitrokey-app-1.4.1/libnitrokey/.idea/vcs.xml --- nitrokey-app-1.3.2/libnitrokey/.idea/vcs.xml 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/.idea/vcs.xml 2019-09-28 16:22:11.000000000 +0000 @@ -2,5 +2,7 @@ + + \ No newline at end of file diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/command_id.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/command_id.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/command_id.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/command_id.h 2019-09-28 16:22:11.000000000 +0000 @@ -88,6 +88,8 @@ CHANGE_ADMIN_PIN = 0x15, WRITE_TO_SLOT_2 = 0x16, SEND_OTP_DATA = 0x17, + FIRMWARE_UPDATE = 0x19, + FIRMWARE_PASSWORD_CHANGE = 0x1A, ENABLE_CRYPTED_PARI = 0x20, DISABLE_CRYPTED_PARI = 0x20 + 1, @@ -130,6 +132,8 @@ ENABLE_ADMIN_READONLY_ENCRYPTED_LUN = 0x20 + 30, ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN = 0x20 + 31, CHECK_SMARTCARD_USAGE = 0x20 + 32, + //v0.52+ + WINK = 0x20 + 33, GET_PW_SAFE_SLOT_STATUS = 0x60, GET_PW_SAFE_SLOT_NAME = 0x61, diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/deprecated.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/deprecated.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/deprecated.h 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/deprecated.h 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + + +#ifndef LIBNITROKEY_DEPRECATED_H +#define LIBNITROKEY_DEPRECATED_H + +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: DEPRECATED macro is not defined for this compiler") +#define DEPRECATED +#endif + +#endif //LIBNITROKEY_DEPRECATED_H diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/device.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/device.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/device.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/device.h 2019-09-28 16:22:11.000000000 +0000 @@ -24,8 +24,11 @@ #include #include "hidapi/hidapi.h" #include +#include #include +#include #include +#include "misc.h" #define HID_REPORT_SIZE 65 @@ -50,6 +53,48 @@ STORAGE }; +std::ostream& operator<<(std::ostream& stream, DeviceModel model); + +/** + * The USB vendor ID for Nitrokey devices. + */ +extern const uint16_t NITROKEY_VID; +/** + * The USB product ID for the Nitrokey Pro. + */ +extern const uint16_t NITROKEY_PRO_PID; +/** + * The USB product ID for the Nitrokey Storage. + */ +extern const uint16_t NITROKEY_STORAGE_PID; + +/** + * Convert the given USB product ID to a Nitrokey model. If there is no model + * with that ID, return an absent value. + */ +misc::Option product_id_to_model(uint16_t product_id); + +/** + * Information about a connected device. + * + * This struct contains the information about a connected device returned by + * hidapi when enumerating the connected devices. + */ +struct DeviceInfo { + /** + * The model of the connected device. + */ + DeviceModel m_deviceModel; + /** + * The USB connection path for the device. + */ + std::string m_path; + /** + * The serial number of the device. + */ + std::string m_serialNumber; +}; + #include class Device { @@ -106,7 +151,17 @@ * @return true if visible by OS */ bool could_be_enumerated(); - std::vector enumerate(); + /** + * Returns a vector with all connected Nitrokey devices. + * + * @return information about all connected devices + */ + static std::vector enumerate(); + + /** + * Create a Device of the given model. + */ + static std::shared_ptr create(DeviceModel model); void show_stats(); diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/log.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/log.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/log.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/log.h 2019-09-28 16:22:11.000000000 +0000 @@ -46,6 +46,7 @@ class LogHandler { public: virtual void print(const std::string &, Loglevel lvl) = 0; + virtual ~LogHandler() = default; protected: std::string loglevel_to_str(Loglevel); std::string format_message_to_string(const std::string &str, const Loglevel &lvl); diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/misc.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/misc.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/misc.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/misc.h 2019-09-28 16:22:11.000000000 +0000 @@ -29,12 +29,37 @@ #include "log.h" #include "LibraryException.h" #include +#include #include namespace nitrokey { namespace misc { +/** + * Simple replacement for std::optional (C++17). + */ +template +class Option { +public: + Option() : m_hasValue(false), m_value() {} + Option(T value) : m_hasValue(true), m_value(value) {} + + bool has_value() const { + return m_hasValue; + } + T value() const { + if (!m_hasValue) { + throw std::logic_error("Called Option::value without value"); + } + return m_value; + } + +private: + bool m_hasValue; + T m_value; +}; + template std::string toHex(T value){ using namespace std; @@ -42,7 +67,8 @@ oss << std::hex << std::setw(sizeof(value)*2) << std::setfill('0') << value; return oss.str(); } - + +#define FIELD_WIDTH_MAX (100) /** * Copies string from pointer to fixed size C-style array. Src needs to be a valid C-string - eg. ended with '\0'. * Throws when source is bigger than destination. @@ -57,12 +83,13 @@ // throw EmptySourceStringException(slot_number); return; const size_t s_dest = sizeof dest; - LOG(std::string("strcpyT sizes dest src ") - +std::to_string(s_dest)+ " " - +std::to_string(strlen(src))+ " " - ,nitrokey::log::Loglevel::DEBUG_L2); - if (strlen(src) > s_dest){ - throw TooLongStringException(strlen(src), s_dest, src); + const size_t src_strlen = strnlen(src, FIELD_WIDTH_MAX); + LOG(std::string("strcpyT sizes dest src ") + + std::to_string(s_dest) + " " + + std::to_string(src_strlen) + " " + , nitrokey::log::Loglevel::DEBUG_L2); + if (src_strlen > s_dest){ + throw TooLongStringException(src_strlen, s_dest, src); } strncpy((char*) &dest, src, s_dest); } diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/NitrokeyManager.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/NitrokeyManager.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/NitrokeyManager.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/NitrokeyManager.h 2019-09-28 16:22:11.000000000 +0000 @@ -65,10 +65,22 @@ stick10::ReadSlot::ResponsePayload get_HOTP_slot_data(const uint8_t slot_number); bool set_time(uint64_t time); + /** + * Set the device time used for TOTP to the given time. Contrary to + * {@code set_time(uint64_t)}, this command fails if {@code old_time} + * > {@code time} or if {@code old_time} is zero (where {@code + * old_time} is the current time on the device). + * + * @param time new device time as Unix timestamp (seconds since + * 1970-01-01) + */ + void set_time_soft(uint64_t time); + + [[deprecated("get_time is deprecated -- use set_time_soft instead")]] bool get_time(uint64_t time = 0); bool erase_totp_slot(uint8_t slot_number, const char *temporary_password); bool erase_hotp_slot(uint8_t slot_number, const char *temporary_password); - std::vector list_devices(); + std::vector list_devices(); std::vector list_devices_by_cpuID(); /** @@ -93,8 +105,8 @@ string get_status_as_string(); string get_serial_number(); - const char * get_totp_slot_name(uint8_t slot_number); - const char * get_hotp_slot_name(uint8_t slot_number); + char * get_totp_slot_name(uint8_t slot_number); + char * get_hotp_slot_name(uint8_t slot_number); void change_user_PIN(const char *current_PIN, const char *new_PIN); void change_admin_PIN(const char *current_PIN, const char *new_PIN); @@ -108,9 +120,9 @@ void lock_device(); - const char *get_password_safe_slot_name(uint8_t slot_number); - const char *get_password_safe_slot_password(uint8_t slot_number); - const char *get_password_safe_slot_login(uint8_t slot_number); + char * get_password_safe_slot_name(uint8_t slot_number); + char * get_password_safe_slot_password(uint8_t slot_number); + char * get_password_safe_slot_login(uint8_t slot_number); void write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login, @@ -187,10 +199,10 @@ void send_startup(uint64_t seconds_from_epoch); - const char * get_status_storage_as_string(); + char * get_status_storage_as_string(); stick20::DeviceConfigurationResponsePacket::ResponsePayload get_status_storage(); - const char *get_SD_usage_data_as_string(); + char * get_SD_usage_data_as_string(); std::pair get_SD_usage_data(); @@ -203,7 +215,7 @@ template void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); - int get_minor_firmware_version(); + uint8_t get_minor_firmware_version(); explicit NitrokeyManager(); void set_log_function(std::function log_function); @@ -227,7 +239,7 @@ uint8_t get_internal_slot_number_for_hotp(uint8_t slot_number) const; uint8_t get_internal_slot_number_for_totp(uint8_t slot_number) const; bool erase_slot(uint8_t slot_number, const char *temporary_password); - const char * get_slot_name(uint8_t slot_number); + char * get_slot_name(uint8_t slot_number); template void change_PIN_general(const char *current_PIN, const char *new_PIN); @@ -266,7 +278,7 @@ */ void set_encrypted_volume_read_write(const char *admin_pin); - int get_major_firmware_version(); + uint8_t get_major_firmware_version(); bool is_smartcard_in_use(); @@ -276,6 +288,18 @@ * @return Returns true, if set unencrypted volume ro/rw pin type is User, false otherwise. */ bool set_unencrypted_volume_rorw_pin_type_user(); + + /** + * Blink red and green LED alternatively and infinitely (until device is reconnected). + */ + void wink(); + + stick20::ProductionTest::ResponsePayload production_info(); + + void enable_firmware_update_pro(const char *firmware_pin); + + void change_firmware_update_password_pro(const char *firmware_pin_current, const char *firmware_pin_new); + bool is_internal_hotp_slot_number(uint8_t slot_number) const; }; } diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/stick10_commands.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/stick10_commands.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/stick10_commands.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/stick10_commands.h 2019-09-28 16:22:11.000000000 +0000 @@ -304,8 +304,13 @@ class ReadSlot : Command { public: + enum class CounterFormat { + ASCII = 0, + BINARY = 1, + }; struct CommandPayload { uint8_t slot_number; + CounterFormat data_format; //Storage v0.54+ only: slot_counter value format: 0 - in ascii, 1 - binary bool isValid() const { return !(slot_number & 0xF0); } @@ -882,6 +887,41 @@ }; +class FirmwareUpdate : Command { +public: + struct CommandPayload { + uint8_t firmware_password[20]; + std::string dissect() const { + std::stringstream ss; + print_to_ss_volatile(firmware_password); + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + +}; + +class FirmwarePasswordChange : Command { +public: + struct CommandPayload { + uint8_t firmware_password_current[20]; + uint8_t firmware_password_new[20]; + std::string dissect() const { + std::stringstream ss; + print_to_ss_volatile(firmware_password_current); + print_to_ss_volatile(firmware_password_new); + return ss.str(); + } + } __packed; + + typedef Transaction + CommandTransaction; + +}; + + } } } diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/stick20_commands.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/stick20_commands.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/stick20_commands.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/stick20_commands.h 2019-09-28 16:22:11.000000000 +0000 @@ -275,6 +275,12 @@ CommandTransaction; }; + class Wink : Command { + public: + typedef Transaction + CommandTransaction; + }; + class CheckSmartcardUsage : Command { public: typedef Transaction diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey/version.h nitrokey-app-1.4.1/libnitrokey/libnitrokey/version.h --- nitrokey-app-1.3.2/libnitrokey/libnitrokey/version.h 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey/version.h 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#ifndef LIBNITROKEY_VERSION_H +#define LIBNITROKEY_VERSION_H + +namespace nitrokey { + unsigned int get_major_library_version(); + + unsigned int get_minor_library_version(); + + const char* get_library_version(); +} + +#endif diff -Nru nitrokey-app-1.3.2/libnitrokey/libnitrokey.pro nitrokey-app-1.4.1/libnitrokey/libnitrokey.pro --- nitrokey-app-1.3.2/libnitrokey/libnitrokey.pro 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/libnitrokey.pro 2019-09-28 16:22:11.000000000 +0000 @@ -7,7 +7,7 @@ TEMPLATE = lib TARGET = nitrokey -VERSION = 3.3 +VERSION = 3.5.0 QMAKE_TARGET_COMPANY = Nitrokey QMAKE_TARGET_PRODUCT = libnitrokey QMAKE_TARGET_DESCRIPTION = Communicate with Nitrokey stick devices in a clean and easy manner @@ -25,6 +25,7 @@ $$PWD/libnitrokey/dissect.h \ $$PWD/libnitrokey/LibraryException.h \ $$PWD/libnitrokey/log.h \ + $$PWD/libnitrokey/version.h \ $$PWD/libnitrokey/LongOperationInProgressException.h \ $$PWD/libnitrokey/misc.h \ $$PWD/libnitrokey/NitrokeyManager.h \ @@ -39,6 +40,7 @@ $$PWD/device.cc \ $$PWD/DeviceCommunicationExceptions.cpp \ $$PWD/log.cc \ + $$PWD/version.cc \ $$PWD/misc.cc \ $$PWD/NitrokeyManager.cc \ $$PWD/NK_C_API.cc diff -Nru nitrokey-app-1.3.2/libnitrokey/meson.build nitrokey-app-1.4.1/libnitrokey/meson.build --- nitrokey-app-1.3.2/libnitrokey/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/meson.build 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,173 @@ +project( + 'libnitrokey', 'cpp', + version : '3.4.1', + license : 'LGPL-3.0+', + default_options : [ + 'cpp_std=c++14' + ], + meson_version : '>= 0.44.0', +) +cxx = meson.get_compiler('cpp') +host_system = host_machine.system() +pkg = import('pkgconfig') + +common_flags = [ + '-Wno-unused-function', + '-Wcast-qual', +] +test_cxxflags = common_flags + [ + '-Woverloaded-virtual', +] +test_cflags = common_flags +add_project_arguments(cxx.get_supported_arguments(test_cxxflags), language : 'cpp') +if get_option('offline-tests') + add_languages('c', required: get_option('offline-tests')) + c = meson.get_compiler('c') + add_project_arguments(c.get_supported_arguments(test_cflags), language : 'c') +endif + +dep_hidapi = dependency('hidapi-libusb') + +inc_libnitrokey = include_directories('libnitrokey') +libnitrokey_args = [] +if not get_option('log') + libnitrokey_args += ['-DNO_LOG'] +endif +if get_option('log-volatile-data') + libnitrokey_args += ['-DLOG_VOLATILE_DATA'] +endif + +version_array = meson.project_version().split('.') +version_major = version_array[0].to_int() +version_minor = version_array[1].to_int() +version_data = configuration_data() +version_data.set('PROJECT_VERSION_MAJOR', version_major) +version_data.set('PROJECT_VERSION_MINOR', version_minor) +# We don't want to substitute it by noop +version_data.set('PROJECT_VERSION_GIT', '@VCS_TAG@') +version_cc_in = configure_file( + input : 'version.cc.in', + output : 'version.cc.in', + configuration : version_data, +) +version_cc = vcs_tag( + input : version_cc_in, + output : 'version.cc', + fallback : 'v@0@'.format(meson.project_version()), +) +libnitrokey = library( + 'nitrokey', + sources : [ + 'command_id.cc', + 'device.cc', + 'log.cc', + version_cc, + 'misc.cc', + 'NitrokeyManager.cc', + 'NK_C_API.cc', + 'DeviceCommunicationExceptions.cpp', + ], + include_directories : [ + inc_libnitrokey, + ], + dependencies : [ + dep_hidapi, + ], + cpp_args : libnitrokey_args, + version : meson.project_version(), + install : true, +) +install_headers( + 'libnitrokey/CommandFailedException.h', + 'libnitrokey/command.h', + 'libnitrokey/command_id.h', + 'libnitrokey/cxx_semantics.h', + 'libnitrokey/DeviceCommunicationExceptions.h', + 'libnitrokey/device.h', + 'libnitrokey/device_proto.h', + 'libnitrokey/dissect.h', + 'libnitrokey/LibraryException.h', + 'libnitrokey/log.h', + 'libnitrokey/LongOperationInProgressException.h', + 'libnitrokey/misc.h', + 'libnitrokey/version.h', + 'libnitrokey/NitrokeyManager.h', + 'libnitrokey/stick10_commands_0.8.h', + 'libnitrokey/stick10_commands.h', + 'libnitrokey/stick20_commands.h', + subdir : meson.project_name(), +) + +ext_libnitrokey = declare_dependency( + link_with : libnitrokey, + include_directories : inc_libnitrokey, +) + +pkg.generate( + name : meson.project_name(), + filebase : 'libnitrokey-1', + libraries : libnitrokey, + version : meson.project_version(), + requires_private : 'hidapi-libusb', + description : 'Library for communicating with Nitrokey in a clean and easy manner', + install : true, +) + +dep_udev = dependency('udev') +install_data( + 'data/41-nitrokey.rules', + install_dir : '@0@/rules.d'.format(dep_udev.get_pkgconfig_variable('udevdir')), +) + +if get_option('tests') or get_option('offline-tests') + dep_catch = dependency('catch2', version : '>=2.3.0', required : false) + if not dep_catch.found() + dep_catch = declare_dependency( + include_directories : include_directories('unittest/Catch/single_include') + ) + endif + _catch = static_library( + 'catch', + sources : [ + 'unittest/catch_main.cpp', + ], + dependencies : [ + dep_catch, + ], + ) + _dep_catch = declare_dependency( + link_with : _catch, + dependencies : dep_catch, + ) +endif + +tests = [] +if get_option('offline-tests') + tests += [ + ['test_offline', 'test_offline.cc'], + ['test_minimal', 'test_minimal.c'], + ] +endif +if get_option('tests') + tests += [ + ['test_C_API', 'test_C_API.cpp'], + ['test1', 'test1.cc'], + ['test2', 'test2.cc'], + ['test3', 'test3.cc'], + ['test_HOTP', 'test_HOTP.cc'], + ['test_issues', 'test_issues.cc'], + ] +endif +foreach tst : tests + test( + tst[0], + executable( + tst[0], + sources : 'unittest/@0@'.format(tst[1]), + dependencies : [ + ext_libnitrokey, + _dep_catch, + ], + ) + ) +endforeach diff -Nru nitrokey-app-1.3.2/libnitrokey/meson_options.txt nitrokey-app-1.4.1/libnitrokey/meson_options.txt --- nitrokey-app-1.3.2/libnitrokey/meson_options.txt 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/meson_options.txt 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,4 @@ +option('log', type : 'boolean', value : true, description : 'Logging functionality') +option('log-volatile-data', type : 'boolean', value : false, description : 'Log volatile data (debug)') +option('tests', type : 'boolean', value : false, description : 'Compile tests (needs connected PRO device)') +option('offline-tests', type : 'boolean', value : false, description : 'Compile offline tests') diff -Nru nitrokey-app-1.3.2/libnitrokey/NitrokeyManager.cc nitrokey-app-1.4.1/libnitrokey/NitrokeyManager.cc --- nitrokey-app-1.3.2/libnitrokey/NitrokeyManager.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/NitrokeyManager.cc 2019-09-28 16:22:11.000000000 +0000 @@ -29,6 +29,7 @@ #include "libnitrokey/misc.h" #include #include "libnitrokey/cxx_semantics.h" +#include "libnitrokey/misc.h" #include #include @@ -105,11 +106,10 @@ return true; } - std::vector NitrokeyManager::list_devices(){ + std::vector NitrokeyManager::list_devices(){ std::lock_guard lock(mex_dev_com_manager); - auto p = make_shared(); - return p->enumerate(); // make static + return Device::enumerate(); } std::vector NitrokeyManager::list_devices_by_cpuID(){ @@ -127,11 +127,13 @@ LOGD1("Enumerating devices"); std::vector res; - auto d = make_shared(); - const auto v = d->enumerate(); + const auto v = Device::enumerate(); LOGD1("Discovering IDs"); - for (auto & p: v){ - d = make_shared(); + for (auto & i: v){ + if (i.m_deviceModel != DeviceModel::STORAGE) + continue; + auto p = i.m_path; + auto d = make_shared(); LOGD1( std::string("Found: ") + p ); d->set_path(p); try{ @@ -215,7 +217,26 @@ } } - auto p = make_shared(); + auto info_ptr = hid_enumerate(NITROKEY_VID, 0); + auto first_info_ptr = info_ptr; + if (!info_ptr) + return false; + + misc::Option model; + while (info_ptr && !model.has_value()) { + if (path == std::string(info_ptr->path)) { + model = product_id_to_model(info_ptr->product_id); + } + info_ptr = info_ptr->next; + } + hid_free_enumeration(first_info_ptr); + + if (!model.has_value()) + return false; + + auto p = Device::create(model.value()); + if (!p) + return false; p->set_path(path); if(!p->connect()) return false; @@ -234,12 +255,14 @@ bool NitrokeyManager::connect() { std::lock_guard lock(mex_dev_com_manager); vector< shared_ptr > devices = { make_shared(), make_shared() }; + bool connected = false; for( auto & d : devices ){ if (d->connect()){ device = std::shared_ptr(d); + connected = true; } } - return device != nullptr; + return connected; } @@ -420,6 +443,7 @@ return ""; } + bool NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; } bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; } bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } //15 uint8_t NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); } @@ -630,12 +654,12 @@ auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload); } - const char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { + char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); slot_number = get_internal_slot_number_for_totp(slot_number); return get_slot_name(slot_number); } - const char * NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) { + char * NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) { if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); slot_number = get_internal_slot_number_for_hotp(slot_number); return get_slot_name(slot_number); @@ -643,7 +667,7 @@ static const int max_string_field_length = 2*1024; //storage's status string is ~1k - const char * NitrokeyManager::get_slot_name(uint8_t slot_number) { + char * NitrokeyManager::get_slot_name(uint8_t slot_number) { auto payload = get_payload(); payload.slot_number = slot_number; auto resp = GetSlotName::CommandTransaction::run(device, payload); @@ -666,11 +690,15 @@ return false; } - bool NitrokeyManager::get_time(uint64_t time) { + void NitrokeyManager::set_time_soft(uint64_t time) { auto p = get_payload(); p.reset = 0; p.time = time; SetTime::CommandTransaction::run(device, p); + } + + bool NitrokeyManager::get_time(uint64_t time) { + set_time_soft(time); return true; } @@ -749,7 +777,7 @@ LockDevice::CommandTransaction::run(device); } - const char *NitrokeyManager::get_password_safe_slot_name(uint8_t slot_number) { + char * NitrokeyManager::get_password_safe_slot_name(uint8_t slot_number) { if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); auto p = get_payload(); p.slot_number = slot_number; @@ -759,7 +787,7 @@ bool NitrokeyManager::is_valid_password_safe_slot_number(uint8_t slot_number) const { return slot_number < 16; } - const char *NitrokeyManager::get_password_safe_slot_login(uint8_t slot_number) { + char * NitrokeyManager::get_password_safe_slot_login(uint8_t slot_number) { if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); auto p = get_payload(); p.slot_number = slot_number; @@ -767,7 +795,7 @@ return strndup((const char *) response.data().slot_login, max_string_field_length); } - const char *NitrokeyManager::get_password_safe_slot_password(uint8_t slot_number) { + char * NitrokeyManager::get_password_safe_slot_password(uint8_t slot_number) { if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); auto p = get_payload(); p.slot_number = slot_number; @@ -879,16 +907,16 @@ //authorization command is supported for versions equal or below: auto m = std::unordered_map({ {DeviceModel::PRO, 7}, - {DeviceModel::STORAGE, 999}, + {DeviceModel::STORAGE, 53}, }); return get_minor_firmware_version() <= m[device->get_device_model()]; } bool NitrokeyManager::is_320_OTP_secret_supported(){ - //authorization command is supported for versions equal or below: + // 320 bit OTP secret is supported by version bigger or equal to: auto m = std::unordered_map({ {DeviceModel::PRO, 8}, - {DeviceModel::STORAGE, 999}, + {DeviceModel::STORAGE, 54}, }); return get_minor_firmware_version() >= m[device->get_device_model()]; } @@ -910,7 +938,7 @@ return false; } - int NitrokeyManager::get_minor_firmware_version(){ + uint8_t NitrokeyManager::get_minor_firmware_version(){ switch(device->get_device_model()){ case DeviceModel::PRO:{ auto status_p = GetStatus::CommandTransaction::run(device); @@ -926,7 +954,7 @@ } return 0; } - int NitrokeyManager::get_major_firmware_version(){ + uint8_t NitrokeyManager::get_major_firmware_version(){ switch(device->get_device_model()){ case DeviceModel::PRO:{ auto status_p = GetStatus::CommandTransaction::run(device); @@ -1059,7 +1087,7 @@ stick20::ChangeUpdatePassword::CommandTransaction::run(device, p); } - const char * NitrokeyManager::get_status_storage_as_string(){ + char * NitrokeyManager::get_status_storage_as_string(){ auto p = stick20::GetDeviceStatus::CommandTransaction::run(device); return strndup(p.data().dissect().c_str(), max_string_field_length); } @@ -1069,7 +1097,7 @@ return p.data(); } - const char * NitrokeyManager::get_SD_usage_data_as_string(){ + char * NitrokeyManager::get_SD_usage_data_as_string(){ auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device); return strndup(p.data().dissect().c_str(), max_string_field_length); } @@ -1093,11 +1121,31 @@ return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password); } + /** + * Returns ReadSlot structure, describing OTP slot configuration. Always return binary counter - + * does the necessary conversion, if needed, to unify the behavior across Pro and Storage. + * @private For internal use only + * @param slot_number which OTP slot to use (usual format) + * @return ReadSlot structure + */ stick10::ReadSlot::ResponsePayload NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) { auto p = get_payload(); p.slot_number = slot_number; + p.data_format = stick10::ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+ auto data = stick10::ReadSlot::CommandTransaction::run(device, p); - return data.data(); + + auto &payload = data.data(); + + // if fw <=v0.53 and asked binary - do the conversion from ASCII + if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53 + && is_internal_hotp_slot_number(slot_number)) + { + //convert counter from string to ull + auto counter_s = std::string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s)); + payload.slot_counter = std::stoull(counter_s); + } + + return payload; } stick10::ReadSlot::ResponsePayload NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) { @@ -1105,13 +1153,7 @@ } stick10::ReadSlot::ResponsePayload NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) { - auto slot_data = get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number)); - if (device->get_device_model() == DeviceModel::STORAGE){ - //convert counter from string to ull - auto counter_s = std::string(slot_data.slot_counter_s, slot_data.slot_counter_s+sizeof(slot_data.slot_counter_s)); - slot_data.slot_counter = std::stoull(counter_s); - } - return slot_data; + return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number)); } void NitrokeyManager::lock_encrypted_volume() { @@ -1131,5 +1173,27 @@ return current_device_id; } + void NitrokeyManager::wink(){ + stick20::Wink::CommandTransaction::run(device); + }; + + stick20::ProductionTest::ResponsePayload NitrokeyManager::production_info(){ + auto data = stick20::ProductionTest::CommandTransaction::run(device); + return data.data(); + }; + + void NitrokeyManager::enable_firmware_update_pro(const char *firmware_pin) { + auto p = get_payload(); + strcpyT(p.firmware_password, firmware_pin); + FirmwareUpdate::CommandTransaction::run(device, p); + } + + void + NitrokeyManager::change_firmware_update_password_pro(const char *firmware_pin_current, const char *firmware_pin_new) { + auto p = get_payload(); + strcpyT(p.firmware_password_current, firmware_pin_current); + strcpyT(p.firmware_password_new, firmware_pin_new); + FirmwarePasswordChange::CommandTransaction::run(device, p); + } } diff -Nru nitrokey-app-1.3.2/libnitrokey/NK_C_API.cc nitrokey-app-1.4.1/libnitrokey/NK_C_API.cc --- nitrokey-app-1.3.2/libnitrokey/NK_C_API.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/NK_C_API.cc 2019-09-28 16:22:11.000000000 +0000 @@ -21,10 +21,14 @@ #include "NK_C_API.h" #include +#include #include "libnitrokey/NitrokeyManager.h" #include #include "libnitrokey/LibraryException.h" #include "libnitrokey/cxx_semantics.h" +#include "libnitrokey/stick20_commands.h" +#include "libnitrokey/device_proto.h" +#include "libnitrokey/version.h" #ifdef _MSC_VER #ifdef _WIN32 @@ -41,6 +45,7 @@ using namespace nitrokey; +const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT; static uint8_t NK_last_command_status = 0; static const int max_string_field_length = 100; @@ -52,11 +57,11 @@ return d; } -template -uint8_t * get_with_array_result(T func){ +template +std::tuple get_with_status(T func, R fallback) { NK_last_command_status = 0; try { - return func(); + return std::make_tuple(0, func()); } catch (CommandFailedException & commandFailedException){ NK_last_command_status = commandFailedException.last_command_status; @@ -67,43 +72,26 @@ catch (const DeviceCommunicationException &deviceException){ NK_last_command_status = 256-deviceException.getType(); } - return nullptr; + return std::make_tuple(NK_last_command_status, fallback); } template -const char* get_with_string_result(T func){ - NK_last_command_status = 0; - try { - return func(); - } - catch (CommandFailedException & commandFailedException){ - NK_last_command_status = commandFailedException.last_command_status; - } - catch (LibraryException & libraryException){ - NK_last_command_status = libraryException.exception_id(); - } - catch (const DeviceCommunicationException &deviceException){ - NK_last_command_status = 256-deviceException.getType(); +uint8_t * get_with_array_result(T func){ + return std::get<1>(get_with_status(func, nullptr)); +} + +template +char* get_with_string_result(T func){ + auto result = std::get<1>(get_with_status(func, nullptr)); + if (result == nullptr) { + return strndup("", MAXIMUM_STR_REPLY_LENGTH); } - return ""; + return result; } template auto get_with_result(T func){ - NK_last_command_status = 0; - try { - return func(); - } - catch (CommandFailedException & commandFailedException){ - NK_last_command_status = commandFailedException.last_command_status; - } - catch (LibraryException & libraryException){ - NK_last_command_status = libraryException.exception_id(); - } - catch (const DeviceCommunicationException &deviceException){ - NK_last_command_status = 256-deviceException.getType(); - } - return static_cast(0); + return std::get<1>(get_with_status(func, static_cast(0))); } template @@ -170,6 +158,7 @@ case NK_STORAGE: model_string = "S"; break; + case NK_DISCONNECTED: default: /* no such enum value -- return error code */ return 0; @@ -238,22 +227,69 @@ } + NK_C_API enum NK_device_model NK_get_device_model() { + auto m = NitrokeyManager::instance(); + try { + auto model = m->get_connected_device_model(); + switch (model) { + case DeviceModel::PRO: + return NK_PRO; + case DeviceModel::STORAGE: + return NK_STORAGE; + default: + /* unknown or not connected device */ + return NK_device_model::NK_DISCONNECTED; + } + } catch (const DeviceNotConnected& e) { + return NK_device_model::NK_DISCONNECTED; + } +} + + void clear_string(std::string &s) { std::fill(s.begin(), s.end(), ' '); } - NK_C_API const char * NK_status() { + NK_C_API char * NK_status() { + return NK_get_status_as_string(); + } + + NK_C_API char * NK_get_status_as_string() { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { string && s = m->get_status_as_string(); - char * rs = strndup(s.c_str(), max_string_field_length); + char * rs = strndup(s.c_str(), MAXIMUM_STR_REPLY_LENGTH); clear_string(s); return rs; }); } - NK_C_API const char * NK_device_serial_number() { + NK_C_API int NK_get_status(struct NK_status* out) { + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_status(); + }, proto::stick10::GetStatus::ResponsePayload()); + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } + + auto status = std::get<1>(result); + out->firmware_version_major = status.firmware_version_st.major; + out->firmware_version_minor = status.firmware_version_st.minor; + out->serial_number_smart_card = status.card_serial_u32; + out->config_numlock = status.numlock; + out->config_capslock = status.capslock; + out->config_scrolllock = status.scrolllock; + out->otp_user_password = status.enable_user_password != 0; + return 0; + } + + NK_C_API char * NK_device_serial_number() { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { string && s = m->get_serial_number(); @@ -263,11 +299,11 @@ }); } - NK_C_API const char * NK_get_hotp_code(uint8_t slot_number) { + NK_C_API char * NK_get_hotp_code(uint8_t slot_number) { return NK_get_hotp_code_PIN(slot_number, ""); } - NK_C_API const char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password) { + NK_C_API char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { string && s = m->get_HOTP_code(slot_number, user_temporary_password); @@ -277,12 +313,12 @@ }); } - NK_C_API const char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + NK_C_API char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, uint8_t last_interval) { return NK_get_totp_code_PIN(slot_number, challenge, last_totp_time, last_interval, ""); } - NK_C_API const char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + NK_C_API char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, uint8_t last_interval, const char *user_temporary_password) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { @@ -327,14 +363,14 @@ }); } - NK_C_API const char* NK_get_totp_slot_name(uint8_t slot_number) { + NK_C_API char* NK_get_totp_slot_name(uint8_t slot_number) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { const auto slot_name = m->get_totp_slot_name(slot_number); return slot_name; }); } - NK_C_API const char* NK_get_hotp_slot_name(uint8_t slot_number) { + NK_C_API char* NK_get_hotp_slot_name(uint8_t slot_number) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { const auto slot_name = m->get_hotp_slot_name(slot_number); @@ -353,6 +389,18 @@ m->set_loglevel(level); } + NK_C_API unsigned int NK_get_major_library_version() { + return get_major_library_version(); + } + + NK_C_API unsigned int NK_get_minor_library_version() { + return get_minor_library_version(); + } + + NK_C_API const char* NK_get_library_version() { + return get_library_version(); + } + NK_C_API int NK_totp_set_time(uint64_t time) { auto m = NitrokeyManager::instance(); return get_without_result([&]() { @@ -360,11 +408,15 @@ }); } - NK_C_API int NK_totp_get_time() { + NK_C_API int NK_totp_set_time_soft(uint64_t time) { auto m = NitrokeyManager::instance(); return get_without_result([&]() { - m->get_time(0); // FIXME check how that should work + m->set_time_soft(time); }); + } + + NK_C_API int NK_totp_get_time() { + return 0; } NK_C_API int NK_change_admin_PIN(const char *current_PIN, const char *new_PIN) { @@ -417,20 +469,20 @@ }); } - NK_C_API const char *NK_get_password_safe_slot_name(uint8_t slot_number) { + NK_C_API char *NK_get_password_safe_slot_name(uint8_t slot_number) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { return m->get_password_safe_slot_name(slot_number); }); } - NK_C_API const char *NK_get_password_safe_slot_login(uint8_t slot_number) { + NK_C_API char *NK_get_password_safe_slot_login(uint8_t slot_number) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { return m->get_password_safe_slot_login(slot_number); }); } - NK_C_API const char *NK_get_password_safe_slot_password(uint8_t slot_number) { + NK_C_API char *NK_get_password_safe_slot_password(uint8_t slot_number) { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { return m->get_password_safe_slot_password(slot_number); @@ -589,14 +641,101 @@ }); } - NK_C_API const char* NK_get_status_storage_as_string() { + NK_C_API char* NK_get_status_storage_as_string() { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { return m->get_status_storage_as_string(); }); } - NK_C_API const char* NK_get_SD_usage_data_as_string() { + NK_C_API int NK_get_status_storage(NK_storage_status* out) { + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_status_storage(); + }, proto::stick20::DeviceConfigurationResponsePacket::ResponsePayload()); + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } + + auto status = std::get<1>(result); + out->unencrypted_volume_read_only = status.ReadWriteFlagUncryptedVolume_u8 != 0; + out->unencrypted_volume_active = status.VolumeActiceFlag_st.unencrypted; + out->encrypted_volume_read_only = status.ReadWriteFlagCryptedVolume_u8 != 0; + out->encrypted_volume_active = status.VolumeActiceFlag_st.encrypted; + out->hidden_volume_read_only = status.ReadWriteFlagHiddenVolume_u8 != 0; + out->hidden_volume_active = status.VolumeActiceFlag_st.hidden; + out->firmware_version_major = status.versionInfo.major; + out->firmware_version_minor = status.versionInfo.minor; + out->firmware_locked = status.FirmwareLocked_u8 != 0; + out->serial_number_sd_card = status.ActiveSD_CardID_u32; + out->serial_number_smart_card = status.ActiveSmartCardID_u32; + out->user_retry_count = status.UserPwRetryCount; + out->admin_retry_count = status.AdminPwRetryCount; + out->new_sd_card_found = status.NewSDCardFound_st.NewCard; + out->filled_with_random = (status.SDFillWithRandomChars_u8 & 0x01) != 0; + out->stick_initialized = status.StickKeysNotInitiated == 0; + return 0; + } + + NK_C_API int NK_get_storage_production_info(NK_storage_ProductionTest * out){ + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->production_info(); + }, proto::stick20::ProductionTest::ResponsePayload()); + + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } + + stick20::ProductionTest::ResponsePayload status = std::get<1>(result); + // Cannot use memcpy without declaring C API struct packed + // (which is not parsed by Python's CFFI apparently), hence the manual way. +#define a(x) out->x = status.x; + a(FirmwareVersion_au8[0]); + a(FirmwareVersion_au8[1]); + a(FirmwareVersionInternal_u8); + a(SD_Card_Size_u8); + a(CPU_CardID_u32); + a(SmartCardID_u32); + a(SD_CardID_u32); + a(SC_UserPwRetryCount); + a(SC_AdminPwRetryCount); + a(SD_Card_ManufacturingYear_u8); + a(SD_Card_ManufacturingMonth_u8); + a(SD_Card_OEM_u16); + a(SD_WriteSpeed_u16); + a(SD_Card_Manufacturer_u8); +#undef a + return 0; + } + + NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out) { + if (out == nullptr) + return -1; + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_SD_usage_data(); + }, std::make_pair(0, 0)); + auto error_code = std::get<0>(result); + if (error_code != 0) + return error_code; + + auto data = std::get<1>(result); + out->write_level_min = std::get<0>(data); + out->write_level_max = std::get<1>(data); + + return 0; + } + +NK_C_API char* NK_get_SD_usage_data_as_string() { auto m = NitrokeyManager::instance(); return get_with_string_result([&]() { return m->get_SD_usage_data_as_string(); @@ -605,19 +744,19 @@ NK_C_API int NK_get_progress_bar_value() { auto m = NitrokeyManager::instance(); - return get_with_result([&]() { + return std::get<1>(get_with_status([&]() { return m->get_progress_bar_value(); - }); + }, -2)); } - NK_C_API int NK_get_major_firmware_version() { + NK_C_API uint8_t NK_get_major_firmware_version() { auto m = NitrokeyManager::instance(); return get_with_result([&]() { return m->get_major_firmware_version(); }); } - NK_C_API int NK_get_minor_firmware_version() { + NK_C_API uint8_t NK_get_minor_firmware_version() { auto m = NitrokeyManager::instance(); return get_with_result([&]() { return m->get_minor_firmware_version(); @@ -631,7 +770,7 @@ }); } - NK_C_API const char* NK_list_devices_by_cpuID() { + NK_C_API char* NK_list_devices_by_cpuID() { auto nm = NitrokeyManager::instance(); return get_with_string_result([&]() { auto v = nm->list_devices_by_cpuID(); @@ -640,10 +779,70 @@ res += a+";"; } if (res.size()>0) res.pop_back(); // remove last delimiter char - return strndup(res.c_str(), 8192); //this buffer size sets limit to over 200 devices ID's + return strndup(res.c_str(), MAXIMUM_STR_REPLY_LENGTH); }); } + bool copy_device_info(const DeviceInfo& source, NK_device_info* target) { + switch (source.m_deviceModel) { + case DeviceModel::PRO: + target->model = NK_PRO; + break; + case DeviceModel::STORAGE: + target->model = NK_STORAGE; + break; + default: + return false; + } + + target->path = strndup(source.m_path.c_str(), MAXIMUM_STR_REPLY_LENGTH); + target->serial_number = strndup(source.m_serialNumber.c_str(), MAXIMUM_STR_REPLY_LENGTH); + target->next = nullptr; + + return target->path && target->serial_number; + } + + NK_C_API struct NK_device_info* NK_list_devices() { + auto nm = NitrokeyManager::instance(); + return get_with_result([&]() -> NK_device_info* { + auto v = nm->list_devices(); + if (v.empty()) + return nullptr; + + auto result = new NK_device_info(); + auto ptr = result; + auto first = v.begin(); + if (!copy_device_info(*first, ptr)) { + NK_free_device_info(result); + return nullptr; + } + v.erase(first); + + for (auto& info : v) { + ptr->next = new NK_device_info(); + ptr = ptr->next; + + if (!copy_device_info(info, ptr)) { + NK_free_device_info(result); + return nullptr; + } + } + return result; + }); + } + + NK_C_API void NK_free_device_info(struct NK_device_info* device_info) { + if (!device_info) + return; + + if (device_info->next) + NK_free_device_info(device_info->next); + + free(device_info->path); + free(device_info->serial_number); + delete device_info; + } + NK_C_API int NK_connect_with_ID(const char* id) { auto m = NitrokeyManager::instance(); return get_with_result([&]() { @@ -651,6 +850,59 @@ }); } + NK_C_API int NK_connect_with_path(const char* path) { + auto m = NitrokeyManager::instance(); + return get_with_result([&]() { + return m->connect_with_path(path) ? 1 : 0; + }); + } + + + NK_C_API int NK_wink() { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + return m->wink(); + }); + } + + NK_C_API int NK_enable_firmware_update_pro(const char* update_password){ + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->enable_firmware_update_pro(update_password); + }); +} + + NK_C_API int NK_change_firmware_password_pro(const char *current_firmware_password, const char *new_firmware_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->change_firmware_update_password_pro(current_firmware_password, + new_firmware_password); + }); + } + + + NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out){ + if (out == nullptr) + return -1; + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_HOTP_slot_data(slot_num); + }, stick10::ReadSlot::ResponsePayload() ); + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } +#define a(x) out->x = read_slot.x + stick10::ReadSlot::ResponsePayload read_slot = std::get<1>(result); + a(_slot_config); + a(slot_counter); +#undef a +#define m(x) memmove(out->x, read_slot.x, sizeof(read_slot.x)) + m(slot_name); + m(slot_token_id); +#undef m + return 0; +} #ifdef __cplusplus diff -Nru nitrokey-app-1.3.2/libnitrokey/NK_C_API.h nitrokey-app-1.4.1/libnitrokey/NK_C_API.h --- nitrokey-app-1.3.2/libnitrokey/NK_C_API.h 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/NK_C_API.h 2019-09-28 16:22:11.000000000 +0000 @@ -25,41 +25,298 @@ #include #include +#include "deprecated.h" + #ifdef _MSC_VER #define NK_C_API __declspec(dllexport) #else -#define NK_C_API +#define NK_C_API #endif +/** + * \file + * + * C API for libnitrokey + * + * \mainpage + * + * **libnitrokey** provides access to Nitrokey Pro and Nitrokey Storage devices. + * This documentation describes libnitrokey’s C API. For a list of the + * available functions, see the NK_C_API.h file. + * + * \section getting_started Example + * + * \code{.c} + * #include + * #include + * #include + * + * int main(void) + * { + * if (NK_login_auto() != 1) { + * fprintf(stderr, "No Nitrokey found.\n"); + * return 1; + * } + * + * NK_device_model model = NK_get_device_model(); + * printf("Connected to "); + * switch (model) { + * case NK_PRO: + * printf("a Nitrokey Pro"); + * break; + * case NK_STORAGE: + * printf("a Nitrokey Storage"); + * break; + * default: + * printf("an unsupported Nitrokey"); + * break; + * } + * + * char* serial_number = NK_device_serial_number(); + * if (serial_number) + * printf(" with serial number %s\n", serial_number); + * else + * printf(" -- could not query serial number!\n"); + * free(serial_number); + * + * NK_logout(); + * return 0; + * } + * \endcode + */ + #ifdef __cplusplus extern "C" { #endif + /** + * The number of slots in the password safe. + */ + extern const uint8_t NK_PWS_SLOT_COUNT; + + static const int MAXIMUM_STR_REPLY_LENGTH = 8192; + /** * The Nitrokey device models supported by the API. */ enum NK_device_model { + /** + * Use, if no supported device is connected + */ + NK_DISCONNECTED = 0, /** * Nitrokey Pro. */ - NK_PRO, + NK_PRO = 1, /** * Nitrokey Storage. */ - NK_STORAGE + NK_STORAGE = 2 + }; + + /** + * The connection info for a Nitrokey device as a linked list. + */ + struct NK_device_info { + /** + * The model of the Nitrokey device. + */ + enum NK_device_model model; + /** + * The USB device path for NK_connect_with_path. + */ + char* path; + /** + * The serial number. + */ + char* serial_number; + /** + * The pointer to the next element of the linked list or null + * if this is the last element in the list. + */ + struct NK_device_info* next; + }; + + /** + * Stores the common device status for all Nitrokey devices. + */ + struct NK_status { + /** + * The major firmware version, e. g. 0 in v0.40. + */ + uint8_t firmware_version_major; + /** + * The minor firmware version, e. g. 40 in v0.40. + */ + uint8_t firmware_version_minor; + /** + * The serial number of the smart card. + */ + uint32_t serial_number_smart_card; + /** + * The HOTP slot to generate a password from if the numlock + * key is pressed twice (slot 0-1, or any other value to + * disable the function). + */ + uint8_t config_numlock; + /** + * The HOTP slot to generate a password from if the capslock + * key is pressed twice (slot 0-1, or any other value to + * disable the function). + */ + uint8_t config_capslock; + /** + * The HOTP slot to generate a password from if the scrolllock + * key is pressed twice (slot 0-1, or any other value to + * disable the function). + */ + uint8_t config_scrolllock; + /** + * Indicates whether the user password is required to generate + * an OTP value. + */ + bool otp_user_password; + }; + + /** + * Stores the status of a Storage device. + */ + struct NK_storage_status { + /** + * Indicates whether the unencrypted volume is read-only. + */ + bool unencrypted_volume_read_only; + /** + * Indicates whether the unencrypted volume is active. + */ + bool unencrypted_volume_active; + /** + * Indicates whether the encrypted volume is read-only. + */ + bool encrypted_volume_read_only; + /** + * Indicates whether the encrypted volume is active. + */ + bool encrypted_volume_active; + /** + * Indicates whether the hidden volume is read-only. + */ + bool hidden_volume_read_only; + /** + * Indicates whether the hidden volume is active. + */ + bool hidden_volume_active; + /** + * The major firmware version, e. g. 0 in v0.40. + */ + uint8_t firmware_version_major; + /** + * The minor firmware version, e. g. 40 in v0.40. + */ + uint8_t firmware_version_minor; + /** + * Indicates whether the firmware is locked. + */ + bool firmware_locked; + /** + * The serial number of the SD card in the Storage stick. + */ + uint32_t serial_number_sd_card; + /** + * The serial number of the smart card in the Storage stick. + */ + uint32_t serial_number_smart_card; + /** + * The number of remaining login attempts for the user PIN. + */ + uint8_t user_retry_count; + /** + * The number of remaining login attempts for the admin PIN. + */ + uint8_t admin_retry_count; + /** + * Indicates whether a new SD card was found. + */ + bool new_sd_card_found; + /** + * Indicates whether the SD card is filled with random characters. + */ + bool filled_with_random; + /** + * Indicates whether the stick has been initialized by generating + * the AES keys. + */ + bool stick_initialized; }; /** - * Set debug level of messages written on stderr - * @param state state=True - most messages, state=False - only errors level + * Data about the usage of the SD card. */ + struct NK_SD_usage_data { + /** + * The minimum write level, as a percentage of the total card + * size. + */ + uint8_t write_level_min; + /** + * The maximum write level, as a percentage of the total card + * size. + */ + uint8_t write_level_max; + }; + + + struct NK_storage_ProductionTest{ + uint8_t FirmwareVersion_au8[2]; + uint8_t FirmwareVersionInternal_u8; + uint8_t SD_Card_Size_u8; + uint32_t CPU_CardID_u32; + uint32_t SmartCardID_u32; + uint32_t SD_CardID_u32; + uint8_t SC_UserPwRetryCount; + uint8_t SC_AdminPwRetryCount; + uint8_t SD_Card_ManufacturingYear_u8; + uint8_t SD_Card_ManufacturingMonth_u8; + uint16_t SD_Card_OEM_u16; + uint16_t SD_WriteSpeed_u16; + uint8_t SD_Card_Manufacturer_u8; + }; + + NK_C_API int NK_get_storage_production_info(struct NK_storage_ProductionTest * out); + + +/** + * Set debug level of messages written on stderr + * @param state state=True - most messages, state=False - only errors level + */ NK_C_API void NK_set_debug(bool state); /** * Set debug level of messages written on stderr * @param level (int) 0-lowest verbosity, 5-highest verbosity */ - NK_C_API void NK_set_debug_level(const int level); + NK_C_API void NK_set_debug_level(const int level); + + /** + * Get the major library version, e. g. the 3 in v3.2. + * @return the major library version + */ + NK_C_API unsigned int NK_get_major_library_version(); + + /** + * Get the minor library version, e. g. the 2 in v3.2. + * @return the minor library version + */ + NK_C_API unsigned int NK_get_minor_library_version(); + + /** + * Get the library version as a string. This is the output of + * `git describe --always` at compile time, for example "v3.3" or + * "v3.3-19-gaee920b". + * The return value is a string literal and must not be freed. + * @return the library version as a string + */ + NK_C_API const char* NK_get_library_version(); /** * Connect to device of given model. Currently library can be connected only to one device at once. @@ -88,16 +345,45 @@ NK_C_API int NK_logout(); /** + * Query the model of the connected device. + * Returns the model of the connected device or NK_DISCONNECTED. + * + * @return true if a device is connected and the out argument has been set + */ + NK_C_API enum NK_device_model NK_get_device_model(); + + /** + * Return the debug status string. Debug purposes. This function is + * deprecated in favor of NK_get_status_as_string. + * @return string representation of the status or an empty string + * if the command failed + */ + DEPRECATED + NK_C_API char * NK_status(); + + /** * Return the debug status string. Debug purposes. + * @return string representation of the status or an empty string + * if the command failed + */ + NK_C_API char * NK_get_status_as_string(); + + /** + * Get the stick status common to all Nitrokey devices and return the + * command processing error code. If the code is zero, i. e. the + * command was successful, the storage status is written to the output + * pointer's target. The output pointer must not be null. + * + * @param out the output pointer for the status * @return command processing error code */ - NK_C_API const char * NK_status(); + NK_C_API int NK_get_status(struct NK_status* out); /** * Return the device's serial number string in hex. * @return string device's serial number in hex */ - NK_C_API const char * NK_device_serial_number(); + NK_C_API char * NK_device_serial_number(); /** * Get last command processing status. Useful for commands which returns the results of their own and could not return @@ -114,37 +400,37 @@ /** * Authenticates the user on USER privilages with user_password and sets user's temporary password on device to user_temporary_password. - * @param user_password char[25](Pro) current user password - * @param user_temporary_password char[25](Pro) user temporary password to be set on device for further communication (authentication command) + * @param user_password char[25] current user password + * @param user_temporary_password char[25] user temporary password to be set on device for further communication (authentication command) * @return command processing error code */ NK_C_API int NK_user_authenticate(const char* user_password, const char* user_temporary_password); /** * Authenticates the user on ADMIN privilages with admin_password and sets user's temporary password on device to admin_temporary_password. - * @param admin_password char[25](Pro) current administrator PIN - * @param admin_temporary_password char[25](Pro) admin temporary password to be set on device for further communication (authentication command) + * @param admin_password char[25] current administrator PIN + * @param admin_temporary_password char[25] admin temporary password to be set on device for further communication (authentication command) * @return command processing error code */ NK_C_API int NK_first_authenticate(const char* admin_password, const char* admin_temporary_password); /** * Execute a factory reset. - * @param admin_password char[20](Pro) current administrator PIN + * @param admin_password char[20] current administrator PIN * @return command processing error code */ NK_C_API int NK_factory_reset(const char* admin_password); /** * Generates AES key on the device - * @param admin_password char[20](Pro) current administrator PIN + * @param admin_password char[20] current administrator PIN * @return command processing error code */ NK_C_API int NK_build_aes_key(const char* admin_password); /** * Unlock user PIN locked after 3 incorrect codes tries. - * @param admin_password char[20](Pro) current administrator PIN + * @param admin_password char[20] current administrator PIN * @return command processing error code */ NK_C_API int NK_unlock_user_password(const char *admin_password, const char *new_user_password); @@ -181,16 +467,16 @@ /** * Get name of given TOTP slot * @param slot_number TOTP slot number, slot_number<15 - * @return char[20](Pro) the name of the slot + * @return char[20] the name of the slot */ - NK_C_API const char * NK_get_totp_slot_name(uint8_t slot_number); + NK_C_API char * NK_get_totp_slot_name(uint8_t slot_number); /** * * @param slot_number HOTP slot number, slot_number<3 - * @return char[20](Pro) the name of the slot + * @return char[20] the name of the slot */ - NK_C_API const char * NK_get_hotp_slot_name(uint8_t slot_number); + NK_C_API char * NK_get_hotp_slot_name(uint8_t slot_number); /** * Erase HOTP slot data from the device @@ -210,15 +496,16 @@ /** * Write HOTP slot data to the device - * @param slot_number HOTP slot number, slot_number<3 - * @param slot_name char[15](Pro) desired slot name - * @param secret char[20](Pro) 160-bit secret + * @param slot_number HOTP slot number, slot_number<3, 0-numbered + * @param slot_name char[15] desired slot name. C string (requires ending '\0'; 16 bytes). + * @param secret char[40] 160-bit or 320-bit (currently Pro v0.8 only) secret as a hex string. C string (requires ending '\0'; 41 bytes). + * See NitrokeyManager::is_320_OTP_secret_supported. * @param hotp_counter uint32_t starting value of HOTP counter * @param use_8_digits should returned codes be 6 (false) or 8 digits (true) * @param use_enter press ENTER key after sending OTP code using double-pressed scroll/num/capslock * @param use_tokenID @see token_ID * @param token_ID @see https://openauthentication.org/token-specs/, 'Class A' section - * @param temporary_password char[25](Pro) admin temporary password + * @param temporary_password char[25] admin temporary password * @return command processing error code */ NK_C_API int NK_write_hotp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter, @@ -227,15 +514,16 @@ /** * Write TOTP slot data to the device - * @param slot_number TOTP slot number, slot_number<15 - * @param slot_name char[15](Pro) desired slot name - * @param secret char[20](Pro) 160-bit secret + * @param slot_number TOTP slot number, slot_number<15, 0-numbered + * @param slot_name char[15] desired slot name. C string (requires ending '\0'; 16 bytes). + * @param secret char[40] 160-bit or 320-bit (currently Pro v0.8 only) secret as a hex string. C string (requires ending '\0'; 41 bytes). + * See NitrokeyManager::is_320_OTP_secret_supported. * @param time_window uint16_t time window for this TOTP * @param use_8_digits should returned codes be 6 (false) or 8 digits (true) * @param use_enter press ENTER key after sending OTP code using double-pressed scroll/num/capslock * @param use_tokenID @see token_ID * @param token_ID @see https://openauthentication.org/token-specs/, 'Class A' section - * @param temporary_password char[20](Pro) admin temporary password + * @param temporary_password char[20] admin temporary password * @return command processing error code */ NK_C_API int NK_write_totp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window, @@ -247,39 +535,39 @@ * @param slot_number HOTP slot number, slot_number<3 * @return HOTP code */ - NK_C_API const char * NK_get_hotp_code(uint8_t slot_number); + NK_C_API char * NK_get_hotp_code(uint8_t slot_number); /** * Get HOTP code from the device (PIN protected) * @param slot_number HOTP slot number, slot_number<3 - * @param user_temporary_password char[25](Pro) user temporary password if PIN protected OTP codes are enabled, + * @param user_temporary_password char[25] user temporary password if PIN protected OTP codes are enabled, * otherwise should be set to empty string - '' * @return HOTP code */ - NK_C_API const char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password); + NK_C_API char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password); /** * Get TOTP code from the device * @param slot_number TOTP slot number, slot_number<15 - * @param challenge TOTP challenge - * @param last_totp_time last time - * @param last_interval last interval + * @param challenge TOTP challenge -- unused + * @param last_totp_time last time -- unused + * @param last_interval last interval --unused * @return TOTP code */ - NK_C_API const char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + NK_C_API char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, uint8_t last_interval); /** * Get TOTP code from the device (PIN protected) * @param slot_number TOTP slot number, slot_number<15 - * @param challenge TOTP challenge - * @param last_totp_time last time - * @param last_interval last interval - * @param user_temporary_password char[25](Pro) user temporary password if PIN protected OTP codes are enabled, + * @param challenge TOTP challenge -- unused + * @param last_totp_time last time -- unused + * @param last_interval last interval -- unused + * @param user_temporary_password char[25] user temporary password if PIN protected OTP codes are enabled, * otherwise should be set to empty string - '' * @return TOTP code */ - NK_C_API const char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, + NK_C_API char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, uint8_t last_interval, const char *user_temporary_password); @@ -290,21 +578,35 @@ */ NK_C_API int NK_totp_set_time(uint64_t time); + /** + * Set the device time used for TOTP to the given time. Contrary to + * {@code set_time(uint64_t)}, this command fails if {@code old_time} + * > {@code time} or if {@code old_time} is zero (where {@code + * old_time} is the current time on the device). + * + * @param time new device time as Unix timestamp (seconds since + * 1970-01-01) + * @return command processing error code + */ + NK_C_API int NK_totp_set_time_soft(uint64_t time); + + // NK_totp_get_time is deprecated -- use NK_totp_set_time_soft instead + DEPRECATED NK_C_API int NK_totp_get_time(); //passwords /** * Change administrator PIN - * @param current_PIN char[25](Pro) current PIN - * @param new_PIN char[25](Pro) new PIN + * @param current_PIN char[25] current PIN + * @param new_PIN char[25] new PIN * @return command processing error code */ NK_C_API int NK_change_admin_PIN(const char *current_PIN, const char *new_PIN); /** * Change user PIN - * @param current_PIN char[25](Pro) current PIN - * @param new_PIN char[25](Pro) new PIN + * @param current_PIN char[25] current PIN + * @param new_PIN char[25] new PIN * @return command processing error code */ NK_C_API int NK_change_user_PIN(const char *current_PIN, const char *new_PIN); @@ -325,7 +627,7 @@ /** * Enable password safe access - * @param user_pin char[30](Pro) current user PIN + * @param user_pin char[30] current user PIN * @return command processing error code */ NK_C_API int NK_enable_password_safe(const char *user_pin); @@ -341,28 +643,28 @@ * @param slot_number password safe slot number, slot_number<16 * @return slot name */ - NK_C_API const char *NK_get_password_safe_slot_name(uint8_t slot_number); + NK_C_API char *NK_get_password_safe_slot_name(uint8_t slot_number); /** * Get password safe slot login * @param slot_number password safe slot number, slot_number<16 * @return login from the PWS slot */ - NK_C_API const char *NK_get_password_safe_slot_login(uint8_t slot_number); + NK_C_API char *NK_get_password_safe_slot_login(uint8_t slot_number); /** * Get the password safe slot password * @param slot_number password safe slot number, slot_number<16 * @return password from the PWS slot */ - NK_C_API const char *NK_get_password_safe_slot_password(uint8_t slot_number); + NK_C_API char *NK_get_password_safe_slot_password(uint8_t slot_number); /** * Write password safe data to the slot * @param slot_number password safe slot number, slot_number<16 - * @param slot_name char[11](Pro) name of the slot - * @param slot_login char[32](Pro) login string - * @param slot_password char[20](Pro) password string + * @param slot_name char[11] name of the slot + * @param slot_login char[32] login string + * @param slot_password char[20] password string * @return command processing error code */ NK_C_API int NK_write_password_safe_slot(uint8_t slot_number, const char *slot_name, @@ -385,13 +687,13 @@ * Get device's major firmware version * @return major part of the version number (e.g. 0 from 0.48, 0 from 0.7 etc.) */ - NK_C_API int NK_get_major_firmware_version(); + NK_C_API uint8_t NK_get_major_firmware_version(); /** * Get device's minor firmware version * @return minor part of the version number (e.g. 7 from 0.7, 48 from 0.48 etc.) */ - NK_C_API int NK_get_minor_firmware_version(); + NK_C_API uint8_t NK_get_minor_firmware_version(); /** * Function to determine unencrypted volume PIN type @@ -580,7 +882,29 @@ * Storage only * @return string with devices attributes */ - NK_C_API const char* NK_get_status_storage_as_string(); + NK_C_API char* NK_get_status_storage_as_string(); + + /** + * Get the Storage stick status and return the command processing + * error code. If the code is zero, i. e. the command was successful, + * the storage status is written to the output pointer's target. + * The output pointer must not be null. + * + * @param out the output pointer for the storage status + * @return command processing error code + */ + NK_C_API int NK_get_status_storage(struct NK_storage_status* out); + + /** + * Get SD card usage attributes. Usable during hidden volumes creation. + * If the command was successful (return value 0), the usage data is + * written to the output pointer’s target. The output pointer must + * not be null. + * Storage only + * @param out the output pointer for the usage data + * @return command processing error code + */ + NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out); /** * Get SD card usage attributes as string. @@ -588,12 +912,13 @@ * Storage only * @return string with SD card usage attributes */ - NK_C_API const char* NK_get_SD_usage_data_as_string(); + NK_C_API char* NK_get_SD_usage_data_as_string(); /** * Get progress value of current long operation. * Storage only - * @return int in range 0-100 or -1 if device is not busy + * @return int in range 0-100 or -1 if device is not busy or -2 if an + * error occured */ NK_C_API int NK_get_progress_bar_value(); @@ -612,8 +937,21 @@ * @example Example of returned data: '00005d19:dacc2cb4_p_0001:0010:02;000037c7:4cf12445_p_0001:000f:02;0001:000c:02' * @return string delimited id's of connected devices */ - NK_C_API const char* NK_list_devices_by_cpuID(); + NK_C_API char* NK_list_devices_by_cpuID(); + + /** + * Returns a linked list of all connected devices, or null if no devices + * are connected or an error occured. The linked list must be freed by + * calling NK_free_device_info. + * @return a linked list of all connected devices + */ + NK_C_API struct NK_device_info* NK_list_devices(); + /** + * Free a linked list returned by NK_list_devices. + * @param the linked list to free or null + */ + NK_C_API void NK_free_device_info(struct NK_device_info* device_info); /** * Connects to the device with given ID. ID's list could be created with NK_list_devices_by_cpuID. @@ -625,7 +963,49 @@ */ NK_C_API int NK_connect_with_ID(const char* id); + /** + * Connects to a device with the given path. The path is a USB device + * path as returned by hidapi. + * @param path the device path + * @return 1 on successful connection, 0 otherwise + */ + NK_C_API int NK_connect_with_path(const char* path); + + /** + * Blink red and green LED alternatively and infinitely (until device is reconnected). + * @return command processing error code + */ + NK_C_API int NK_wink(); + + + /** + * Enable update mode on Nitrokey Pro. + * Supported from v0.11. + * @param update_password 20 bytes update password + * @return command processing error code + */ + NK_C_API int NK_enable_firmware_update_pro(const char* update_password); + + /** + * Change update-mode password on Nitrokey Pro. + * Supported from v0.11. + * @param current_firmware_password 20 bytes update password + * @param new_firmware_password 20 bytes update password + * @return command processing error code + */ + NK_C_API int NK_change_firmware_password_pro(const char *current_firmware_password, const char *new_firmware_password); + + +// as in ReadSlot::ResponsePayload +struct ReadSlot_t { + uint8_t slot_name[15]; + uint8_t _slot_config; + uint8_t slot_token_id[13]; + uint64_t slot_counter; +}; + +NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out); #ifdef __cplusplus } diff -Nru nitrokey-app-1.3.2/libnitrokey/README.md nitrokey-app-1.4.1/libnitrokey/README.md --- nitrokey-app-1.3.2/libnitrokey/README.md 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/README.md 2019-09-28 16:22:11.000000000 +0000 @@ -4,7 +4,7 @@ # libnitrokey libnitrokey is a project to communicate with Nitrokey Pro and Storage devices in a clean and easy manner. Written in C++14, testable with `py.test` and `Catch` frameworks, with C API, Python access (through CFFI and C API, in future with Pybind11). -The development of this project is aimed to make it itself a living documentation of communication protocol between host and the Nitrokey stick devices. The command packets' format is described here: [Pro v0.7](include/stick10_commands.h), [Pro v0.8](include/stick10_commands_0.8.h), [Storage](include/stick20_commands.h). Handling and additional operations are described here: [NitrokeyManager.cc](NitrokeyManager.cc). +The development of this project is aimed to make it itself a living documentation of communication protocol between host and the Nitrokey stick devices. The command packets' format is described here: [Pro v0.7](libnitrokey/stick10_commands.h), [Pro v0.8](libnitrokey/stick10_commands_0.8.h), [Storage](libnitrokey/stick20_commands.h). Handling and additional operations are described here: [NitrokeyManager.cc](NitrokeyManager.cc). A C++14 complying compiler is required due to heavy use of variable templates. For feature support tables please check [table 1](https://gcc.gnu.org/projects/cxx-status.html#cxx14) or [table 2](http://en.cppreference.com/w/cpp/compiler_support). @@ -44,7 +44,7 @@ make -j2 ``` -### Windows MS Visual Studio 2017 +### Windows and Visual Studio 2017 Lately Visual Studio has started handling CMake files directly. After opening the project's directory it should recognize it and initialize build system. Afterwards please run: 1. `CMake -> Cache -> View Cache CMakeLists.txt -> CMakeLists.txt` to edit settings 2. `CMake -> Build All` to build @@ -76,6 +76,14 @@ * NO_LOG (default: OFF) - do not compile LOG statements - will make library smaller, but without any diagnostic messages +### Meson +It is possible to use Meson and Ninja to build the project as well (currently available only `master` branch). +Please run: +``` +meson builddir +meson configure builddir # to show available build flags +ninja -C builddir +``` # Using libnitrokey with Python To use libnitrokey with Python a [CFFI](http://cffi.readthedocs.io/en/latest/overview.html) library is required (either 2.7+ or 3.0+). It can be installed with: @@ -155,25 +163,31 @@ All available functions for C and Python are listed in [NK_C_API.h](NK_C_API.h). Please check `Documentation` section below. ## Documentation -The documentation of C API is included in the sources (could be generated with doxygen if requested). -Please check [NK_C_API.h](NK_C_API.h) (C API) for high level commands and [include/NitrokeyManager.h](include/NitrokeyManager.h) (C++ API). All devices' commands are listed along with packet format in [include/stick10_commands.h](include/stick10_commands.h) and [include/stick20_commands.h](include/stick20_commands.h) respectively for Nitrokey Pro and Nitrokey Storage products. +The documentation of C API is included in the sources (can be generated with `make doc` if Doxygen is installed). +Please check [NK_C_API.h](NK_C_API.h) (C API) for high level commands and [libnitrokey/NitrokeyManager.h](libnitrokey/NitrokeyManager.h) (C++ API). All devices' commands are listed along with packet format in [libnitrokey/stick10_commands.h](libnitrokey/stick10_commands.h) and [libnitrokey/stick20_commands.h](libnitrokey/stick20_commands.h) respectively for Nitrokey Pro and Nitrokey Storage products. # Tests -Warning! Before you run unittests please either change both your Admin and User PINs on your Nitrostick to defaults (`12345678` and `123456` respectively) or change the values in tests source code. If you do not change them the tests might lock your device and lose your data. If it's too late, you can reset your Nitrokey using instructions from [homepage](https://www.nitrokey.com/de/documentation/how-reset-nitrokey). +**Warning!** Most of the tests will overwrite user data. The only user-data safe tests are specified in `unittest/test_safe.cpp` (see *C++ tests* chapter). + +**Warning!** Before you run unittests please change both your Admin and User PINs on your Nitrostick to defaults (`12345678` and `123456` respectively), or change the values in tests source code. If you do not change them, the tests might lock your device temporarily. If it's too late already, you can reset your Nitrokey using instructions from [homepage](https://www.nitrokey.com/de/documentation/how-reset-nitrokey). ## Python tests -libnitrokey has a great suite of tests written in Python 3 under the path: `unittest/test_*.py`: +libnitrokey has a great suite of tests written in Python 3 under the path: [unittest/test_*.py](https://github.com/Nitrokey/libnitrokey/tree/master/unittest): * `test_pro.py` - contains tests of OTP, Password Safe and PIN control functionality. Could be run on both Pro and Storage devices. * `test_storage.py` - contains tests of Encrypted Volumes functionality. Could be run only on Storage. + The tests themselves show how to handle common requests to device. Before running please install all required libraries with: ```bash cd unittest pip install --user -r requirements.txt ``` +or use Python's environment managing tool like [pipenv](https://pipenv.readthedocs.io/en/latest/) or `virtualenv`. + + To run them please execute: ```bash -# substitute with either pro or storage +# substitute with either 'pro' or 'storage' py.test -v test_.py # more specific use - run tests containing in name 5 times: py.test -v test_.py -k --count 5 @@ -182,9 +196,76 @@ For additional documentation please check the following for [py.test installation](http://doc.pytest.org/en/latest/getting-started.html). For better coverage [randomly plugin](https://pypi.python.org/pypi/pytest-randomly) is installed - it randomizes the test order allowing to detect unseen dependencies between the tests. ## C++ tests -There are also some unit tests implemented in C++, placed in unittest directory. They are not written as extensively as Python tests and are rather more a C++ low level interface check, often not using C++ API from `NitrokeyManager.cc`. Some of them are: [test_HOTP.cc](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test_HOTP.cc), -[test.cc](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test.cc). -Unit tests were written and tested on Ubuntu 16.04/16.10/17.04. To run them just execute binaries built in ./libnitrokey/build dir after enabling them by passing `-DCOMPILE_TESTS=ON` option like in `cmake .. -DCOMPILE_TESTS=ON && make`. +There are also some unit tests implemented in C++, placed in unittest directory. The only user-data safe online test set here is [test_safe.cpp](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test_safe.cpp), which tries to connect to the device, and collect its status data. Example run for Storage: +```text +# Storage device inserted, firmware version v0.53 +$ ./test_safe +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_DEVICE_STATUS +.. +[Wed Jan 2 13:31:17 2019][DEBUG_L1] <= GET_DEVICE_STATUS 0 1 +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_PASSWORD_RETRY_COUNT +[Wed Jan 2 13:31:17 2019][DEBUG_L1] <= GET_PASSWORD_RETRY_COUNT 0 0 +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_DEVICE_STATUS +.. +[Wed Jan 2 13:31:17 2019][DEBUG_L1] <= GET_DEVICE_STATUS 0 1 +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_USER_PASSWORD_RETRY_COUNT +[Wed Jan 2 13:31:17 2019][DEBUG_L1] <= GET_USER_PASSWORD_RETRY_COUNT 0 0 +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_DEVICE_STATUS +... +[Wed Jan 2 13:31:17 2019][DEBUG_L1] <= GET_DEVICE_STATUS 0 1 + transmission_data.dissect(): _padding: +0000 00 00 00 00 00 00 00 00 00 00 00 00 00 05 2e 01 ................ +0010 00 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- .. + (int) SendCounter_u8: 0 + (int) SendDataType_u8: 3 + (int) FollowBytesFlag_u8: 0 + (int) SendSize_u8: 28 + + MagicNumber_StickConfig_u16: 13080 + (int) ReadWriteFlagUncryptedVolume_u8: 1 + (int) ReadWriteFlagCryptedVolume_u8: 0 + (int) ReadWriteFlagHiddenVolume_u8: 0 + (int) versionInfo.major: 0 + (int) versionInfo.minor: 53 + (int) versionInfo.build_iteration: 0 + (int) FirmwareLocked_u8: 0 + (int) NewSDCardFound_u8: 1 + (int) NewSDCardFound_st.NewCard: 1 + (int) NewSDCardFound_st.Counter: 0 + (int) SDFillWithRandomChars_u8: 1 + ActiveSD_CardID_u32: 3670817656 + (int) VolumeActiceFlag_u8: 1 + (int) VolumeActiceFlag_st.unencrypted: 1 + (int) VolumeActiceFlag_st.encrypted: 0 + (int) VolumeActiceFlag_st.hidden: 0 + (int) NewSmartCardFound_u8: 0 + (int) UserPwRetryCount: 3 + (int) AdminPwRetryCount: 3 + ActiveSmartCardID_u32: 24122 + (int) StickKeysNotInitiated: 0 + +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_DEVICE_STATUS +.. +[Wed Jan 2 13:31:17 2019][DEBUG_L1] <= GET_DEVICE_STATUS 0 1 +00005e3a +[Wed Jan 2 13:31:17 2019][DEBUG_L1] => GET_DEVICE_STATUS +.... +[Wed Jan 2 13:31:18 2019][DEBUG_L1] <= GET_DEVICE_STATUS 0 1 +[Wed Jan 2 13:31:18 2019][DEBUG_L1] => GET_DEVICE_STATUS +... +[Wed Jan 2 13:31:18 2019][DEBUG_L1] <= GET_DEVICE_STATUS 0 1 +=============================================================================== +All tests passed (18 assertions in 6 test cases) +``` +Test's execution configuration and verbosity could be manipulated - please see `./test_safe --help` for details. + +The other tests sets are not written as extensively as Python tests and are rather more a C++ low level interface check used during the library development, using either low-level components, C API from `NK_C_API.cc`, or C++ API from `NitrokeyManager.cc`. Some of them are: [test_HOTP.cc](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test_HOTP.cc), +[test1.cc](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test1.cc). See more in [unittest](https://github.com/Nitrokey/libnitrokey/tree/master/unittest) directory. + +**Note: these are not device model agnostic, and will most probably destroy your data on the device.** + + +Unit tests were checked on Ubuntu 16.04/16.10/17.04. To run them just execute binaries built in `./libnitrokey/build` dir, after enabling them by passing `-DCOMPILE_TESTS=ON` option to `cmake` - e.g.: `cmake .. -DCOMPILE_TESTS=ON && make`. The documentation of how it works could be found in nitrokey-app project's README on Github: @@ -198,7 +279,7 @@ # Known issues / tasks * Currently only one device can be connected at a time (experimental work could be found in `wip-multiple_devices` branch), -* C++ API needs some reorganization to C++ objects (instead of pointers to arrays). This will be also preparing for integration with Pybind11, +* C++ API needs some reorganization to C++ objects (instead of pointers to byte arrays). This will be also preparing for integration with Pybind11, * Fix compilation warnings. Other tasks might be listed either in [TODO](TODO) file or on project's issues page. diff -Nru nitrokey-app-1.3.2/libnitrokey/.travis.yml nitrokey-app-1.4.1/libnitrokey/.travis.yml --- nitrokey-app-1.3.2/libnitrokey/.travis.yml 2017-12-28 14:01:52.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/.travis.yml 2019-09-28 16:22:11.000000000 +0000 @@ -22,8 +22,20 @@ - cmake - libhidapi-dev - g++-5 + - python3 + - python3-pip + - python3-requests + - git sources: &sources - ubuntu-toolchain-r-test + script: + - make -j2 + - ctest -VV + - mkdir install && make install DESTDIR=install + - pip3 install pytest --user + - cd ../ + - pip3 install -r unittest/requirements.txt --user + - cd unittest && python3 -m pytest -sv test_offline.py - os: linux dist: trusty env: COMPILER_NAME=gcc CXX=g++-6 CC=gcc-6 diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/catch_main.cpp nitrokey-app-1.4.1/libnitrokey/unittest/catch_main.cpp --- nitrokey-app-1.3.2/libnitrokey/unittest/catch_main.cpp 2018-01-24 13:06:53.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/catch_main.cpp 2019-09-28 16:22:11.000000000 +0000 @@ -20,4 +20,4 @@ */ #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() -#include "catch.hpp" \ No newline at end of file +#include "catch2/catch.hpp" \ No newline at end of file diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/conftest.py nitrokey-app-1.4.1/libnitrokey/unittest/conftest.py --- nitrokey-app-1.3.2/libnitrokey/unittest/conftest.py 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/conftest.py 2019-09-28 16:22:11.000000000 +0000 @@ -1,5 +1,5 @@ """ -Copyright (c) 2015-2018 Nitrokey UG +Copyright (c) 2015-2019 Nitrokey UG This file is part of libnitrokey. @@ -21,10 +21,20 @@ import pytest -from misc import ffi +from misc import ffi, gs device_type = None +from logging import getLogger, basicConfig, DEBUG + +basicConfig(format='* %(relativeCreated)6d %(filename)s:%(lineno)d %(message)s',level=DEBUG) +log = getLogger('conftest') +print = log.debug + +def get_device_type(): + return device_type + + def skip_if_device_version_lower_than(allowed_devices): global device_type model, version = device_type @@ -33,8 +43,45 @@ pytest.skip('This device model is not applicable to run this test') +class AtrrCallProx(object): + def __init__(self, C, name): + self.C = C + self.name = name + + def __call__(self, *args, **kwargs): + print('Calling {}{}'.format(self.name, args)) + res = self.C(*args, **kwargs) + res_s = res + try: + res_s = '{} => '.format(res) + '{}'.format(gs(res)) + except Exception as e: + pass + print('Result of {}: {}'.format(self.name, res_s)) + return res + + +class AttrProxy(object): + def __init__(self, C, name): + self.C = C + self.name = name + + def __getattr__(self, attr): + return AtrrCallProx(getattr(self.C, attr), attr) + + +@pytest.fixture(scope="module") +def C_offline(request=None): + print("Getting library without initializing connection") + return get_library(request, allow_offline=True) + + @pytest.fixture(scope="module") def C(request=None): + print("Getting library with connection initialized") + return get_library(request) + + +def get_library(request, allow_offline=False): fp = '../NK_C_API.h' declarations = [] @@ -44,14 +91,13 @@ cnt = 0 a = iter(declarations) for declaration in a: - if 'NK_device_model' in declaration: continue - if declaration.strip().startswith('NK_C_API'): + if declaration.strip().startswith('NK_C_API') \ + or declaration.strip().startswith('struct'): declaration = declaration.replace('NK_C_API', '').strip() - while ';' not in declaration: - declaration += (next(a)).strip() - # print(declaration) + while ');' not in declaration and '};' not in declaration: + declaration += (next(a)).strip()+'\n' ffi.cdef(declaration, override=True) - cnt +=1 + cnt += 1 print('Imported {} declarations'.format(cnt)) C = None @@ -83,12 +129,14 @@ nk_login = C.NK_login_auto() if nk_login != 1: print('No devices detected!') - assert nk_login != 0 # returns 0 if not connected or wrong model or 1 when connected - global device_type - firmware_version = C.NK_get_minor_firmware_version() - model = 'P' if firmware_version in [7,8] else 'S' - device_type = (model, firmware_version) - print('Connected device: {} {}'.format(model, firmware_version)) + if not allow_offline: + assert nk_login != 0 # returns 0 if not connected or wrong model or 1 when connected + global device_type + firmware_version = C.NK_get_minor_firmware_version() + model = C.NK_get_device_model() + model = 'P' if model == 1 else 'S' if model == 2 else 'U' + device_type = (model, firmware_version) + print('Connected device: {} {}'.format(model, firmware_version)) # assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK # assert C.NK_user_authenticate(DefaultPasswords.USER, DefaultPasswords.USER_TEMP) == DeviceErrorCode.STATUS_OK @@ -105,4 +153,5 @@ # C.NK_set_debug(True) C.NK_set_debug_level(int(os.environ.get('LIBNK_DEBUG', 3))) - return C + return AttrProxy(C, "libnitrokey C") + diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/constants.py nitrokey-app-1.4.1/libnitrokey/unittest/constants.py --- nitrokey-app-1.3.2/libnitrokey/unittest/constants.py 2018-01-24 13:06:53.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/constants.py 2019-09-28 16:22:11.000000000 +0000 @@ -48,6 +48,7 @@ WRONG_PASSWORD = 4 STATUS_NOT_AUTHORIZED = 5 STATUS_AES_DEC_FAILED = 0xa + STATUS_UNKNOWN_ERROR = 100 class LibraryErrors: @@ -56,3 +57,6 @@ INVALID_HEX_STRING = 202 TARGET_BUFFER_SIZE_SMALLER_THAN_SOURCE = 203 + +HOTP_slot_count = 3 +TOTP_slot_count = 15 \ No newline at end of file diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/libnk-tool.py nitrokey-app-1.4.1/libnitrokey/unittest/libnk-tool.py --- nitrokey-app-1.3.2/libnitrokey/unittest/libnk-tool.py 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/libnk-tool.py 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +""" +Copyright (c) 2015-2019 Nitrokey UG + +This file is part of libnitrokey. + +libnitrokey is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +any later version. + +libnitrokey is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with libnitrokey. If not, see . + +SPDX-License-Identifier: LGPL-3.0 +""" + +import click + +from conftest import get_library, get_device_type +from constants import DefaultPasswords, DeviceErrorCode + + +@click.group() +def cli(): + pass + + +@click.command() +def update(): + libnk = get_library(None) + device_type = get_device_type() + print(device_type) + assert device_type[0] == 'S' + assert libnk.NK_enable_firmware_update(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + + +cli.add_command(update) + +if __name__ == '__main__': + cli() diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/misc.py nitrokey-app-1.4.1/libnitrokey/unittest/misc.py --- nitrokey-app-1.3.2/libnitrokey/unittest/misc.py 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/misc.py 2019-09-28 16:22:11.000000000 +0000 @@ -67,4 +67,8 @@ def is_long_OTP_secret_handled(C): - return is_pro_rtm_08(C) or is_storage(C) and get_devices_firmware_version(C) > 43 + return is_pro_rtm_08(C) or is_storage(C) and get_devices_firmware_version(C) >= 54 + + +def has_binary_counter(C): + return (not is_storage(C)) or (is_storage(C) and get_devices_firmware_version(C) >= 54) diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/requirements.txt nitrokey-app-1.4.1/libnitrokey/unittest/requirements.txt --- nitrokey-app-1.3.2/libnitrokey/unittest/requirements.txt 2017-12-28 14:01:52.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/requirements.txt 2019-09-28 16:22:11.000000000 +0000 @@ -1,4 +1,5 @@ cffi pytest-repeat pytest-randomly -oath \ No newline at end of file +tqdm +oath diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test1.cc nitrokey-app-1.4.1/libnitrokey/unittest/test1.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test1.cc 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test1.cc 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015-2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#include "catch2/catch.hpp" + +#include +#include +#include "device_proto.h" +#include "log.h" +#include "stick10_commands.h" + +using namespace std; +using namespace nitrokey::device; +using namespace nitrokey::proto::stick10; +using namespace nitrokey::log; +using namespace nitrokey::misc; + +using Dev10 = std::shared_ptr; + +std::string getSlotName(Dev10 stick, int slotNo) { + auto slot_req = get_payload(); + slot_req.slot_number = slotNo; + auto slot = ReadSlot::CommandTransaction::run(stick, slot_req); + std::string sName(reinterpret_cast(slot.data().slot_name)); + return sName; +} + +TEST_CASE("Slot names are correct", "[slotNames]") { + auto stick = make_shared(); + bool connected = stick->connect(); + REQUIRE(connected == true); + + Log::instance().set_loglevel(Loglevel::DEBUG); + + auto resp = GetStatus::CommandTransaction::run(stick); + + auto authreq = get_payload(); + strcpy((char *)(authreq.card_password), "12345678"); + FirstAuthenticate::CommandTransaction::run(stick, authreq); + + { + auto authreq = get_payload(); + strcpy((char *)(authreq.user_password), "123456"); + EnablePasswordSafe::CommandTransaction::run(stick, authreq); + } + + //assuming these values were set earlier, thus failing on normal use + REQUIRE(getSlotName(stick, 0x20) == std::string("1")); + REQUIRE(getSlotName(stick, 0x21) == std::string("slot2")); + + { + auto resp = GetPasswordRetryCount::CommandTransaction::run(stick); + REQUIRE(resp.data().password_retry_count == 3); + } + { + auto resp = GetUserPasswordRetryCount::CommandTransaction::run(stick); + REQUIRE(resp.data().password_retry_count == 3); + } + + { + auto slot = get_payload(); + slot.slot_number = 0; + auto resp2 = GetPasswordSafeSlotName::CommandTransaction::run(stick, slot); + std::string sName(reinterpret_cast(resp2.data().slot_name)); + REQUIRE(sName == std::string("web1")); + } + + { + auto slot = get_payload(); + slot.slot_number = 0; + auto resp2 = + GetPasswordSafeSlotPassword::CommandTransaction::run(stick, slot); + std::string sName(reinterpret_cast(resp2.data().slot_password)); + REQUIRE(sName == std::string("pass1")); + } + + { + auto slot = get_payload(); + slot.slot_number = 0; + auto resp2 = GetPasswordSafeSlotLogin::CommandTransaction::run(stick, slot); + std::string sName(reinterpret_cast(resp2.data().slot_login)); + REQUIRE(sName == std::string("login1")); + } + + stick->disconnect(); +} diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test2.cc nitrokey-app-1.4.1/libnitrokey/unittest/test2.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test2.cc 2018-01-24 13:06:53.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test2.cc 2019-09-28 16:22:11.000000000 +0000 @@ -23,7 +23,7 @@ static const char *const default_admin_pin = "12345678"; static const char *const default_user_pin = "123456"; -#include "catch.hpp" +#include "catch2/catch.hpp" #include #include diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test3.cc nitrokey-app-1.4.1/libnitrokey/unittest/test3.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test3.cc 2018-01-24 13:06:53.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test3.cc 2019-09-28 16:22:11.000000000 +0000 @@ -25,7 +25,7 @@ const char * temporary_password = "123456789012345678901234"; const char * RFC_SECRET = "12345678901234567890"; -#include "catch.hpp" +#include "catch2/catch.hpp" #include #include diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_C_API.cpp nitrokey-app-1.4.1/libnitrokey/unittest/test_C_API.cpp --- nitrokey-app-1.3.2/libnitrokey/unittest/test_C_API.cpp 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_C_API.cpp 2019-09-28 16:22:11.000000000 +0000 @@ -21,7 +21,7 @@ static const int TOO_LONG_STRING = 200; -#include "catch.hpp" +#include "catch2/catch.hpp" #include #include @@ -74,7 +74,7 @@ int t; string = strndup(s, 4096); - free ( (void*) s); + free (static_cast(const_cast(s))); while ((token = strsep(&string, ";")) != nullptr){ if (strnlen(token, 4096) < 3) continue; @@ -84,4 +84,18 @@ } free (string); -} \ No newline at end of file +} + +TEST_CASE("Get device model", "[BASIC]") { + NK_logout(); + NK_device_model model = NK_get_device_model(); + REQUIRE(model == NK_device_model::NK_DISCONNECTED); + + auto success = NK_login_auto() == 1; + REQUIRE(success); + model = NK_get_device_model(); + REQUIRE(model != NK_device_model::NK_DISCONNECTED); + + REQUIRE((model == NK_PRO || model == NK_STORAGE)); + NK_logout(); +} diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test.cc nitrokey-app-1.4.1/libnitrokey/unittest/test.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test.cc 2018-01-24 13:06:53.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2015-2018 Nitrokey UG - * - * This file is part of libnitrokey. - * - * libnitrokey is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * libnitrokey is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with libnitrokey. If not, see . - * - * SPDX-License-Identifier: LGPL-3.0 - */ - -#include "catch.hpp" - -#include -#include -#include "device_proto.h" -#include "log.h" -#include "stick10_commands.h" - -using namespace std; -using namespace nitrokey::device; -using namespace nitrokey::proto::stick10; -using namespace nitrokey::log; -using namespace nitrokey::misc; - -using Dev10 = std::shared_ptr; - -std::string getSlotName(Dev10 stick, int slotNo) { - auto slot_req = get_payload(); - slot_req.slot_number = slotNo; - auto slot = ReadSlot::CommandTransaction::run(stick, slot_req); - std::string sName(reinterpret_cast(slot.data().slot_name)); - return sName; -} - -TEST_CASE("Slot names are correct", "[slotNames]") { - auto stick = make_shared(); - bool connected = stick->connect(); - REQUIRE(connected == true); - - Log::instance().set_loglevel(Loglevel::DEBUG); - - auto resp = GetStatus::CommandTransaction::run(stick); - - auto authreq = get_payload(); - strcpy((char *)(authreq.card_password), "12345678"); - FirstAuthenticate::CommandTransaction::run(stick, authreq); - - { - auto authreq = get_payload(); - strcpy((char *)(authreq.user_password), "123456"); - EnablePasswordSafe::CommandTransaction::run(stick, authreq); - } - - //assuming these values were set earlier, thus failing on normal use - REQUIRE(getSlotName(stick, 0x20) == std::string("1")); - REQUIRE(getSlotName(stick, 0x21) == std::string("slot2")); - - { - auto resp = GetPasswordRetryCount::CommandTransaction::run(stick); - REQUIRE(resp.data().password_retry_count == 3); - } - { - auto resp = GetUserPasswordRetryCount::CommandTransaction::run(stick); - REQUIRE(resp.data().password_retry_count == 3); - } - - { - auto slot = get_payload(); - slot.slot_number = 0; - auto resp2 = GetPasswordSafeSlotName::CommandTransaction::run(stick, slot); - std::string sName(reinterpret_cast(resp2.data().slot_name)); - REQUIRE(sName == std::string("web1")); - } - - { - auto slot = get_payload(); - slot.slot_number = 0; - auto resp2 = - GetPasswordSafeSlotPassword::CommandTransaction::run(stick, slot); - std::string sName(reinterpret_cast(resp2.data().slot_password)); - REQUIRE(sName == std::string("pass1")); - } - - { - auto slot = get_payload(); - slot.slot_number = 0; - auto resp2 = GetPasswordSafeSlotLogin::CommandTransaction::run(stick, slot); - std::string sName(reinterpret_cast(resp2.data().slot_login)); - REQUIRE(sName == std::string("login1")); - } - - stick->disconnect(); -} diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_HOTP.cc nitrokey-app-1.4.1/libnitrokey/unittest/test_HOTP.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test_HOTP.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_HOTP.cc 2019-09-28 16:22:11.000000000 +0000 @@ -20,7 +20,7 @@ */ -#include "catch.hpp" +#include "catch2/catch.hpp" #include #include "device_proto.h" #include "log.h" @@ -38,7 +38,7 @@ REQUIRE(strlen(hexString)%2==0); char buf[3]; buf[2] = '\0'; - for(int i=0; i diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_library.py nitrokey-app-1.4.1/libnitrokey/unittest/test_library.py --- nitrokey-app-1.3.2/libnitrokey/unittest/test_library.py 2018-01-24 13:06:53.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_library.py 2019-09-28 16:22:11.000000000 +0000 @@ -41,6 +41,8 @@ long_string) == LibraryErrors.TOO_LONG_STRING assert gs(C.NK_get_hotp_code_PIN(0, long_string)) == b"" assert C.NK_get_last_command_status() == LibraryErrors.TOO_LONG_STRING + assert C.NK_change_firmware_password_pro(long_string, long_string) == LibraryErrors.TOO_LONG_STRING + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, long_string) == LibraryErrors.TOO_LONG_STRING def test_invalid_slot(C): diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_minimal.c nitrokey-app-1.4.1/libnitrokey/unittest/test_minimal.c --- nitrokey-app-1.3.2/libnitrokey/unittest/test_minimal.c 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_minimal.c 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#include "../NK_C_API.h" + +// This test is only intended to make sure that the C API header can be +// compiled by a C compiler. (All other tests are written in C++.) +int main() { + return 0; +} diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_multiple_devices.cc nitrokey-app-1.4.1/libnitrokey/unittest/test_multiple_devices.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test_multiple_devices.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_multiple_devices.cc 2019-09-28 16:22:11.000000000 +0000 @@ -24,20 +24,45 @@ const char * temporary_password = "123456789012345678901234"; const char * RFC_SECRET = "12345678901234567890"; -#include "catch.hpp" +#include "catch2/catch.hpp" #include #include #include +#include "../NK_C_API.h" using namespace nitrokey; TEST_CASE("List devices", "[BASIC]") { + auto v = Device::enumerate(); + REQUIRE(v.size() > 0); + for (auto i : v){ + auto d = Device::create(i.m_deviceModel); + if (!d) { + std::cout << "Could not create device with model " << i.m_deviceModel << "\n"; + continue; + } + std::cout << i.m_deviceModel << " " << i.m_path << " " + << i.m_serialNumber << " |"; + d->set_path(i.m_path); + d->connect(); + auto res = GetStatus::CommandTransaction::run(d); + std::cout << " " << res.data().card_serial_u32 << " " + << res.data().get_card_serial_hex() + << std::endl; + d->disconnect(); + } +} + +TEST_CASE("List Storage devices", "[BASIC]") { shared_ptr d = make_shared(); - auto v = d->enumerate(); + auto v = Device::enumerate(); REQUIRE(v.size() > 0); - for (auto a : v){ + for (auto i : v){ + if (i.m_deviceModel != DeviceModel::STORAGE) + continue; + auto a = i.m_path; std::cout << a; d->set_path(a); d->connect(); @@ -53,11 +78,14 @@ TEST_CASE("Regenerate AES keys", "[BASIC]") { shared_ptr d = make_shared(); - auto v = d->enumerate(); + auto v = Device::enumerate(); REQUIRE(v.size() > 0); std::vector> devices; - for (auto a : v){ + for (auto i : v){ + if (i.m_deviceModel != DeviceModel::STORAGE) + continue; + auto a = i.m_path; std::cout << a << endl; d = make_shared(); d->set_path(a); @@ -81,14 +109,57 @@ } +TEST_CASE("Use C API", "[BASIC]") { + auto ptr = NK_list_devices(); + auto first_ptr = ptr; + REQUIRE(ptr != nullptr); + + while (ptr) { + std::cout << "Connect with: " << ptr->model << " " << ptr->path << " " + << ptr->serial_number << " | " << NK_connect_with_path(ptr->path) << " | "; + auto status = NK_get_status_as_string(); + std::cout << status << std::endl; + free(status); + ptr = ptr->next; + } + + NK_free_device_info(first_ptr); +} + + TEST_CASE("Use API", "[BASIC]") { auto nm = NitrokeyManager::instance(); nm->set_loglevel(2); auto v = nm->list_devices(); REQUIRE(v.size() > 0); + for (auto i : v) { + std::cout << "Connect with: " << i.m_deviceModel << " " << i.m_path << " " + << i.m_serialNumber << " | " << std::boolalpha << nm->connect_with_path(i.m_path) << " |"; + try { + auto status = nm->get_status(); + std::cout << " " << status.card_serial_u32 << " " + << status.get_card_serial_hex() + << std::endl; + } catch (const LongOperationInProgressException &e) { + std::cout << "long operation in progress on " << i.m_path + << " " << std::to_string(e.progress_bar_value) << std::endl; + } + } +} + + +TEST_CASE("Use Storage API", "[BASIC]") { + auto nm = NitrokeyManager::instance(); + nm->set_loglevel(2); + auto v = nm->list_devices(); + REQUIRE(v.size() > 0); + for (int i=0; i<10; i++){ - for (auto a : v) { + for (auto i : v) { + if (i.m_deviceModel != DeviceModel::STORAGE) + continue; + auto a = i.m_path; std::cout <<"Connect with: " << a << " " << std::boolalpha << nm->connect_with_path(a) << " "; try{ diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_multiple.py nitrokey-app-1.4.1/libnitrokey/unittest/test_multiple.py --- nitrokey-app-1.3.2/libnitrokey/unittest/test_multiple.py 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_multiple.py 2019-09-28 16:22:11.000000000 +0000 @@ -29,12 +29,39 @@ from conftest import skip_if_device_version_lower_than from constants import DefaultPasswords, DeviceErrorCode, bb -from misc import gs, wait +from misc import gs, wait, ffi pprint = pprint.PrettyPrinter(indent=4).pprint @pytest.mark.other +@pytest.mark.info +def test_list_devices(C): + infos = C.NK_list_devices() + assert infos != ffi.NULL + C.NK_free_device_info(infos) + + +@pytest.mark.other +@pytest.mark.info +def test_connect_with_path(C): + ids = gs(C.NK_list_devices_by_cpuID()) + # NK_list_devices_by_cpuID already opened the devices, so we have to close + # them before trying to reconnect + assert C.NK_logout() == 0 + + devices_list = ids.split(b';') + for value in devices_list: + parts = value.split(b'_p_') + assert len(parts) < 3 + if len(parts) == 2: + path = parts[1] + else: + path = parts[0] + assert C.NK_connect_with_path(path) == 1 + + +@pytest.mark.other @pytest.mark.info def test_get_status_storage_multiple(C): ids = gs(C.NK_list_devices_by_cpuID()) diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_offline.cc nitrokey-app-1.4.1/libnitrokey/unittest/test_offline.cc --- nitrokey-app-1.3.2/libnitrokey/unittest/test_offline.cc 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_offline.cc 2019-09-28 16:22:11.000000000 +0000 @@ -19,9 +19,11 @@ * SPDX-License-Identifier: LGPL-3.0 */ -#include "catch.hpp" +#include "catch2/catch.hpp" #include #include +#include +#include #include "../NK_C_API.h" using namespace nitrokey::proto; @@ -113,7 +115,7 @@ REQUIRE_NOTHROW(v = hex_string_to_byte("00112233445566")); const uint8_t test_data[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; REQUIRE(v.size() == sizeof(test_data)); - for (int i = 0; i < v.size(); ++i) { + for (size_t i = 0; i < v.size(); ++i) { INFO("Position i: " << i); REQUIRE(v[i] == test_data[i]); } @@ -160,3 +162,49 @@ REQUIRE(STICK20_CMD_CHANGE_UPDATE_PIN == static_cast(CommandID::CHANGE_UPDATE_PIN)); } + +#include "version.h" +TEST_CASE("Test version getter", "[fast]") { + REQUIRE(nitrokey::get_major_library_version() >= 3u); + REQUIRE(nitrokey::get_minor_library_version() >= 3u); + const char *library_version = nitrokey::get_library_version(); + REQUIRE(library_version != nullptr); + CAPTURE(library_version); + + // The library version has to match the pattern returned by git describe: + // v. or v.--g, where is the number + // of commits since the last tag, and is the hash of the current + // commit. (This assumes that all tags have the name v..). + // Optional field is allowed as well. + INFO("This test will fail, if the full git commit version was not collected during library build."); + std::string s = library_version; + std::string version("(pre-)?v[0-9]+\\.[0-9]+(\\.[0-9]+)?"); + std::string git_suffix("(-[0-9]+)+-g[0-9a-z]+"); + std::regex pattern(version + "(" + git_suffix + ")?"); + REQUIRE(std::regex_match(s, pattern)); +} + +TEST_CASE("Connect should not return true after the second attempt", "[fast]") { + int result = 0; + + result = NK_login("S"); + REQUIRE(result == 0); + + result = NK_login_auto(); + REQUIRE(result == 0); + + result = NK_logout(); + REQUIRE(result == 0); + + result = NK_logout(); + REQUIRE(result == 0); + + result = NK_login("P"); + REQUIRE(result == 0); + + result = NK_login_auto(); + REQUIRE(result == 0); + + result = NK_logout(); + REQUIRE(result == 0); +} diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_offline.py nitrokey-app-1.4.1/libnitrokey/unittest/test_offline.py --- nitrokey-app-1.3.2/libnitrokey/unittest/test_offline.py 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_offline.py 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,39 @@ +""" +Copyright (c) 2019 Nitrokey UG + +This file is part of libnitrokey. + +libnitrokey is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +any later version. + +libnitrokey is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with libnitrokey. If not, see . + +SPDX-License-Identifier: LGPL-3.0 +""" + +from misc import gs +import re + + +def test_offline(C_offline): + C_offline.NK_set_debug(False) + C_offline.NK_set_debug_level(4) + assert C_offline.NK_get_major_library_version() == 3 + assert C_offline.NK_get_minor_library_version() >= 3 + assert C_offline.NK_login_auto() == 0 + + libnk_version = gs(C_offline.NK_get_library_version()) + assert libnk_version + print(libnk_version) + + # v3.4.1-29-g1f3d + search = re.search(b'v\d\.\d(\.\d)?', libnk_version) + assert search is not None \ No newline at end of file diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_pro.py nitrokey-app-1.4.1/libnitrokey/unittest/test_pro.py --- nitrokey-app-1.3.2/libnitrokey/unittest/test_pro.py 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_pro.py 2019-09-28 16:22:11.000000000 +0000 @@ -1,5 +1,5 @@ """ -Copyright (c) 2015-2018 Nitrokey UG +Copyright (c) 2015-2019 Nitrokey UG This file is part of libnitrokey. @@ -22,9 +22,10 @@ import pytest from conftest import skip_if_device_version_lower_than -from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, bb, bbRFC_SECRET -from misc import ffi, gs, wait, cast_pointer_to_tuple -from misc import is_pro_rtm_07, is_pro_rtm_08, is_storage +from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, bb, bbRFC_SECRET, LibraryErrors, HOTP_slot_count, \ + TOTP_slot_count +from misc import ffi, gs, wait, cast_pointer_to_tuple, has_binary_counter +from misc import is_storage @pytest.mark.lock_device @pytest.mark.PWS @@ -192,7 +193,8 @@ assert C.NK_clear_new_sd_card_warning(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK enable_password_safe_result = C.NK_enable_password_safe(DefaultPasswords.USER) assert enable_password_safe_result == DeviceErrorCode.STATUS_AES_DEC_FAILED \ - or is_storage(C) and enable_password_safe_result == DeviceErrorCode.WRONG_PASSWORD + or is_storage(C) and enable_password_safe_result in \ + [DeviceErrorCode.WRONG_PASSWORD, DeviceErrorCode.STATUS_UNKNOWN_ERROR] # UNKNOWN_ERROR since v0.51 assert C.NK_build_aes_key(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK @@ -408,7 +410,7 @@ INT32_MAX = 2 ** 31 - 1 @pytest.mark.otp def test_HOTP_64bit_counter(C): - if is_storage(C): + if not has_binary_counter(C): pytest.xfail('bug in NK Storage HOTP firmware - counter is set with a 8 digits string, ' 'however int32max takes 10 digits to be written') oath = pytest.importorskip("oath") @@ -430,27 +432,46 @@ lib_res += (t, lib_at(t)) assert dev_res == lib_res +def helper_set_HOTP_test_slot(C, slot_number): + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_hotp_slot(slot_number, b'python_test', bbRFC_SECRET, 0, False, False, True, b'', DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK -@pytest.mark.otp -def test_TOTP_64bit_time(C): - if is_storage(C): - pytest.xfail('bug in NK Storage TOTP firmware') - oath = pytest.importorskip("oath") - T = 1 - lib_at = lambda t: bb(oath.totp(RFC_SECRET, t=t)) + +def helper_set_TOTP_test_slot(C, slot_number): PIN_protection = False - slot_number = 1 assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_write_config(255, 255, 255, PIN_protection, not PIN_protection, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_write_totp_slot(slot_number, b'python_test', bbRFC_SECRET, 30, False, False, False, b'', DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + + +def helper_set_time_on_device(C, t): + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_totp_set_time(t) == DeviceErrorCode.STATUS_OK + + +@pytest.mark.otp +@pytest.mark.parametrize("t_values",[ + range(INT32_MAX - 5, INT32_MAX + 5, 1), + [2**31, 2**32, 2**33, 2**34, 2**40, 2**50, 2**60], + pytest.param([2**61-1, 2**62-1, 2**63-1, 2**64-1], marks=pytest.mark.xfail), + ]) +def test_TOTP_64bit_time(C, t_values): + if not has_binary_counter(C): + pytest.xfail('bug in NK Storage TOTP firmware') + oath = pytest.importorskip("oath") + T = 1 + slot_number = 1 + lib_at = lambda t: bb(oath.totp(RFC_SECRET, t=t)) + + helper_set_TOTP_test_slot(C, slot_number) + dev_res = [] lib_res = [] - for t in range(INT32_MAX - 5, INT32_MAX + 5, 1): - assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK - assert C.NK_totp_set_time(t) == DeviceErrorCode.STATUS_OK + for t in t_values: + helper_set_time_on_device(C, t) code_device = gs((C.NK_get_totp_code(slot_number, T, 0, 30))) dev_res += (t, code_device) lib_res += (t, lib_at(t)) @@ -514,11 +535,11 @@ assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_erase_hotp_slot(0, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK - for i in range(15): + for i in range(TOTP_slot_count): name = ffi.string(C.NK_get_totp_slot_name(i)) if name == '': assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED - for i in range(3): + for i in range(HOTP_slot_count): name = ffi.string(C.NK_get_hotp_slot_name(i)) if name == '': assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED @@ -528,12 +549,12 @@ def test_get_OTP_codes(C): assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_write_config(255, 255, 255, False, True, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK - for i in range(15): + for i in range(TOTP_slot_count): code = gs(C.NK_get_totp_code(i, 0, 0, 0)) if code == b'': assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED - for i in range(3): + for i in range(HOTP_slot_count): code = gs(C.NK_get_hotp_code(i)) if code == b'': assert C.NK_get_last_command_status() == DeviceErrorCode.NOT_PROGRAMMED @@ -577,6 +598,69 @@ assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK +def helper_get_TOTP_code(C,i): + code = gs(C.NK_get_totp_code(i, 0, 0, 30)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + assert code != b'' + return code + + +def helper_get_HOTP_code(C,i): + code = gs(C.NK_get_hotp_code(i)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + assert code != b'' + return code + + +@pytest.mark.otp +def test_authorize_issue_admin(C): + skip_if_device_version_lower_than({'S': 43, 'P': 9}) + + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_config(255, 255, 255, True, False, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + + assert C.NK_first_authenticate(b"wrong pass", b"another temp pass") == DeviceErrorCode.WRONG_PASSWORD + assert C.NK_write_config(255, 255, 255, False, True, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_NOT_AUTHORIZED + + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_config(255, 255, 255, True, False, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + +@pytest.mark.otp +def test_authorize_issue_user(C): + skip_if_device_version_lower_than({'S': 43, 'P': 9}) # issue fixed in Pro v0.9, Storage version chosen arbitrary + + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_totp_slot(0, b'python_otp_auth', bbRFC_SECRET, 30, True, False, False, b'', + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + # enable PIN protection of OTP codes with write_config + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_config(255, 255, 255, True, False, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + gs(C.NK_get_totp_code(0, 0, 0, 0)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_NOT_AUTHORIZED + + assert C.NK_user_authenticate(DefaultPasswords.USER, DefaultPasswords.USER_TEMP) == DeviceErrorCode.STATUS_OK + gs(C.NK_get_totp_code_PIN(0, 0, 0, 0, DefaultPasswords.USER_TEMP)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + + assert C.NK_user_authenticate(b"wrong pass", b"another temp pass") == DeviceErrorCode.WRONG_PASSWORD + gs(C.NK_get_totp_code_PIN(0, 0, 0, 0, DefaultPasswords.USER_TEMP)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_NOT_AUTHORIZED + + assert C.NK_user_authenticate(DefaultPasswords.USER, DefaultPasswords.USER_TEMP) == DeviceErrorCode.STATUS_OK + gs(C.NK_get_totp_code_PIN(0, 0, 0, 0, DefaultPasswords.USER_TEMP)) + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + + # disable PIN protection with write_config + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_config(255, 255, 255, False, True, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + code = gs(C.NK_get_totp_code(0, 0, 0, 0)) + assert code != b'' + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + def cast_pointer_to_tuple(obj, typen, len): # usage: # config = cast_pointer_to_tuple(config_raw_data, 'uint8_t', 5) @@ -624,11 +708,23 @@ @pytest.mark.status -def test_get_status(C): - status = C.NK_status() +def test_get_status_as_string(C): + status = C.NK_get_status_as_string() s = gs(status) assert len(s) > 0 + +@pytest.mark.status +def test_get_status(C): + status_st = ffi.new('struct NK_status *') + if not status_st: + raise Exception("Could not allocate status") + err = C.NK_get_status(status_st) + assert err == 0 + assert status_st.firmware_version_major == 0 + assert status_st.firmware_version_minor != 0 + + @pytest.mark.status def test_get_serial_number(C): sn = C.NK_device_serial_number() @@ -647,7 +743,7 @@ skip_if_device_version_lower_than({'S': 43, 'P': 8}) if len(secret) > 40: # feature: 320 bit long secret handling - skip_if_device_version_lower_than({'P': 8}) + skip_if_device_version_lower_than({'P': 8, 'S': 54}) oath = pytest.importorskip("oath") lib_at = lambda t: bb(oath.hotp(secret, t, format='dec6')) @@ -679,8 +775,8 @@ :param counter: """ if counter >= 1e7: - # Storage does not handle counters longer than 7 digits - skip_if_device_version_lower_than({'P': 7}) + # Storage v0.53 and below does not handle counters longer than 7 digits + skip_if_device_version_lower_than({'P': 7, 'S': 54}) secret = RFC_SECRET oath = pytest.importorskip("oath") @@ -692,7 +788,7 @@ DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK dev_res = [] lib_res = [] - for slot_number in range(3): + for slot_number in range(HOTP_slot_count): assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_write_hotp_slot(slot_number, b'HOTP rw' + bytes(slot_number), bb(secret), counter, use_8_digits, False, False, b"", DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK @@ -721,7 +817,7 @@ DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK dev_res = [] lib_res = [] - for slot_number in range(15): + for slot_number in range(TOTP_slot_count): assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK assert C.NK_write_totp_slot(slot_number, b'TOTP rw' + bytes(slot_number), bb(secret), period, use_8_digits, False, False, b"", DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK @@ -742,8 +838,8 @@ skip_if_device_version_lower_than({'S': 44, 'P': 8}) if len(secret)>20*2: #*2 since secret is in hex - # pytest.skip("Secret lengths over 20 bytes are not supported by NK Pro 0.7 and NK Storage") - skip_if_device_version_lower_than({'P': 8}) + # pytest.skip("Secret lengths over 20 bytes are not supported by NK Pro 0.7 and NK Storage v0.53 and older") + skip_if_device_version_lower_than({'P': 8, 'S': 54}) slot_number = 0 time = 0 period = 30 @@ -774,7 +870,7 @@ feature needed: support for 320bit secrets """ if len(secret)>40: - skip_if_device_version_lower_than({'P': 8}) + skip_if_device_version_lower_than({'P': 8, 'S': 54}) slot_number = 0 counter = 0 @@ -872,3 +968,128 @@ lib_at = lambda : bb(oath.totp(secret, period=period)) print (lib_at()) assert lib_at() == code_device + + +def test_get_device_model(C): + assert C.NK_get_device_model() != 0 + # assert C.NK_get_device_model() != C.NK_DISCONNECTED + + +@pytest.mark.firmware +def test_bootloader_password_change_pro(C): + skip_if_device_version_lower_than({'P': 11}) + assert C.NK_change_firmware_password_pro(b'zxcasd', b'zxcasd') == DeviceErrorCode.WRONG_PASSWORD + + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + + +@pytest.mark.firmware +def test_bootloader_run_pro(C): + skip_if_device_version_lower_than({'P': 11}) + assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD + # Not enabled due to lack of side-effect removal at this point + # assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + + +@pytest.mark.firmware +def test_bootloader_password_change_pro_too_long(C): + skip_if_device_version_lower_than({'P': 11}) + long_string = b'a' * 100 + assert C.NK_change_firmware_password_pro(long_string, long_string) == LibraryErrors.TOO_LONG_STRING + assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, long_string) == LibraryErrors.TOO_LONG_STRING + + +@pytest.mark.otp +@pytest.mark.parametrize('counter_mid', [10**3-1, 10**4-1, 10**7-1, 10**8-10, 2**16, 2**31-1, 2**32-1, 2**33, 2**50, 2**60, 2**63]) # 2**64-1 +def test_HOTP_counter_getter(C, counter_mid: int): + if len(str(counter_mid)) > 8: + skip_if_device_version_lower_than({'S': 54, 'P': 7}) + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + use_pin_protection = False + use_8_digits = False + assert C.NK_write_config(255, 255, 255, use_pin_protection, not use_pin_protection, + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + read_slot_st = ffi.new('struct ReadSlot_t *') + if not read_slot_st: + raise Exception("Could not allocate status") + slot_number = 1 + for counter in range(counter_mid-3, counter_mid+3): + # assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_hotp_slot(slot_number, b'python_test', bbRFC_SECRET, counter, use_8_digits, False, False, b'', + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_read_HOTP_slot(slot_number, read_slot_st) == DeviceErrorCode.STATUS_OK + assert read_slot_st.slot_counter == counter + + +@pytest.mark.otp +def test_edge_OTP_slots(C): + # -> shows TOTP15 is not written + # -> assuming HOTP1 is written + # (optional) Write slot HOTP1 + # Write slot TOTP15 + # Wait + # Read slot TOTP15 details + # Read HOTP1 details + # returns SLOT_NOT_PROGRAMMED + # (next nkapp execution) + # -> shows HOTP1 is not written + # briefly writing TOTP15 clears HOTP1, and vice versa + + read_slot_st = ffi.new('struct ReadSlot_t *') + if not read_slot_st: + raise Exception("Could not allocate status") + use_pin_protection = False + use_8_digits = False + assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_config(255, 255, 255, use_pin_protection, not use_pin_protection, + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + counter = 0 + HOTP_slot_number = 1 -1 + TOTP_slot_number = TOTP_slot_count -1 # 0 based + assert C.NK_write_totp_slot(TOTP_slot_number, b'python_test', bbRFC_SECRET, 30, False, False, False, b'', + DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_write_hotp_slot(HOTP_slot_number, b'python_test', bbRFC_SECRET, counter, use_8_digits, False, False, b'', DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK + for i in range(5): + code_hotp = gs(C.NK_get_hotp_code(HOTP_slot_number)) + assert code_hotp + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + assert C.NK_read_HOTP_slot(HOTP_slot_number, read_slot_st) == DeviceErrorCode.STATUS_OK + assert read_slot_st.slot_counter == (i+1) + helper_set_time_on_device(C, 1) + code_totp = gs((C.NK_get_totp_code(TOTP_slot_number, 0, 0, 30))) + assert code_totp + assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK + + +@pytest.mark.otp +def test_OTP_all_rw(C): + """ + Write all OTP slots and read codes from them two times. + All generated codes should be the same, which is checked as well. + """ + for i in range(TOTP_slot_count): + helper_set_TOTP_test_slot(C, i) + for i in range(HOTP_slot_count): + helper_set_HOTP_test_slot(C, i) + all_codes = [] + for i in range(5): + this_loop_codes = [] + code_old = b'' + helper_set_time_on_device(C, 30*i) + for i in range(TOTP_slot_count): + code = helper_get_TOTP_code(C, i) + if code_old: + assert code == code_old + code_old = code + this_loop_codes.append(('T', i, code)) + code_old = b'' + for i in range(HOTP_slot_count): + code = helper_get_HOTP_code(C, i) + if code_old: + assert code == code_old + code_old = code + this_loop_codes.append(('H', i, code)) + all_codes.append(this_loop_codes) + from pprint import pprint + pprint(all_codes) \ No newline at end of file diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_safe.cpp nitrokey-app-1.4.1/libnitrokey/unittest/test_safe.cpp --- nitrokey-app-1.3.2/libnitrokey/unittest/test_safe.cpp 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_safe.cpp 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#include "catch2/catch.hpp" + +#include +#include +#include "log.h" +#include "../NK_C_API.h" + +int login; + +TEST_CASE("C API connect", "[BASIC]") { + INFO("This test set assumes either Pro or Storage device is connected."); + INFO("Here should be implemented only tests not changing the device's state, " + "and safe to user data."); + + login = NK_login_auto(); + REQUIRE(login != 0); + NK_set_debug_level(3); +} + +TEST_CASE("Check retry count", "[BASIC]") { + INFO("This test assumes your PINs' attempt counters are set to 3"); + REQUIRE(login != 0); + REQUIRE(NK_get_admin_retry_count() == 3); + REQUIRE(NK_get_user_retry_count() == 3); +} + +void validate_cstring(char *s){ + constexpr uint16_t max_length = 8*1024; + REQUIRE(s != nullptr); + REQUIRE(strnlen(s, max_length) > 0); + REQUIRE(strnlen(s, max_length) < max_length); + std::cout << s << std::endl; +} + +TEST_CASE("Status command for Pro or Storage", "[BASIC]") { + REQUIRE(login != 0); + char* s = nullptr; + + auto const m = NK_get_device_model(); + REQUIRE(m != NK_DISCONNECTED); + if (m == NK_PRO) + s = NK_get_status_as_string(); + else if (m == NK_STORAGE){ + s = NK_get_status_storage_as_string(); + } + + validate_cstring(s); + free(s); + s = nullptr; +} + +TEST_CASE("Device serial", "[BASIC]") { + REQUIRE(login != 0); + char* s = nullptr; + s = NK_device_serial_number(); + validate_cstring(s); + free(s); + s = nullptr; +} + +TEST_CASE("Firmware version", "[BASIC]") { + REQUIRE(login != 0); + // Currently all devices has major version '0' + // No firmware ever had a minor equal to '0' + REQUIRE(NK_get_major_firmware_version() == 0); + REQUIRE(NK_get_minor_firmware_version() != 0); +} + +TEST_CASE("Library version", "[BASIC]") { + REQUIRE(NK_get_major_library_version() == 3); + REQUIRE(NK_get_minor_library_version() >= 4); +} diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_storage.py nitrokey-app-1.4.1/libnitrokey/unittest/test_storage.py --- nitrokey-app-1.3.2/libnitrokey/unittest/test_storage.py 2018-05-13 08:58:38.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_storage.py 2019-09-28 16:22:11.000000000 +0000 @@ -1,5 +1,5 @@ """ -Copyright (c) 2015-2018 Nitrokey UG +Copyright (c) 2015-2019 Nitrokey UG This file is part of libnitrokey. @@ -24,7 +24,8 @@ from conftest import skip_if_device_version_lower_than from constants import DefaultPasswords, DeviceErrorCode, bb -from misc import gs, wait +from misc import gs, wait, ffi + pprint = pprint.PrettyPrinter(indent=4).pprint @@ -352,13 +353,14 @@ assert C.NK_change_update_password(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK -@pytest.mark.skip(reason='no reversing method added yet') +# @pytest.mark.skip(reason='no reversing method added yet') @pytest.mark.update def test_enable_firmware_update(C): skip_if_device_version_lower_than({'S': 50}) wrong_password = b'aaaaaaaaaaa' assert C.NK_enable_firmware_update(wrong_password) == DeviceErrorCode.WRONG_PASSWORD - assert C.NK_enable_firmware_update(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + # skip actual test - reason: no reversing method added yet + # assert C.NK_enable_firmware_update(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK @pytest.mark.other @@ -366,3 +368,214 @@ skip_if_device_version_lower_than({'S': 43}) time_seconds_from_epoch = 0 # FIXME set proper date assert C.NK_send_startup(time_seconds_from_epoch) == DeviceErrorCode.STATUS_OK + + +@pytest.mark.other +def test_struct_multiline_prodtest(C): + info_st = ffi.new('struct NK_storage_ProductionTest *') + if info_st is None: raise Exception('Invalid value') + err = C.NK_get_storage_production_info(info_st) + assert err == 0 + assert info_st.SD_Card_ManufacturingYear_u8 != 0 + assert info_st.SD_Card_ManufacturingMonth_u8 != 0 + assert info_st.SD_Card_Size_u8 != 0 + assert info_st.FirmwareVersion_au8[0] == 0 + assert info_st.FirmwareVersion_au8[1] >= 50 + + info = 'CPU:{CPU},SC:{SC},SD:{SD},' \ + 'SCM:{SCM},SCO:{SCO},DAT:{DAT},Size:{size},Firmware:{fw} - {fwb}'.format( + CPU='0x{:08x}'.format(info_st.CPU_CardID_u32), + SC='0x{:08x}'.format(info_st.SmartCardID_u32), + SD='0x{:08x}'.format(info_st.SD_CardID_u32), + SCM='0x{:02x}'.format(info_st.SD_Card_Manufacturer_u8), + SCO='0x{:04x}'.format(info_st.SD_Card_OEM_u16), + DAT='20{}.{}'.format(info_st.SD_Card_ManufacturingYear_u8, info_st.SD_Card_ManufacturingMonth_u8), + size=info_st.SD_Card_Size_u8, + fw='{}.{}'.format(info_st.FirmwareVersion_au8[0], info_st.FirmwareVersion_au8[1]), + fwb=info_st.FirmwareVersionInternal_u8 + ) + print(info) + +@pytest.mark.other +@pytest.mark.firmware +def test_export_firmware_extended_fedora29(C): + """ + Check, whether the firmware file is exported correctly, and in correct size. + Apparently, the auto-remounting side effect of the v0.46 change, is disturbing the export process. + Unmounting the UV just before the export gives the device 20/20 success rate. + Test case for issue https://github.com/Nitrokey/nitrokey-app/issues/399 + """ + + skip_if_device_version_lower_than({'S': 43}) + skip_if_not_fedora('Tested on Fedora only. To check on other distros.') + + from time import sleep + import os + from os.path import exists as exist + import re + try: + import pyudev as pu + import pexpect + except: + pytest.skip('Skipping due to missing required packages: pyudev and pexpect.') + + ctx = pu.Context() + devices = ctx.list_devices(subsystem='block', ID_VENDOR='Nitrokey') + device = None + for d in devices: + if d.device_type == 'partition': + device = '/dev/{}'.format(d.sys_name) + break + assert device, 'Device could not be found' + + pexpect.run(f'udisksctl unmount -b {device}').decode() + sleep(1) + _res = pexpect.run(f'udisksctl mount -b {device}').decode() + firmware_abs_path = re.findall('at (/.*)\.', _res) + assert firmware_abs_path, 'Cannot get mount point' + firmware_abs_path = firmware_abs_path[0] + + print('path: {}, device: {}'.format(firmware_abs_path, device)) + assert firmware_abs_path, 'Cannot get mount point' + firmware_abs_path = firmware_abs_path + '/firmware.bin' + + checks = 0 + checks_add = 0 + + if exist(firmware_abs_path): + os.remove(firmware_abs_path) + + assert not exist(firmware_abs_path) + + ATTEMPTS = 20 + for i in range(ATTEMPTS): + # if umount is disabled, success rate is 3/10, enabled: 10/10 + pexpect.run(f'udisksctl unmount -b {device}') + assert C.NK_export_firmware(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + pexpect.run(f'udisksctl mount -b {device}') + sleep(1) + firmware_file_exist = exist(firmware_abs_path) + if firmware_file_exist: + checks += 1 + getsize = os.path.getsize(firmware_abs_path) + print('Firmware file exist, size: {}'.format(getsize)) + checks_add += 1 if getsize >= 100 * 1024 else 0 + # checks_add += 1 if os.path.getsize(firmware_abs_path) == 256*1024 else 0 + os.remove(firmware_abs_path) + assert not exist(firmware_abs_path) + + print('CHECK {} ; CHECK ADDITIONAL {}'.format(checks, checks_add)) + + assert checks == ATTEMPTS + assert checks_add == checks + + +def skip_if_not_fedora(message:str) -> None: + import os + from os.path import exists as exist + + def skip(): + pytest.skip(message) + + os_release_fp = '/etc/os-release' + if not exist(os_release_fp): + skip() + with open(os_release_fp) as f: + os_release_lines = f.readlines() + if 'Fedora' not in os_release_lines[0]: + skip() + + +@pytest.mark.other +@pytest.mark.firmware +def test_export_firmware_extended_macos(C): + """ + Check, whether the firmware file is exported correctly, and in correct size. + Apparently, the auto-remounting side effect of the v0.46 change, is disturbing the export process. + Unmounting the UV just before the export gives the device 20/20 success rate. + Test case for issue https://github.com/Nitrokey/nitrokey-app/issues/399 + """ + + skip_if_device_version_lower_than({'S': 43}) + skip_if_not_macos('macOS specific test, due to the mount path and command.') + + import pexpect + from time import sleep + import os + from os.path import exists as exist + import plistlib + + usb_devices = pexpect.run('system_profiler -xml SPUSBDataType') + assert b'Nitrokey' in usb_devices, 'No Nitrokey devices connected' + usb_devices_parsed = plistlib.loads(usb_devices) + + assert isinstance(usb_devices_parsed, list), 'usb_devices_parsed has unexpected type' + + # Try to get all USB devices + try: + devices = usb_devices_parsed[0]['_items'][0]['_items'] + except KeyError: + devices = None + + assert devices is not None, 'could not list USB devices' + + device_item = None + + for item in devices: + if '_items' in item: + # Fix for macOS 10.13.6, Python 3.6.2 + item = item['_items'][0] + if 'manufacturer' in item and item['manufacturer'] == 'Nitrokey': + device_item = item + + # Try to get first volume of USB device + try: + volume = device_item['Media'][0]['volumes'][0] + except (KeyError, TypeError): + volume = None + + assert volume is not None, 'could not determine volume' + assert 'bsd_name' in volume, 'could not get BSD style device name' + + device = '/dev/' + volume['bsd_name'] + pexpect.run(f'diskutil mount {device}') + sleep(3) + assert 'mount_point' in volume, 'could not get mount point' + firmware_abs_path = volume['mount_point'] + '/firmware.bin' + checks = 0 + print('path: {}, device: {}'.format(firmware_abs_path, device)) + checks_add = 0 + + if exist(firmware_abs_path): + os.remove(firmware_abs_path) + + assert not exist(firmware_abs_path) + + ATTEMPTS = 20 + for i in range(ATTEMPTS): + # if umount is disabled, success rate is 3/10, enabled: 10/10 + pexpect.run(f'diskutil unmount {device}') + assert C.NK_export_firmware(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + pexpect.run(f'diskutil mount {device}') + sleep(1) + firmware_file_exist = exist(firmware_abs_path) + if firmware_file_exist: + checks += 1 + getsize = os.path.getsize(firmware_abs_path) + print('Firmware file exist, size: {}'.format(getsize)) + checks_add += 1 if getsize >= 100 * 1024 else 0 + # checks_add += 1 if os.path.getsize(firmware_abs_path) == 256*1024 else 0 + os.remove(firmware_abs_path) + assert not exist(firmware_abs_path) + + print('CHECK {} ; CHECK ADDITIONAL {}'.format(checks, checks_add)) + + assert checks == ATTEMPTS + assert checks_add == checks + + +def skip_if_not_macos(message:str) -> None: + import platform + + if platform.system() != 'Darwin': + pytest.skip(message) diff -Nru nitrokey-app-1.3.2/libnitrokey/unittest/test_strdup.cpp nitrokey-app-1.4.1/libnitrokey/unittest/test_strdup.cpp --- nitrokey-app-1.3.2/libnitrokey/unittest/test_strdup.cpp 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/unittest/test_strdup.cpp 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015-2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +// issue: https://github.com/Nitrokey/libnitrokey/issues/110 +// tests according to the issue's author, Robin Krahl (robinkrahl) +// suggested run command: valgrind --tool=memcheck --leak-check=full ./test_strdup + +#include +#include +#include "../NK_C_API.h" +#include "catch2/catch.hpp" + + +static const int SHORT_STRING_LENGTH = 10; + +TEST_CASE("Test strdup memory free error", "[BASIC]") +{ + NK_set_debug(false); + char *c = NK_get_status_as_string(); /* error --> string literal */ + REQUIRE(c != nullptr); + REQUIRE(strnlen(c, SHORT_STRING_LENGTH) == 0); + puts(c); + free(c); +} + +TEST_CASE("Test strdup memory leak", "[BASIC]") +{ + NK_set_debug(false); + bool connected = NK_login_auto() == 1; + if (!connected) return; + + REQUIRE(connected); + char *c = NK_get_status_as_string(); /* no error --> dynamically allocated */ + REQUIRE(c != nullptr); + REQUIRE(strnlen(c, SHORT_STRING_LENGTH) > 0); + puts(c); + free(c); +} + diff -Nru nitrokey-app-1.3.2/libnitrokey/version.cc nitrokey-app-1.4.1/libnitrokey/version.cc --- nitrokey-app-1.3.2/libnitrokey/version.cc 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/version.cc 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#include "version.h" + +namespace nitrokey { + unsigned int get_major_library_version() { + return 3; + } + + unsigned int get_minor_library_version() { + return 0; + } + + const char* get_library_version() { + return "unknown"; + } +} + diff -Nru nitrokey-app-1.3.2/libnitrokey/version.cc.in nitrokey-app-1.4.1/libnitrokey/version.cc.in --- nitrokey-app-1.3.2/libnitrokey/version.cc.in 1970-01-01 00:00:00.000000000 +0000 +++ nitrokey-app-1.4.1/libnitrokey/version.cc.in 2019-09-28 16:22:11.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Nitrokey UG + * + * This file is part of libnitrokey. + * + * libnitrokey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * libnitrokey is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnitrokey. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0 + */ + +#include "version.h" + +namespace nitrokey { + unsigned int get_major_library_version() { + return @PROJECT_VERSION_MAJOR@; + } + + unsigned int get_minor_library_version() { + return @PROJECT_VERSION_MINOR@; + } + + const char* get_library_version() { + return "@PROJECT_VERSION_GIT@"; + } +} + diff -Nru nitrokey-app-1.3.2/nitrokey-app-qt5.pro nitrokey-app-1.4.1/nitrokey-app-qt5.pro --- nitrokey-app-1.3.2/nitrokey-app-qt5.pro 2018-12-12 12:23:09.000000000 +0000 +++ nitrokey-app-1.4.1/nitrokey-app-qt5.pro 2020-08-06 10:07:14.000000000 +0000 @@ -22,13 +22,13 @@ TARGET = nitrokey-app TEMPLATE = app -VERSION = 1.3.2 -VERSION_STR = 1.3.2 +VERSION = 1.4.1 +VERSION_STR = 1.4.1 QMAKE_TARGET_COMPANY = Nitrokey QMAKE_TARGET_PRODUCT = Nitrokey App QMAKE_TARGET_DESCRIPTION = Nitrokey Device Manager -QMAKE_TARGET_COPYRIGHT = Copyright (c) 2012-2018 Nitrokey UG +QMAKE_TARGET_COPYRIGHT = Copyright (c) 2012-2020 Nitrokey UG ROOTDIR=$$PWD diff -Nru nitrokey-app-1.3.2/README.md nitrokey-app-1.4.1/README.md --- nitrokey-app-1.3.2/README.md 2018-06-26 15:47:20.000000000 +0000 +++ nitrokey-app-1.4.1/README.md 2019-09-28 16:20:07.000000000 +0000 @@ -47,19 +47,21 @@ - `build-essential` - for building applications - `cmake` - for compiling libnitrokey - `qt5-default` - QT5 library -- `qttools5-dev-tools` - QT5 library tools - generating translations +- `qttools5-dev` and `qttools5-dev-tools` - QT5 library tools - generating translations - `libqt5svg5-dev` - QT5 library for rendering SVG - `libqt5concurrent5` - QT5 library for concurrent calls - `pkg-config` - system libraries detection -- `libnitrokey` v3.3 - compiled only, if not already installed in the OS +- `libnitrokey` (v3.3+) - this is built only, if not already installed in the OS (otherwise App will use system library) - `libusb-1.0-0-dev` - library to communicate with USB devices - `libhidapi-dev` - to communicate using HID layer Whole command for Ubuntu: ``` -sudo apt-get install libusb-1.0.0-dev cmake qt5-default qttools5-dev-tools pkg-config libhidapi-dev build-essential libqt5svg5-dev libqt5concurrent5 +sudo apt-get install libusb-1.0.0-dev cmake qt5-default qttools5-dev qttools5-dev-tools pkg-config libhidapi-dev build-essential libqt5svg5-dev libqt5concurrent5 ``` +During the compilation CMake will test via `pkg-config`, whether system libnitrokey is available, and is it at least [LIBNK_MIN_VERSION](https://github.com/Nitrokey/nitrokey-app/blob/d6fad2bd1aecbda2e36d4e9873f613ef5bf7649d/CMakeLists.txt#L210) version. On failed test libnitrokey will be compiled as well. + #### Getting the Nitrokey Sources Clone the Nitrokey-App repository using `git` and `--recursive` switch: @@ -195,4 +197,4 @@ which means App requests the data only when it needs them (it was earlier loading all OTP slot data to memory). Migration to `libnitrokey` comes with a cost of increasing compiler's requirements to be compliant with C++14 standard. -Fortunately most compatible compilers have been released in 2015 and all current ones should work. \ No newline at end of file +Fortunately most compatible compilers have been released in 2015 and all current ones should work. diff -Nru nitrokey-app-1.3.2/resources.qrc nitrokey-app-1.4.1/resources.qrc --- nitrokey-app-1.3.2/resources.qrc 2018-12-12 12:23:09.000000000 +0000 +++ nitrokey-app-1.4.1/resources.qrc 2019-09-28 16:20:07.000000000 +0000 @@ -28,6 +28,7 @@ images/new/icon_passwords.svg images/new/icon_quit.svg images/new/icon_safe.svg + images/new/icon_unsafe.svg images/new/icon_settings.svg images/new/icon_warning.svg diff -Nru nitrokey-app-1.3.2/src/GUI/Tray.cpp nitrokey-app-1.4.1/src/GUI/Tray.cpp --- nitrokey-app-1.3.2/src/GUI/Tray.cpp 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/GUI/Tray.cpp 2019-09-28 16:20:07.000000000 +0000 @@ -69,6 +69,11 @@ destroyThread(); } +void Tray::delayedShowIndicator(){ + if(!trayIcon->isSystemTrayAvailable()) return; + trayIcon->show(); + delayedShowTimer->stop(); +} /* * Create the tray menu. @@ -79,7 +84,10 @@ connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); - trayIcon->show(); + delayedShowTimer = new QTimer(this); + connect(delayedShowTimer, SIGNAL(timeout()), this, SLOT(delayedShowIndicator())); + delayedShowTimer->setSingleShot(false); + delayedShowTimer->start(2000); // Initial message if (debug_mode) @@ -394,6 +402,7 @@ SLOT(startResetUserPassword())); LockDeviceAction = new QAction(tr("&Lock Device"), main_window); + LockDeviceAction->setIcon(GraphicsTools::loadColorize(":/images/new/icon_unsafe.svg")); connect(LockDeviceAction, SIGNAL(triggered()), main_window, SLOT(startLockDeviceAction())); Stick20ActionUpdateStickStatus = new QAction(tr("Smartcard or SD card are not ready"), main_window); @@ -476,6 +485,10 @@ //should not run before worker is done QMutexLocker mutexLocker(&worker->mtx); + if (!trayMenuPasswdSubMenu->actions().empty()) { + return; + } + for (int i=0; i < TOTP_SLOT_COUNT; i++){ auto slotName = libada::i()->getTOTPSlotName(i); @@ -530,9 +543,6 @@ trayMenuSubConfigure = trayMenu->addMenu(tr("Configure")); trayMenuSubConfigure->setIcon(GraphicsTools::loadColorize(":/images/new/icon_settings.svg")); - trayMenuSubConfigure_tray = trayMenu->addMenu(tr("Configure")); - trayMenuSubConfigure_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_settings.svg", true)); - if (TRUE == libada::i()->isPasswordSafeAvailable()) trayMenuSubConfigure->addAction(configureActionStick20); else diff -Nru nitrokey-app-1.3.2/src/GUI/Tray.h nitrokey-app-1.4.1/src/GUI/Tray.h --- nitrokey-app-1.3.2/src/GUI/Tray.h 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/GUI/Tray.h 2019-09-28 16:20:07.000000000 +0000 @@ -79,6 +79,7 @@ void populateOTPPasswordMenu(); void passOTPProgressFurther(int i); void showOTPProgressInTray(int i); + void delayedShowIndicator(); private: Q_DISABLE_COPY(Tray); @@ -107,6 +108,7 @@ // QMenu *trayMenuHOTPSubMenu; QMenu *trayMenuSubSpecialConfigure; QMenuBar* file_menu; + QTimer *delayedShowTimer; public: void setFile_menu(QMenuBar *file_menu); @@ -167,7 +169,6 @@ QAction *Stick20ActionEnableHiddenVolume_tray; QAction *Stick20ActionDisableHiddenVolume_tray; std::shared_ptr trayMenuPasswdSubMenu_tray; - QMenu *trayMenuSubConfigure_tray; QAction *UnlockPasswordSafeAction_tray; }; diff -Nru nitrokey-app-1.3.2/src/hotpslot.h nitrokey-app-1.4.1/src/hotpslot.h --- nitrokey-app-1.3.2/src/hotpslot.h 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/hotpslot.h 2019-09-28 16:20:07.000000000 +0000 @@ -28,8 +28,10 @@ #include #include +#define TO_BASE32_LEN(x) ((x)/10*16) + static const unsigned int SECRET_LENGTH = 40; -static const unsigned int SECRET_LENGTH_BASE32 = SECRET_LENGTH / 10 * 16; +static const unsigned int SECRET_LENGTH_BASE32 = TO_BASE32_LEN(SECRET_LENGTH); static const unsigned int SECRET_LENGTH_HEX = SECRET_LENGTH * 2; std::vector decodeBase32Secret(const std::string secret, const bool debug_mode = false); diff -Nru nitrokey-app-1.3.2/src/libada.cpp nitrokey-app-1.4.1/src/libada.cpp --- nitrokey-app-1.3.2/src/libada.cpp 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/libada.cpp 2019-09-28 16:20:07.000000000 +0000 @@ -321,7 +321,7 @@ bool libada::is_time_synchronized() { auto time = QDateTime::currentDateTimeUtc().toTime_t(); try{ - nm::instance()->get_time(time); + nm::instance()->set_time_soft(time); return true; } catch (const LongOperationInProgressException &e){ diff -Nru nitrokey-app-1.3.2/src/main.cpp nitrokey-app-1.4.1/src/main.cpp --- nitrokey-app-1.3.2/src/main.cpp 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/main.cpp 2019-09-28 16:20:07.000000000 +0000 @@ -150,6 +150,10 @@ w.set_debug_level(parser.value("debug-level").toInt()); } + if(parser.isSet("no-window") || !settings.value("main/show_on_start", true).toBool() ) { + w.hideOnStartup(); + } + // csApplet()->setParent(&w); int retcode = -1; @@ -296,6 +300,8 @@ "Load translation file with given name " "and store this choice in settings file."), "en"}, + {"no-window", + QCoreApplication::translate("main", "Display no window.")}, }); parser.process(a); diff -Nru nitrokey-app-1.3.2/src/ui/mainwindow.cpp nitrokey-app-1.4.1/src/ui/mainwindow.cpp --- nitrokey-app-1.3.2/src/ui/mainwindow.cpp 2018-12-12 12:23:09.000000000 +0000 +++ nitrokey-app-1.4.1/src/ui/mainwindow.cpp 2019-09-28 16:20:07.000000000 +0000 @@ -55,6 +55,8 @@ #include #include +#include + using nm = nitrokey::NitrokeyManager; const auto Communication_error_message = QT_TRANSLATE_NOOP("MainWindow", "Communication error. Please reinsert the device."); @@ -109,6 +111,7 @@ ui->cb_show_main_window_on_connection->setChecked(settings.value("main/show_main_on_connection", true).toBool()); ui->cb_hide_main_window_on_connection->setChecked(settings.value("main/close_main_on_connection", false).toBool()); ui->cb_hide_main_window_on_close->setChecked(settings.value("main/hide_on_close", true).toBool()); + ui->cb_show_window_on_start->setChecked(settings.value("main/show_on_start", true).toBool()); ui->cb_check_symlink->setChecked(settings.value("storage/check_symlink", false).toBool()); #ifndef Q_OS_LINUX @@ -417,6 +420,22 @@ } } +void MainWindow::showEvent(QShowEvent *event) { + if (suppress_next_show){ + suppress_next_show = false; +#ifdef Q_OS_MAC + QTimer::singleShot(0, this, SLOT(showMinimized())); +#else + QTimer::singleShot(0, this, SLOT(hide())); +#endif + } +} + +void MainWindow::hideOnStartup() +{ + suppress_next_show = true; +} + void MainWindow::generateComboBoxEntrys() { //FIXME run in separate thread int i; @@ -516,15 +535,15 @@ memcpy(slot->slotName, slotNameFromGUI.constData(), toCopy); memset(slot->tokenID, 0, sizeof(slot->tokenID)); - QByteArray ompFromGUI = (this->ui->ompEdit->text().toLatin1()); + QByteArray ompFromGUI = ""; toCopy = std::min(2ul, (const unsigned long &) ompFromGUI.length()); memcpy(slot->tokenID, ompFromGUI.constData(), toCopy); - QByteArray ttFromGUI = (this->ui->ttEdit->text().toLatin1()); + QByteArray ttFromGUI = ""; toCopy = std::min(2ul, (const unsigned long &) ttFromGUI.length()); memcpy(slot->tokenID + 2, ttFromGUI.constData(), toCopy); - QByteArray muiFromGUI = (this->ui->muiEdit->text().toLatin1()); + QByteArray muiFromGUI = ""; toCopy = std::min(8ul, (const unsigned long &) muiFromGUI.length()); memcpy(slot->tokenID + 4, muiFromGUI.constData(), toCopy); @@ -533,10 +552,7 @@ slot->config = 0; if (ui->digits8radioButton->isChecked()) slot->config += (1 << 0); - if (ui->enterCheckBox->isChecked()) - slot->config += (1 << 1); - if (ui->tokenIDCheckBox->isChecked()) - slot->config += (1 << 2); + } void MainWindow::generateTOTPConfig(OTPSlot *slot) { @@ -565,17 +581,10 @@ } void updateSlotConfig(const nitrokey::ReadSlot::ResponsePayload &p, Ui::MainWindow* ui) { - ui->ompEdit->setText(QString(reinterpret_cast(p.slot_token_fields.omp)).trimmed()); - ui->ttEdit->setText(QString(reinterpret_cast(p.slot_token_fields.tt)).trimmed()); - ui->muiEdit->setText(QString(reinterpret_cast(p.slot_token_fields.mui)).trimmed()); - if (p.use_8_digits) ui->digits8radioButton->setChecked(true); else ui->digits6radioButton->setChecked(true); - - ui->enterCheckBox->setChecked(p.use_enter); - ui->tokenIDCheckBox->setChecked(p.use_tokenID); } void MainWindow::displayCurrentTotpSlotConfig(uint8_t slotNo) { @@ -584,7 +593,6 @@ ui->counterEdit->hide(); ui->setToZeroButton->hide(); ui->setToRandomButton->hide(); - ui->enterCheckBox->hide(); ui->labelNotify->hide(); ui->intervalLabel->show(); ui->intervalSpinBox->show(); @@ -596,13 +604,9 @@ ui->base32RadioButton->setChecked(true); ui->counterEdit->setText("0"); - ui->tokenIDCheckBox->setChecked(false); ui->digits6radioButton->setChecked(true); - ui->ompEdit->setText("NK"); - ui->ttEdit->setText("01"); std::string cardSerial = libada::i()->get_serial_number(); - ui->muiEdit->setText(QString("%1").arg(QString::fromStdString(cardSerial), 8, '0')); ui->intervalSpinBox->setValue(30); //TODO move reading to separate thread @@ -617,6 +621,8 @@ if (interval < 1) interval = 30; ui->intervalSpinBox->setValue(interval); } + ui->secret_key_generated_len->setValue(get_supported_secret_length_hex()/2); + ui->secret_key_generated_len->setMaximum(get_supported_secret_length_hex()/2); } catch (DeviceCommunicationException &e){ emit DeviceDisconnected(); @@ -632,7 +638,6 @@ ui->counterEdit->show(); ui->setToZeroButton->show(); ui->setToRandomButton->show(); - ui->enterCheckBox->show(); ui->labelNotify->hide(); ui->intervalLabel->hide(); ui->intervalSpinBox->hide(); @@ -644,9 +649,6 @@ ui->base32RadioButton->setChecked(true); std::string cardSerial = libada::i()->get_serial_number(); - ui->muiEdit->setText(QString("%1").arg(QString::fromStdString(cardSerial), 8, '0')); - ui->ompEdit->setText("NK"); - ui->ttEdit->setText("01"); ui->counterEdit->setText(QString::number(0)); try { @@ -656,6 +658,8 @@ updateSlotConfig(p, ui); ui->counterEdit->setText(QString::number(p.slot_counter)); } + ui->secret_key_generated_len->setValue(get_supported_secret_length_hex()/2); + ui->secret_key_generated_len->setMaximum(get_supported_secret_length_hex()/2); } catch (DeviceCommunicationException &e){ emit DeviceDisconnected(); @@ -690,9 +694,6 @@ void MainWindow::displayCurrentGeneralConfig() { auto status = libada::i()->get_status(); - ui->numLockComboBox->setCurrentIndex(status.numlock<2?status.numlock+1:0); - ui->capsLockComboBox->setCurrentIndex(status.capslock<2?status.capslock+1:0); - ui->scrollLockComboBox->setCurrentIndex(status.scrolllock<2?status.scrolllock+1:0); ui->enableUserPasswordCheckBox->setChecked(status.enable_user_password != 0); ui->deleteUserPasswordCheckBox->setChecked(status.delete_user_password != 0); @@ -961,14 +962,6 @@ ui->counterEdit->setText(QString(QByteArray::number(counter, 10))); } -void MainWindow::on_tokenIDCheckBox_toggled(bool checked) { - ui->ompEdit->setEnabled(checked); - ui->ttEdit->setEnabled(checked); - ui->muiEdit->setEnabled(checked); - ui->ompEdit->setText(ui->ompEdit->text().trimmed()); - ui->ttEdit->setText(ui->ttEdit->text().trimmed()); - ui->muiEdit->setText(ui->muiEdit->text().trimmed()); -} void MainWindow::on_enableUserPasswordCheckBox_toggled(bool checked) { ui->deleteUserPasswordCheckBox->setEnabled(checked); @@ -990,9 +983,7 @@ try{ auto password_byte_array = auth_admin.getTempPassword(); nm::instance()->write_config( - ui->numLockComboBox->currentIndex() - 1, - ui->capsLockComboBox->currentIndex() - 1, - ui->scrollLockComboBox->currentIndex() - 1, + 0,0,0, ui->enableUserPasswordCheckBox->isChecked(), ui->deleteUserPasswordCheckBox->isChecked() && ui->enableUserPasswordCheckBox->isChecked(), @@ -1005,7 +996,6 @@ } generateAllConfigs(); - displayCurrentGeneralConfig(); } void MainWindow::getHOTPDialog(int slot) { @@ -1087,30 +1077,36 @@ // QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // QApplication::restoreOverrideCursor(); generateAllConfigs(); - displayCurrentSlotConfig(); } -void MainWindow::on_randomSecretButton_clicked() { - int i = 0; +quint32 get_random(){ +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + return QRandomGenerator::global()->generate(); +#else + static std::random_device dev; + static std::mt19937 rng(dev()); + static std::uniform_int_distribution dist(0, UINT32_MAX); + return dist(rng); +#endif +} +void MainWindow::on_randomSecretButton_clicked() { - int local_secret_length = get_supported_secret_length_base32(); + int local_secret_length = std::min( (int) get_supported_secret_length_hex()/2, ui->secret_key_generated_len->value()); + local_secret_length = std::max(local_secret_length, 1); uint8_t secret[local_secret_length]; - char temp; - + int i = 0; while (i < local_secret_length) { - temp = qrand() & 0xFF; - if ((temp >= 'A' && temp <= 'Z') || (temp >= '2' && temp <= '7')) { - secret[i] = temp; + secret[i] = get_random() & 0xFF; i++; - } } - QByteArray secretArray((char *)secret, local_secret_length); + QByteArray secretArray = QByteArray((char*)secret, sizeof(secret)); - ui->base32RadioButton->setChecked(true); - ui->secretEdit->setText(secretArray); +// ui->base32RadioButton->setChecked(false); + ui->hexRadioButton->setChecked(true); + ui->secretEdit->setText(secretArray.toHex()); ui->checkBox->setEnabled(true); ui->checkBox->setChecked(true); clipboard.copyOTP(secretArray); @@ -1498,12 +1494,12 @@ void MainWindow::on_PWS_ButtonCreatePW_clicked() { //FIXME generate in separate class - int n; + quint32 n; const QString PasswordCharSpace = PWS_RANDOM_PASSWORD_CHAR_SPACE; QString generated_password(20, 0); for (int i = 0; i < PWS_CreatePWSize; i++) { - n = qrand(); + n = get_random(); n = n % PasswordCharSpace.length(); generated_password[i] = PasswordCharSpace[n]; } @@ -1834,6 +1830,7 @@ settings.setValue("main/show_main_on_connection", ui->cb_show_main_window_on_connection->isChecked()); settings.setValue("main/close_main_on_connection", ui->cb_hide_main_window_on_connection->isChecked()); settings.setValue("main/hide_on_close", ui->cb_hide_main_window_on_close->isChecked()); + settings.setValue("main/show_on_start", ui->cb_show_window_on_start->isChecked()); settings.setValue("storage/check_symlink", ui->cb_check_symlink->isChecked()); diff -Nru nitrokey-app-1.3.2/src/ui/mainwindow.h nitrokey-app-1.4.1/src/ui/mainwindow.h --- nitrokey-app-1.3.2/src/ui/mainwindow.h 2018-06-26 15:47:20.000000000 +0000 +++ nitrokey-app-1.4.1/src/ui/mainwindow.h 2019-09-28 16:20:07.000000000 +0000 @@ -58,6 +58,7 @@ protected: void closeEvent(QCloseEvent *event) override; + void showEvent(QShowEvent *event) override; private: Q_DISABLE_COPY(MainWindow); @@ -158,7 +159,6 @@ void on_base32RadioButton_toggled(bool checked); void on_setToZeroButton_clicked(); void on_setToRandomButton_clicked(); - void on_tokenIDCheckBox_toggled(bool checked); void on_enableUserPasswordCheckBox_toggled(bool checked); void on_writeGeneralConfigButton_clicked(); @@ -221,8 +221,11 @@ void set_debug_mode(); void set_debug_level(int debug_level); + void hideOnStartup(); + private: bool debug_mode = false; + bool suppress_next_show = false; void showNotificationLabel(); diff -Nru nitrokey-app-1.3.2/src/ui/mainwindow.ui nitrokey-app-1.4.1/src/ui/mainwindow.ui --- nitrokey-app-1.3.2/src/ui/mainwindow.ui 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/ui/mainwindow.ui 2020-08-06 10:07:14.000000000 +0000 @@ -7,7 +7,7 @@ 0 0 932 - 717 + 750 @@ -43,7 +43,7 @@ QTabWidget::Rounded - 0 + 4 Qt::ElideNone @@ -166,6 +166,10 @@ Lock Device + + + :/images/new/icon_unsafe.svg:/images/new/icon_unsafe.svg + @@ -312,6 +316,12 @@ + + + 300 + 0 + + Select OTP slot number @@ -329,13 +339,6 @@ - - - Erase Slot - - - - Name: @@ -355,6 +358,13 @@ + + + + Erase Slot + + + @@ -556,13 +566,30 @@ + + + + - - - Copy secret to clipboard - + - Copy to clipboard + Generated secret target length (bytes): + + + + + + + TOTP interval value + + + 10 + + + 40 + + + 40 @@ -579,6 +606,16 @@ + + + + Copy secret to clipboard + + + Copy to clipboard + + + @@ -630,13 +667,6 @@ - - - Send 'enter' as the last keystroke - - - - QFormLayout::AllNonFixedFieldsGrow @@ -798,121 +828,6 @@ - - - false - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - - - 75 - true - - - - Token ID - - - - - - - - - true - - - Send token ID - - - - - - - - - OMP: - - - - - - - false - - - OMP part of Token ID - - - - - - 2 - - - - - - - TT: - - - - - - - false - - - TT part of Token ID - - - - - - 2 - - - - - - - MUI: - - - - - - - false - - - MUI part of Token ID - - - - - - 8 - - - - - - - - - - - Qt::Vertical @@ -1030,155 +945,6 @@ - - - false - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - - - 75 - true - - - - Settings for inserting HOTP code through special key shortcut (USB-Keyboard only) - - - - - - - - - - - Double press NumLock: - - - - - - - Double press CapsLock: - - - - - - - Double press ScrollLock: - - - - - - - - - - - Double press NumLock: - - - Settings for inserting HOTP code through special key shortcut (USB-Keyboard only) - - - - Do nothing - - - - - Send HOTP1 - - - - - Send HOTP2 - - - - - - - - Double press CapsLock: - - - Settings for inserting HOTP code through special key shortcut (USB-Keyboard only) - - - - Do nothing - - - - - Send HOTP1 - - - - - Send HOTP2 - - - - - - - - Double press ScrollLock: - - - Settings for inserting HOTP code through special key shortcut (USB-Keyboard only) - - - - Do nothing - - - - - Send HOTP1 - - - - - Send HOTP2 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical @@ -1521,9 +1287,9 @@ General - + - + @@ -1532,29 +1298,20 @@ - + - Show warning when no partitions could be detected on Encrypted Volume (Linux only) - - - true - - - - - - - Show message about device's connection / disconnection - - - true + Show main window on start + + + + - + - Show main window when device connects + Do not quit when the main window is closed true @@ -1571,33 +1328,53 @@ + + + + + + Show main window when device connects + + + true + + + + + + + Show warning when no partitions could be detected on Encrypted Volume (Linux only) + + + true + + + + + + + Show message about device's connection / disconnection + + + true + + + + + - + - Do not quit when the main window is closed - - - true + <html><head/><body><p>Translation file (needs restart)</p></body></html> - - - - - <html><head/><body><p>Translation file (needs restart)</p></body></html> - - - - - - - Translation file (needs restart) - - - - + + + Translation file (needs restart) + + @@ -1615,26 +1392,6 @@ Debug log settings - - - - Path for debug log file: - - - edit_debug_file_path - - - - - - - Verbosity level: - - - spin_debug_verbosity - - - @@ -1655,10 +1412,23 @@ - - + + - Select path + Path for debug log file: + + + edit_debug_file_path + + + + + + + Verbosity level: + + + spin_debug_verbosity @@ -1679,6 +1449,13 @@ + + + + Select path + + + @@ -1767,7 +1544,7 @@ 20 - 78 + 0 @@ -1831,14 +1608,13 @@ 0 0 932 - 20 + 27 - tabWidget btn_dial_PWS btn_dial_EV btn_dial_HV @@ -1848,32 +1624,22 @@ radioButton_2 radioButton slotComboBox - eraseButton nameEdit + eraseButton base32RadioButton hexRadioButton secretEdit checkBox - btn_copyToClipboard - randomSecretButton - enterCheckBox intervalSpinBox digits6radioButton digits8radioButton counterEdit setToZeroButton setToRandomButton - tokenIDCheckBox - ompEdit - ttEdit - muiEdit cancelButton writeButton enableUserPasswordCheckBox deleteUserPasswordCheckBox - numLockComboBox - capsLockComboBox - scrollLockComboBox PWS_ComboBoxSelectSlot PWS_ButtonClearSlot PWS_EditSlotName @@ -1887,6 +1653,7 @@ PWS_ButtonClose PWS_ButtonSaveSlot cb_first_run_message + cb_show_window_on_start cb_check_symlink cb_device_connection_message cb_show_main_window_on_connection @@ -1904,6 +1671,10 @@ btn_writeSettings writeGeneralConfigButton generalCancelButton + tabWidget + secret_key_generated_len + randomSecretButton + btn_copyToClipboard diff -Nru nitrokey-app-1.3.2/src/version.h nitrokey-app-1.4.1/src/version.h --- nitrokey-app-1.3.2/src/version.h 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/src/version.h 2019-09-28 16:20:07.000000000 +0000 @@ -29,13 +29,13 @@ #endif #ifndef GUI_VERSION -#define GUI_VERSION "1.3-unspecified" +#define GUI_VERSION "1.4-unspecified" #endif #ifndef GIT_VERSION #define GIT_VERSION "" #endif -#define COPYRIGHT_YEARS "2012-2018" +#define COPYRIGHT_YEARS "2012-2019" #endif //NITROKEYAPP_VERSION_H diff -Nru nitrokey-app-1.3.2/.travis.yml nitrokey-app-1.4.1/.travis.yml --- nitrokey-app-1.3.2/.travis.yml 2018-05-13 08:58:17.000000000 +0000 +++ nitrokey-app-1.4.1/.travis.yml 2019-09-28 16:20:07.000000000 +0000 @@ -16,8 +16,17 @@ - sudo apt-get -qq install ${AF} cmake libhidapi-dev ${COMP} - sudo apt-get -qq remove gcc-4.8 g++-4.8 --purge +#cache: +# - apt + +before_cache: + - brew cleanup + cache: - - apt + directories: + # https://stackoverflow.com/questions/39930171/cache-brew-builds-with-travis-ci + - $HOME/Library/Caches/Homebrew + - /usr/local/Homebrew/ script: | @@ -46,10 +55,9 @@ matrix: - exclude: include: - os: osx - osx_image: xcode7.3 #default + osx_image: xcode8.3 #default before_install: &before - brew update - brew install qt5 @@ -58,11 +66,7 @@ - export env: builder=cmake PATH="/usr/local/opt/qt5/bin:$PATH" CMAKE_PREFIX_PATH=/usr/local/lib/cmake MACOS_DEPLOYMENT_TARGET=10.9 - os: osx - osx_image: xcode7.3 #default - before_install: *before - env: builder=qmake PATH="/usr/local/opt/qt5/bin:$PATH" CMAKE_PREFIX_PATH=/usr/local/lib/cmake MACOS_DEPLOYMENT_TARGET=10.9 - - os: osx - osx_image: xcode8.3 + osx_image: xcode8.3 #default before_install: *before env: builder=qmake PATH="/usr/local/opt/qt5/bin:$PATH" CMAKE_PREFIX_PATH=/usr/local/lib/cmake MACOS_DEPLOYMENT_TARGET=10.9 - os: osx