1 /*
2 * Copyright (c) 2015-2018 Nitrokey UG
3 *
4 * This file is part of libnitrokey.
5 *
6 * libnitrokey is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * any later version.
10 *
11 * libnitrokey is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with libnitrokey. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * SPDX-License-Identifier: LGPL-3.0
20 */
21
22 #include "NK_C_API.h"
23 #include <iostream>
24 #include <tuple>
25 #include "libnitrokey/NitrokeyManager.h"
26 #include <cstring>
27 #include "libnitrokey/LibraryException.h"
28 #include "libnitrokey/cxx_semantics.h"
29 #include "libnitrokey/stick20_commands.h"
30 #include "libnitrokey/device_proto.h"
31 #include "libnitrokey/version.h"
32
33 #ifdef _MSC_VER
34 #ifdef _WIN32
35 #pragma message "Using own strndup"
strndup(const char * str,size_t maxlen)36 char * strndup(const char* str, size_t maxlen) {
37 size_t len = strnlen(str, maxlen);
38 char* dup = (char *)malloc(len + 1);
39 memcpy(dup, str, len);
40 dup[len] = 0;
41 return dup;
42 }
43 #endif
44 #endif
45
46 using namespace nitrokey;
47
48 const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT;
49 static uint8_t NK_last_command_status = 0;
50 static const int max_string_field_length = 100;
51
52 template <typename T>
duplicate_vector_and_clear(std::vector<T> & v)53 T* duplicate_vector_and_clear(std::vector<T> &v){
54 auto d = new T[v.size()];
55 std::copy(v.begin(), v.end(), d);
56 std::fill(v.begin(), v.end(), 0);
57 return d;
58 }
59
60 template <typename R, typename T>
get_with_status(T func,R fallback)61 std::tuple<int, R> get_with_status(T func, R fallback) {
62 NK_last_command_status = 0;
63 try {
64 return std::make_tuple(0, func());
65 }
66 catch (CommandFailedException & commandFailedException){
67 NK_last_command_status = commandFailedException.last_command_status;
68 }
69 catch (LibraryException & libraryException){
70 NK_last_command_status = libraryException.exception_id();
71 }
72 catch (const DeviceCommunicationException &deviceException){
73 NK_last_command_status = 256-deviceException.getType();
74 }
75 return std::make_tuple(NK_last_command_status, fallback);
76 }
77
78 template <typename T>
get_with_array_result(T func)79 uint8_t * get_with_array_result(T func){
80 return std::get<1>(get_with_status<uint8_t*>(func, nullptr));
81 }
82
83 template <typename T>
get_with_string_result(T func)84 char* get_with_string_result(T func){
85 auto result = std::get<1>(get_with_status<char*>(func, nullptr));
86 if (result == nullptr) {
87 return strndup("", MAXIMUM_STR_REPLY_LENGTH);
88 }
89 return result;
90 }
91
92 template <typename T>
get_with_result(T func)93 auto get_with_result(T func){
94 return std::get<1>(get_with_status(func, static_cast<decltype(func())>(0)));
95 }
96
97 template <typename T>
get_without_result(T func)98 uint8_t get_without_result(T func){
99 NK_last_command_status = 0;
100 try {
101 func();
102 return 0;
103 }
104 catch (CommandFailedException & commandFailedException){
105 NK_last_command_status = commandFailedException.last_command_status;
106 }
107 catch (LibraryException & libraryException){
108 NK_last_command_status = libraryException.exception_id();
109 }
110 catch (const InvalidCRCReceived &invalidCRCException){
111 ;
112 }
113 catch (const DeviceCommunicationException &deviceException){
114 NK_last_command_status = 256-deviceException.getType();
115 }
116 return NK_last_command_status;
117 }
118
119
120 #ifdef __cplusplus
121 extern "C" {
122 #endif
123
NK_get_last_command_status()124 NK_C_API uint8_t NK_get_last_command_status() {
125 auto _copy = NK_last_command_status;
126 NK_last_command_status = 0;
127 return _copy;
128 }
129
NK_login(const char * device_model)130 NK_C_API int NK_login(const char *device_model) {
131 auto m = NitrokeyManager::instance();
132 try {
133 NK_last_command_status = 0;
134 return m->connect(device_model);
135 }
136 catch (CommandFailedException & commandFailedException) {
137 NK_last_command_status = commandFailedException.last_command_status;
138 return commandFailedException.last_command_status;
139 }
140 catch (const DeviceCommunicationException &deviceException){
141 NK_last_command_status = 256-deviceException.getType();
142 cerr << deviceException.what() << endl;
143 return 0;
144 }
145 catch (std::runtime_error &e) {
146 cerr << e.what() << endl;
147 return 0;
148 }
149 return 0;
150 }
151
NK_login_enum(NK_device_model device_model)152 NK_C_API int NK_login_enum(NK_device_model device_model) {
153 const char *model_string;
154 switch (device_model) {
155 case NK_PRO:
156 model_string = "P";
157 break;
158 case NK_STORAGE:
159 model_string = "S";
160 break;
161 case NK_LIBREM:
162 model_string = "L";
163 break;
164 case NK_DISCONNECTED:
165 default:
166 /* no such enum value -- return error code */
167 return 0;
168 }
169 return NK_login(model_string);
170 }
171
NK_logout()172 NK_C_API int NK_logout() {
173 auto m = NitrokeyManager::instance();
174 return get_without_result([&]() {
175 m->disconnect();
176 });
177 }
178
NK_first_authenticate(const char * admin_password,const char * admin_temporary_password)179 NK_C_API int NK_first_authenticate(const char* admin_password, const char* admin_temporary_password) {
180 auto m = NitrokeyManager::instance();
181 return get_without_result([&]() {
182 return m->first_authenticate(admin_password, admin_temporary_password);
183 });
184 }
185
186
NK_user_authenticate(const char * user_password,const char * user_temporary_password)187 NK_C_API int NK_user_authenticate(const char* user_password, const char* user_temporary_password) {
188 auto m = NitrokeyManager::instance();
189 return get_without_result([&]() {
190 m->user_authenticate(user_password, user_temporary_password);
191 });
192 }
193
NK_factory_reset(const char * admin_password)194 NK_C_API int NK_factory_reset(const char* admin_password) {
195 auto m = NitrokeyManager::instance();
196 return get_without_result([&]() {
197 m->factory_reset(admin_password);
198 });
199 }
NK_build_aes_key(const char * admin_password)200 NK_C_API int NK_build_aes_key(const char* admin_password) {
201 auto m = NitrokeyManager::instance();
202 return get_without_result([&]() {
203 m->build_aes_key(admin_password);
204 });
205 }
206
NK_unlock_user_password(const char * admin_password,const char * new_user_password)207 NK_C_API int NK_unlock_user_password(const char *admin_password, const char *new_user_password) {
208 auto m = NitrokeyManager::instance();
209 return get_without_result([&]() {
210 m->unlock_user_password(admin_password, new_user_password);
211 });
212 }
213
NK_write_config(uint8_t numlock,uint8_t capslock,uint8_t scrolllock,bool enable_user_password,bool delete_user_password,const char * admin_temporary_password)214 NK_C_API int NK_write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password,
215 bool delete_user_password,
216 const char *admin_temporary_password) {
217 auto m = NitrokeyManager::instance();
218 return get_without_result([&]() {
219 return m->write_config(numlock, capslock, scrolllock, enable_user_password, delete_user_password, admin_temporary_password);
220 });
221 }
222
NK_write_config_struct(struct NK_config config,const char * admin_temporary_password)223 NK_C_API int NK_write_config_struct(struct NK_config config,
224 const char *admin_temporary_password) {
225 return NK_write_config(config.numlock, config.capslock, config.scrolllock, config.enable_user_password,
226 config.disable_user_password, admin_temporary_password);
227 }
228
229
NK_read_config()230 NK_C_API uint8_t* NK_read_config() {
231 auto m = NitrokeyManager::instance();
232 return get_with_array_result([&]() {
233 auto v = m->read_config();
234 return duplicate_vector_and_clear(v);
235 });
236 }
237
NK_free_config(uint8_t * config)238 NK_C_API void NK_free_config(uint8_t* config) {
239 delete[] config;
240 }
241
NK_read_config_struct(struct NK_config * out)242 NK_C_API int NK_read_config_struct(struct NK_config* out) {
243 if (out == nullptr) {
244 return -1;
245 }
246 auto m = NitrokeyManager::instance();
247 return get_without_result([&]() {
248 auto v = m->read_config();
249 out->numlock = v[0];
250 out->capslock = v[1];
251 out->scrolllock = v[2];
252 out->enable_user_password = v[3];
253 out->disable_user_password = v[4];
254 });
255 }
256
257
NK_get_device_model()258 NK_C_API enum NK_device_model NK_get_device_model() {
259 auto m = NitrokeyManager::instance();
260 try {
261 auto model = m->get_connected_device_model();
262 switch (model) {
263 case DeviceModel::PRO:
264 return NK_PRO;
265 case DeviceModel::STORAGE:
266 return NK_STORAGE;
267 case DeviceModel::LIBREM:
268 return NK_LIBREM;
269 default:
270 /* unknown or not connected device */
271 return NK_device_model::NK_DISCONNECTED;
272 }
273 } catch (const DeviceNotConnected& e) {
274 return NK_device_model::NK_DISCONNECTED;
275 }
276 }
277
278
clear_string(std::string & s)279 void clear_string(std::string &s) {
280 std::fill(s.begin(), s.end(), ' ');
281 }
282
283
NK_status()284 NK_C_API char * NK_status() {
285 return NK_get_status_as_string();
286 }
287
NK_get_status_as_string()288 NK_C_API char * NK_get_status_as_string() {
289 auto m = NitrokeyManager::instance();
290 return get_with_string_result([&]() {
291 string && s = m->get_status_as_string();
292 char * rs = strndup(s.c_str(), MAXIMUM_STR_REPLY_LENGTH);
293 clear_string(s);
294 return rs;
295 });
296 }
297
NK_get_status(struct NK_status * out)298 NK_C_API int NK_get_status(struct NK_status* out) {
299 if (out == nullptr) {
300 return -1;
301 }
302 auto m = NitrokeyManager::instance();
303 auto result = get_with_status([&]() {
304 return m->get_status();
305 }, proto::stick10::GetStatus::ResponsePayload());
306 auto error_code = std::get<0>(result);
307 if (error_code != 0) {
308 return error_code;
309 }
310
311 auto status = std::get<1>(result);
312 out->firmware_version_major = status.firmware_version_st.major;
313 out->firmware_version_minor = status.firmware_version_st.minor;
314 out->serial_number_smart_card = status.card_serial_u32;
315 out->config_numlock = status.numlock;
316 out->config_capslock = status.capslock;
317 out->config_scrolllock = status.scrolllock;
318 out->otp_user_password = status.enable_user_password != 0;
319 return 0;
320 }
321
NK_device_serial_number()322 NK_C_API char * NK_device_serial_number() {
323 auto m = NitrokeyManager::instance();
324 return get_with_string_result([&]() {
325 string && s = m->get_serial_number();
326 char * rs = strndup(s.c_str(), max_string_field_length);
327 clear_string(s);
328 return rs;
329 });
330 }
331
NK_device_serial_number_as_u32()332 NK_C_API uint32_t NK_device_serial_number_as_u32() {
333 auto m = NitrokeyManager::instance();
334 return get_with_result([&]() {
335 return m->get_serial_number_as_u32();
336 });
337 }
338
NK_get_hotp_code(uint8_t slot_number)339 NK_C_API char * NK_get_hotp_code(uint8_t slot_number) {
340 return NK_get_hotp_code_PIN(slot_number, "");
341 }
342
NK_get_hotp_code_PIN(uint8_t slot_number,const char * user_temporary_password)343 NK_C_API char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password) {
344 auto m = NitrokeyManager::instance();
345 return get_with_string_result([&]() {
346 string && s = m->get_HOTP_code(slot_number, user_temporary_password);
347 char * rs = strndup(s.c_str(), max_string_field_length);
348 clear_string(s);
349 return rs;
350 });
351 }
352
NK_get_totp_code(uint8_t slot_number,uint64_t challenge,uint64_t last_totp_time,uint8_t last_interval)353 NK_C_API char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time,
354 uint8_t last_interval) {
355 return NK_get_totp_code_PIN(slot_number, challenge, last_totp_time, last_interval, "");
356 }
357
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)358 NK_C_API char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time,
359 uint8_t last_interval, const char *user_temporary_password) {
360 auto m = NitrokeyManager::instance();
361 return get_with_string_result([&]() {
362 string && s = m->get_TOTP_code(slot_number, challenge, last_totp_time, last_interval, user_temporary_password);
363 char * rs = strndup(s.c_str(), max_string_field_length);
364 clear_string(s);
365 return rs;
366 });
367 }
368
NK_erase_hotp_slot(uint8_t slot_number,const char * temporary_password)369 NK_C_API int NK_erase_hotp_slot(uint8_t slot_number, const char *temporary_password) {
370 auto m = NitrokeyManager::instance();
371 return get_without_result([&] {
372 m->erase_hotp_slot(slot_number, temporary_password);
373 });
374 }
375
NK_erase_totp_slot(uint8_t slot_number,const char * temporary_password)376 NK_C_API int NK_erase_totp_slot(uint8_t slot_number, const char *temporary_password) {
377 auto m = NitrokeyManager::instance();
378 return get_without_result([&] {
379 m->erase_totp_slot(slot_number, temporary_password);
380 });
381 }
382
NK_write_hotp_slot(uint8_t slot_number,const char * slot_name,const char * secret,uint64_t hotp_counter,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password)383 NK_C_API int NK_write_hotp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter,
384 bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
385 const char *temporary_password) {
386 auto m = NitrokeyManager::instance();
387 return get_without_result([&] {
388 m->write_HOTP_slot(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, token_ID,
389 temporary_password);
390 });
391 }
392
NK_write_totp_slot(uint8_t slot_number,const char * slot_name,const char * secret,uint16_t time_window,bool use_8_digits,bool use_enter,bool use_tokenID,const char * token_ID,const char * temporary_password)393 NK_C_API int NK_write_totp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window,
394 bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID,
395 const char *temporary_password) {
396 auto m = NitrokeyManager::instance();
397 return get_without_result([&] {
398 m->write_TOTP_slot(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, token_ID,
399 temporary_password);
400 });
401 }
402
NK_get_totp_slot_name(uint8_t slot_number)403 NK_C_API char* NK_get_totp_slot_name(uint8_t slot_number) {
404 auto m = NitrokeyManager::instance();
405 return get_with_string_result([&]() {
406 const auto slot_name = m->get_totp_slot_name(slot_number);
407 return slot_name;
408 });
409 }
NK_get_hotp_slot_name(uint8_t slot_number)410 NK_C_API char* NK_get_hotp_slot_name(uint8_t slot_number) {
411 auto m = NitrokeyManager::instance();
412 return get_with_string_result([&]() {
413 const auto slot_name = m->get_hotp_slot_name(slot_number);
414 return slot_name;
415 });
416 }
417
NK_set_debug(bool state)418 NK_C_API void NK_set_debug(bool state) {
419 auto m = NitrokeyManager::instance();
420 m->set_debug(state);
421 }
422
423
NK_set_debug_level(const int level)424 NK_C_API void NK_set_debug_level(const int level) {
425 auto m = NitrokeyManager::instance();
426 m->set_loglevel(level);
427 }
428
NK_get_major_library_version()429 NK_C_API unsigned int NK_get_major_library_version() {
430 return get_major_library_version();
431 }
432
NK_get_minor_library_version()433 NK_C_API unsigned int NK_get_minor_library_version() {
434 return get_minor_library_version();
435 }
436
NK_get_library_version()437 NK_C_API const char* NK_get_library_version() {
438 return get_library_version();
439 }
440
NK_totp_set_time(uint64_t time)441 NK_C_API int NK_totp_set_time(uint64_t time) {
442 auto m = NitrokeyManager::instance();
443 return get_without_result([&]() {
444 m->set_time(time);
445 });
446 }
447
NK_totp_set_time_soft(uint64_t time)448 NK_C_API int NK_totp_set_time_soft(uint64_t time) {
449 auto m = NitrokeyManager::instance();
450 return get_without_result([&]() {
451 m->set_time_soft(time);
452 });
453 }
454
NK_totp_get_time()455 NK_C_API int NK_totp_get_time() {
456 return 0;
457 }
458
NK_change_admin_PIN(const char * current_PIN,const char * new_PIN)459 NK_C_API int NK_change_admin_PIN(const char *current_PIN, const char *new_PIN) {
460 auto m = NitrokeyManager::instance();
461 return get_without_result([&]() {
462 m->change_admin_PIN(current_PIN, new_PIN);
463 });
464 }
465
NK_change_user_PIN(const char * current_PIN,const char * new_PIN)466 NK_C_API int NK_change_user_PIN(const char *current_PIN, const char *new_PIN) {
467 auto m = NitrokeyManager::instance();
468 return get_without_result([&]() {
469 m->change_user_PIN(current_PIN, new_PIN);
470 });
471 }
472
NK_enable_password_safe(const char * user_pin)473 NK_C_API int NK_enable_password_safe(const char *user_pin) {
474 auto m = NitrokeyManager::instance();
475 return get_without_result([&]() {
476 m->enable_password_safe(user_pin);
477 });
478 }
NK_get_password_safe_slot_status()479 NK_C_API uint8_t * NK_get_password_safe_slot_status() {
480 auto m = NitrokeyManager::instance();
481 return get_with_array_result([&]() {
482 auto slot_status = m->get_password_safe_slot_status();
483 return duplicate_vector_and_clear(slot_status);
484 });
485
486 }
487
NK_free_password_safe_slot_status(uint8_t * status)488 NK_C_API void NK_free_password_safe_slot_status(uint8_t* status) {
489 delete[] status;
490 }
491
NK_get_user_retry_count()492 NK_C_API uint8_t NK_get_user_retry_count() {
493 auto m = NitrokeyManager::instance();
494 return get_with_result([&]() {
495 return m->get_user_retry_count();
496 });
497 }
498
NK_get_admin_retry_count()499 NK_C_API uint8_t NK_get_admin_retry_count() {
500 auto m = NitrokeyManager::instance();
501 return get_with_result([&]() {
502 return m->get_admin_retry_count();
503 });
504 }
505
NK_lock_device()506 NK_C_API int NK_lock_device() {
507 auto m = NitrokeyManager::instance();
508 return get_without_result([&]() {
509 m->lock_device();
510 });
511 }
512
NK_get_password_safe_slot_name(uint8_t slot_number)513 NK_C_API char *NK_get_password_safe_slot_name(uint8_t slot_number) {
514 auto m = NitrokeyManager::instance();
515 return get_with_string_result([&]() {
516 return m->get_password_safe_slot_name(slot_number);
517 });
518 }
519
NK_get_password_safe_slot_login(uint8_t slot_number)520 NK_C_API char *NK_get_password_safe_slot_login(uint8_t slot_number) {
521 auto m = NitrokeyManager::instance();
522 return get_with_string_result([&]() {
523 return m->get_password_safe_slot_login(slot_number);
524 });
525 }
NK_get_password_safe_slot_password(uint8_t slot_number)526 NK_C_API char *NK_get_password_safe_slot_password(uint8_t slot_number) {
527 auto m = NitrokeyManager::instance();
528 return get_with_string_result([&]() {
529 return m->get_password_safe_slot_password(slot_number);
530 });
531 }
NK_write_password_safe_slot(uint8_t slot_number,const char * slot_name,const char * slot_login,const char * slot_password)532 NK_C_API int NK_write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login,
533 const char *slot_password) {
534 auto m = NitrokeyManager::instance();
535 return get_without_result([&]() {
536 m->write_password_safe_slot(slot_number, slot_name, slot_login, slot_password);
537 });
538 }
539
NK_erase_password_safe_slot(uint8_t slot_number)540 NK_C_API int NK_erase_password_safe_slot(uint8_t slot_number) {
541 auto m = NitrokeyManager::instance();
542 return get_without_result([&]() {
543 m->erase_password_safe_slot(slot_number);
544 });
545 }
546
NK_is_AES_supported(const char * user_password)547 NK_C_API int NK_is_AES_supported(const char *user_password) {
548 auto m = NitrokeyManager::instance();
549 return get_with_result([&]() {
550 return (uint8_t)m->is_AES_supported(user_password);
551 });
552 }
553
NK_login_auto()554 NK_C_API int NK_login_auto() {
555 auto m = NitrokeyManager::instance();
556 return get_with_result([&]() {
557 return (uint8_t)m->connect();
558 });
559 }
560
561 // storage commands
562
NK_send_startup(uint64_t seconds_from_epoch)563 NK_C_API int NK_send_startup(uint64_t seconds_from_epoch) {
564 auto m = NitrokeyManager::instance();
565 return get_without_result([&]() {
566 m->send_startup(seconds_from_epoch);
567 });
568 }
569
NK_unlock_encrypted_volume(const char * user_pin)570 NK_C_API int NK_unlock_encrypted_volume(const char* user_pin) {
571 auto m = NitrokeyManager::instance();
572 return get_without_result([&]() {
573 m->unlock_encrypted_volume(user_pin);
574 });
575 }
576
NK_lock_encrypted_volume()577 NK_C_API int NK_lock_encrypted_volume() {
578 auto m = NitrokeyManager::instance();
579 return get_without_result([&]() {
580 m->lock_encrypted_volume();
581 });
582 }
583
NK_unlock_hidden_volume(const char * hidden_volume_password)584 NK_C_API int NK_unlock_hidden_volume(const char* hidden_volume_password) {
585 auto m = NitrokeyManager::instance();
586 return get_without_result([&]() {
587 m->unlock_hidden_volume(hidden_volume_password);
588 });
589 }
590
NK_lock_hidden_volume()591 NK_C_API int NK_lock_hidden_volume() {
592 auto m = NitrokeyManager::instance();
593 return get_without_result([&]() {
594 m->lock_hidden_volume();
595 });
596 }
597
NK_create_hidden_volume(uint8_t slot_nr,uint8_t start_percent,uint8_t end_percent,const char * hidden_volume_password)598 NK_C_API int NK_create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent,
599 const char *hidden_volume_password) {
600 auto m = NitrokeyManager::instance();
601 return get_without_result([&]() {
602 m->create_hidden_volume(slot_nr, start_percent, end_percent,
603 hidden_volume_password);
604 });
605 }
606
607 // deprecated, noop on v0.51 and older (excl. v0.49)
608 #pragma GCC diagnostic push
609 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
NK_set_unencrypted_read_only(const char * user_pin)610 NK_C_API int NK_set_unencrypted_read_only(const char *user_pin) {
611 auto m = NitrokeyManager::instance();
612 return get_without_result([&]() {
613 m->set_unencrypted_read_only(user_pin);
614 });
615 }
616
617 // deprecated, noop on v0.51 and older (excl. v0.49)
NK_set_unencrypted_read_write(const char * user_pin)618 NK_C_API int NK_set_unencrypted_read_write(const char *user_pin) {
619 auto m = NitrokeyManager::instance();
620 return get_without_result([&]() {
621 m->set_unencrypted_read_write(user_pin);
622 });
623 }
624 #pragma GCC diagnostic pop
625
NK_set_unencrypted_read_only_admin(const char * admin_pin)626 NK_C_API int NK_set_unencrypted_read_only_admin(const char *admin_pin) {
627 auto m = NitrokeyManager::instance();
628 return get_without_result([&]() {
629 m->set_unencrypted_read_only_admin(admin_pin);
630 });
631 }
632
NK_set_unencrypted_read_write_admin(const char * admin_pin)633 NK_C_API int NK_set_unencrypted_read_write_admin(const char *admin_pin) {
634 auto m = NitrokeyManager::instance();
635 return get_without_result([&]() {
636 m->set_unencrypted_read_write_admin(admin_pin);
637 });
638 }
639
NK_set_encrypted_read_only(const char * admin_pin)640 NK_C_API int NK_set_encrypted_read_only(const char* admin_pin) {
641 auto m = NitrokeyManager::instance();
642 return get_without_result([&]() {
643 m->set_encrypted_volume_read_only(admin_pin);
644 });
645 }
646
NK_set_encrypted_read_write(const char * admin_pin)647 NK_C_API int NK_set_encrypted_read_write(const char* admin_pin) {
648 auto m = NitrokeyManager::instance();
649 return get_without_result([&]() {
650 m->set_encrypted_volume_read_write(admin_pin);
651 });
652 }
653
NK_export_firmware(const char * admin_pin)654 NK_C_API int NK_export_firmware(const char* admin_pin) {
655 auto m = NitrokeyManager::instance();
656 return get_without_result([&]() {
657 m->export_firmware(admin_pin);
658 });
659 }
660
NK_clear_new_sd_card_warning(const char * admin_pin)661 NK_C_API int NK_clear_new_sd_card_warning(const char* admin_pin) {
662 auto m = NitrokeyManager::instance();
663 return get_without_result([&]() {
664 m->clear_new_sd_card_warning(admin_pin);
665 });
666 }
667
NK_fill_SD_card_with_random_data(const char * admin_pin)668 NK_C_API int NK_fill_SD_card_with_random_data(const char* admin_pin) {
669 auto m = NitrokeyManager::instance();
670 return get_without_result([&]() {
671 m->fill_SD_card_with_random_data(admin_pin);
672 });
673 }
674
NK_change_update_password(const char * current_update_password,const char * new_update_password)675 NK_C_API int NK_change_update_password(const char* current_update_password,
676 const char* new_update_password) {
677 auto m = NitrokeyManager::instance();
678 return get_without_result([&]() {
679 m->change_update_password(current_update_password, new_update_password);
680 });
681 }
682
NK_enable_firmware_update(const char * update_password)683 NK_C_API int NK_enable_firmware_update(const char* update_password){
684 auto m = NitrokeyManager::instance();
685 return get_without_result([&]() {
686 m->enable_firmware_update(update_password);
687 });
688 }
689
NK_get_status_storage_as_string()690 NK_C_API char* NK_get_status_storage_as_string() {
691 auto m = NitrokeyManager::instance();
692 return get_with_string_result([&]() {
693 return m->get_status_storage_as_string();
694 });
695 }
696
NK_get_status_storage(NK_storage_status * out)697 NK_C_API int NK_get_status_storage(NK_storage_status* out) {
698 if (out == nullptr) {
699 return -1;
700 }
701 auto m = NitrokeyManager::instance();
702 auto result = get_with_status([&]() {
703 return m->get_status_storage();
704 }, proto::stick20::DeviceConfigurationResponsePacket::ResponsePayload());
705 auto error_code = std::get<0>(result);
706 if (error_code != 0) {
707 return error_code;
708 }
709
710 auto status = std::get<1>(result);
711 out->unencrypted_volume_read_only = status.ReadWriteFlagUncryptedVolume_u8 != 0;
712 out->unencrypted_volume_active = status.VolumeActiceFlag_st.unencrypted;
713 out->encrypted_volume_read_only = status.ReadWriteFlagCryptedVolume_u8 != 0;
714 out->encrypted_volume_active = status.VolumeActiceFlag_st.encrypted;
715 out->hidden_volume_read_only = status.ReadWriteFlagHiddenVolume_u8 != 0;
716 out->hidden_volume_active = status.VolumeActiceFlag_st.hidden;
717 out->firmware_version_major = status.versionInfo.major;
718 out->firmware_version_minor = status.versionInfo.minor;
719 out->firmware_locked = status.FirmwareLocked_u8 != 0;
720 out->serial_number_sd_card = status.ActiveSD_CardID_u32;
721 out->serial_number_smart_card = status.ActiveSmartCardID_u32;
722 out->user_retry_count = status.UserPwRetryCount;
723 out->admin_retry_count = status.AdminPwRetryCount;
724 out->new_sd_card_found = status.NewSDCardFound_st.NewCard;
725 out->filled_with_random = (status.SDFillWithRandomChars_u8 & 0x01) != 0;
726 out->stick_initialized = status.StickKeysNotInitiated == 0;
727 return 0;
728 }
729
NK_get_storage_production_info(NK_storage_ProductionTest * out)730 NK_C_API int NK_get_storage_production_info(NK_storage_ProductionTest * out){
731 if (out == nullptr) {
732 return -1;
733 }
734 auto m = NitrokeyManager::instance();
735 auto result = get_with_status([&]() {
736 return m->production_info();
737 }, proto::stick20::ProductionTest::ResponsePayload());
738
739 auto error_code = std::get<0>(result);
740 if (error_code != 0) {
741 return error_code;
742 }
743
744 stick20::ProductionTest::ResponsePayload status = std::get<1>(result);
745 // Cannot use memcpy without declaring C API struct packed
746 // (which is not parsed by Python's CFFI apparently), hence the manual way.
747 #define a(x) out->x = status.x;
748 a(FirmwareVersion_au8[0]);
749 a(FirmwareVersion_au8[1]);
750 a(FirmwareVersionInternal_u8);
751 a(SD_Card_Size_u8);
752 a(CPU_CardID_u32);
753 a(SmartCardID_u32);
754 a(SD_CardID_u32);
755 a(SC_UserPwRetryCount);
756 a(SC_AdminPwRetryCount);
757 a(SD_Card_ManufacturingYear_u8);
758 a(SD_Card_ManufacturingMonth_u8);
759 a(SD_Card_OEM_u16);
760 a(SD_WriteSpeed_u16);
761 a(SD_Card_Manufacturer_u8);
762 #undef a
763 return 0;
764 }
765
NK_get_SD_usage_data(struct NK_SD_usage_data * out)766 NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out) {
767 if (out == nullptr)
768 return -1;
769 auto m = NitrokeyManager::instance();
770 auto result = get_with_status([&]() {
771 return m->get_SD_usage_data();
772 }, std::make_pair<uint8_t, uint8_t>(0, 0));
773 auto error_code = std::get<0>(result);
774 if (error_code != 0)
775 return error_code;
776
777 auto data = std::get<1>(result);
778 out->write_level_min = std::get<0>(data);
779 out->write_level_max = std::get<1>(data);
780
781 return 0;
782 }
783
NK_get_SD_usage_data_as_string()784 NK_C_API char* NK_get_SD_usage_data_as_string() {
785 auto m = NitrokeyManager::instance();
786 return get_with_string_result([&]() {
787 return m->get_SD_usage_data_as_string();
788 });
789 }
790
NK_get_progress_bar_value()791 NK_C_API int NK_get_progress_bar_value() {
792 auto m = NitrokeyManager::instance();
793 return std::get<1>(get_with_status([&]() {
794 return m->get_progress_bar_value();
795 }, -2));
796 }
797
NK_get_major_firmware_version()798 NK_C_API uint8_t NK_get_major_firmware_version() {
799 auto m = NitrokeyManager::instance();
800 return get_with_result([&]() {
801 return m->get_major_firmware_version();
802 });
803 }
804
NK_get_minor_firmware_version()805 NK_C_API uint8_t NK_get_minor_firmware_version() {
806 auto m = NitrokeyManager::instance();
807 return get_with_result([&]() {
808 return m->get_minor_firmware_version();
809 });
810 }
811
NK_set_unencrypted_volume_rorw_pin_type_user()812 NK_C_API int NK_set_unencrypted_volume_rorw_pin_type_user() {
813 auto m = NitrokeyManager::instance();
814 return get_with_result([&]() {
815 return m->set_unencrypted_volume_rorw_pin_type_user() ? 1 : 0;
816 });
817 }
818
NK_list_devices_by_cpuID()819 NK_C_API char* NK_list_devices_by_cpuID() {
820 auto nm = NitrokeyManager::instance();
821 return get_with_string_result([&]() {
822 auto v = nm->list_devices_by_cpuID();
823 std::string res;
824 for (const auto a : v){
825 res += a+";";
826 }
827 if (res.size()>0) res.pop_back(); // remove last delimiter char
828 return strndup(res.c_str(), MAXIMUM_STR_REPLY_LENGTH);
829 });
830 }
831
copy_device_info(const DeviceInfo & source,NK_device_info * target)832 bool copy_device_info(const DeviceInfo& source, NK_device_info* target) {
833 switch (source.m_deviceModel) {
834 case DeviceModel::PRO:
835 target->model = NK_PRO;
836 break;
837 case DeviceModel::STORAGE:
838 target->model = NK_STORAGE;
839 break;
840 case DeviceModel::LIBREM:
841 target->model = NK_LIBREM;
842 break;
843 default:
844 return false;
845 }
846
847 target->path = strndup(source.m_path.c_str(), MAXIMUM_STR_REPLY_LENGTH);
848 target->serial_number = strndup(source.m_serialNumber.c_str(), MAXIMUM_STR_REPLY_LENGTH);
849 target->next = nullptr;
850
851 return target->path && target->serial_number;
852 }
853
NK_list_devices()854 NK_C_API struct NK_device_info* NK_list_devices() {
855 auto nm = NitrokeyManager::instance();
856 return get_with_result([&]() -> NK_device_info* {
857 auto v = nm->list_devices();
858 if (v.empty())
859 return nullptr;
860
861 auto result = new NK_device_info();
862 auto ptr = result;
863 auto first = v.begin();
864 if (!copy_device_info(*first, ptr)) {
865 NK_free_device_info(result);
866 return nullptr;
867 }
868 v.erase(first);
869
870 for (auto& info : v) {
871 ptr->next = new NK_device_info();
872 ptr = ptr->next;
873
874 if (!copy_device_info(info, ptr)) {
875 NK_free_device_info(result);
876 return nullptr;
877 }
878 }
879 return result;
880 });
881 }
882
NK_free_device_info(struct NK_device_info * device_info)883 NK_C_API void NK_free_device_info(struct NK_device_info* device_info) {
884 if (!device_info)
885 return;
886
887 if (device_info->next)
888 NK_free_device_info(device_info->next);
889
890 free(device_info->path);
891 free(device_info->serial_number);
892 delete device_info;
893 }
894
NK_connect_with_ID(const char * id)895 NK_C_API int NK_connect_with_ID(const char* id) {
896 auto m = NitrokeyManager::instance();
897 return get_with_result([&]() {
898 return m->connect_with_ID(id) ? 1 : 0;
899 });
900 }
901
NK_connect_with_path(const char * path)902 NK_C_API int NK_connect_with_path(const char* path) {
903 auto m = NitrokeyManager::instance();
904 return get_with_result([&]() {
905 return m->connect_with_path(path) ? 1 : 0;
906 });
907 }
908
909
NK_wink()910 NK_C_API int NK_wink() {
911 auto m = NitrokeyManager::instance();
912 return get_without_result([&]() {
913 return m->wink();
914 });
915 }
916
NK_enable_firmware_update_pro(const char * update_password)917 NK_C_API int NK_enable_firmware_update_pro(const char* update_password){
918 auto m = NitrokeyManager::instance();
919 return get_without_result([&]() {
920 m->enable_firmware_update_pro(update_password);
921 });
922 }
923
NK_change_firmware_password_pro(const char * current_firmware_password,const char * new_firmware_password)924 NK_C_API int NK_change_firmware_password_pro(const char *current_firmware_password, const char *new_firmware_password) {
925 auto m = NitrokeyManager::instance();
926 return get_without_result([&]() {
927 m->change_firmware_update_password_pro(current_firmware_password,
928 new_firmware_password);
929 });
930 }
931
932
NK_read_HOTP_slot(const uint8_t slot_num,struct ReadSlot_t * out)933 NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out){
934 if (out == nullptr)
935 return -1;
936 auto m = NitrokeyManager::instance();
937 auto result = get_with_status([&]() {
938 return m->get_HOTP_slot_data(slot_num);
939 }, stick10::ReadSlot::ResponsePayload() );
940 auto error_code = std::get<0>(result);
941 if (error_code != 0) {
942 return error_code;
943 }
944 #define a(x) out->x = read_slot.x
945 stick10::ReadSlot::ResponsePayload read_slot = std::get<1>(result);
946 a(_slot_config);
947 a(slot_counter);
948 #undef a
949 #define m(x) memmove(out->x, read_slot.x, sizeof(read_slot.x))
950 m(slot_name);
951 m(slot_token_id);
952 #undef m
953 return 0;
954 }
955
956
957 #ifdef __cplusplus
958 }
959 #endif
960