diff --git a/examples/desktop/at_talk/src/main.c b/examples/desktop/at_talk/src/main.c index a7521e90..07ad72ba 100644 --- a/examples/desktop/at_talk/src/main.c +++ b/examples/desktop/at_talk/src/main.c @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) { pthread_mutex_lock(&client_mutex); atclient_authenticate_options options; atclient_authenticate_options_init(&options); - if ((ret = atclient_pkam_authenticate(&atclient1, from_atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient1, from_atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "\natclient_pkam_authenticate: %d\n", ret); goto exit; } @@ -342,7 +342,7 @@ static int reconnect_clients(atclient *monitor, atclient *ctx, const char *atser atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Reconnecting client connection...\n"); atclient_authenticate_options options; atclient_authenticate_options_init(&options); - if ((ret = atclient_pkam_authenticate(ctx, from_atsign, atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(ctx, from_atsign, atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_pkam_authenticate: %d\n", ret); return ret; } diff --git a/examples/desktop/crud/delete.c b/examples/desktop/crud/delete.c index dbe8b09a..c68253fe 100644 --- a/examples/desktop/crud/delete.c +++ b/examples/desktop/crud/delete.c @@ -49,7 +49,7 @@ int main() { goto exit; } - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate"); goto exit; } diff --git a/examples/desktop/crud/get_publickey.c b/examples/desktop/crud/get_publickey.c index 9d748413..05ff093f 100644 --- a/examples/desktop/crud/get_publickey.c +++ b/examples/desktop/crud/get_publickey.c @@ -55,7 +55,7 @@ int main() { char *metadatajsonstr = NULL; - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate"); goto exit; } diff --git a/examples/desktop/crud/get_selfkey.c b/examples/desktop/crud/get_selfkey.c index c1c8c35f..6225257c 100644 --- a/examples/desktop/crud/get_selfkey.c +++ b/examples/desktop/crud/get_selfkey.c @@ -53,7 +53,7 @@ int main() { char *atkeystr = NULL; - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); goto exit; } else { diff --git a/examples/desktop/crud/get_sharedkey.c b/examples/desktop/crud/get_sharedkey.c index 73d3aae7..db810103 100644 --- a/examples/desktop/crud/get_sharedkey.c +++ b/examples/desktop/crud/get_sharedkey.c @@ -66,7 +66,7 @@ int main() { char *atkeystr = NULL; - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); goto exit; } else { diff --git a/examples/desktop/crud/put_publickey.c b/examples/desktop/crud/put_publickey.c index 7ba455bc..8295498c 100644 --- a/examples/desktop/crud/put_publickey.c +++ b/examples/desktop/crud/put_publickey.c @@ -52,7 +52,7 @@ int main() { char *atkeystr = NULL; - if ((ret = atclient_pkam_authenticate(&atclient, ATSIGN, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, ATSIGN, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate"); goto exit; } diff --git a/examples/desktop/crud/put_selfkey.c b/examples/desktop/crud/put_selfkey.c index 498053f5..33ace246 100644 --- a/examples/desktop/crud/put_selfkey.c +++ b/examples/desktop/crud/put_selfkey.c @@ -52,7 +52,7 @@ int main() { char *atkeystr = NULL; - if ((ret = atclient_pkam_authenticate(&atclient, ATSIGN, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, ATSIGN, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate"); goto exit; } diff --git a/examples/desktop/crud/put_sharedkey.c b/examples/desktop/crud/put_sharedkey.c index 720617b3..636d37a6 100644 --- a/examples/desktop/crud/put_sharedkey.c +++ b/examples/desktop/crud/put_sharedkey.c @@ -53,7 +53,7 @@ int main() { char *atkeystr = NULL; - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate"); goto exit; } diff --git a/examples/desktop/events/monitor.c b/examples/desktop/events/monitor.c index 36880b13..157698de 100644 --- a/examples/desktop/events/monitor.c +++ b/examples/desktop/events/monitor.c @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) { goto exit; } - if ((ret = atclient_pkam_authenticate(&atclient2, atsign, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient2, atsign, &atkeys, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate with PKAM\n"); goto exit; } diff --git a/examples/desktop/events/notify.c b/examples/desktop/events/notify.c index 4506ee06..f2bd2445 100644 --- a/examples/desktop/events/notify.c +++ b/examples/desktop/events/notify.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) { - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); goto exit; } diff --git a/examples/desktop/events/resilient_monitor.c b/examples/desktop/events/resilient_monitor.c index a2834103..69d0fb63 100644 --- a/examples/desktop/events/resilient_monitor.c +++ b/examples/desktop/events/resilient_monitor.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) { goto exit; } - if ((ret = atclient_pkam_authenticate(&atclient2, atsign, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient2, atsign, &atkeys, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate with PKAM\n"); goto exit; } diff --git a/examples/desktop/pkam_authenticate/src/main.c b/examples/desktop/pkam_authenticate/src/main.c index c6eebcac..fec0e4dd 100644 --- a/examples/desktop/pkam_authenticate/src/main.c +++ b/examples/desktop/pkam_authenticate/src/main.c @@ -36,8 +36,9 @@ int main(int argc, char **argv) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "atclient_atkeys_populate_from_atkeys_file: %d\n", ret); const char *atsign = ATSIGN; + char *err_msg; - if ((ret = atclient_pkam_authenticate(&atclient, ATSIGN, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, ATSIGN, &atkeys, NULL, &err_msg)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); goto exit; } else { diff --git a/examples/desktop/reconnection/main.c b/examples/desktop/reconnection/main.c index 52df3419..b5cb2bf6 100644 --- a/examples/desktop/reconnection/main.c +++ b/examples/desktop/reconnection/main.c @@ -33,7 +33,7 @@ int main() { goto exit; } - if ((ret = atclient_pkam_authenticate(&atclient1, ATSIGN, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient1, ATSIGN, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to PKAM authenticate.\n"); goto exit; } @@ -47,7 +47,7 @@ int main() { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "We are connected to the atServer! :)\n"); } else { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "We are not connected to atServer? :(\n"); - if((ret = atclient_pkam_authenticate(&atclient1, ATSIGN, &atkeys, &options)) == 0) { + if((ret = atclient_pkam_authenticate(&atclient1, ATSIGN, &atkeys, &options, NULL)) == 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Reconnected to atServer! :)\n"); atclient_set_read_timeout(&atclient1, 1000); } else { diff --git a/examples/desktop/repl/src/main.c b/examples/desktop/repl/src/main.c index 7ca1e764..d1f57138 100644 --- a/examples/desktop/repl/src/main.c +++ b/examples/desktop/repl/src/main.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { goto exit; } - if ((ret = atclient_pkam_authenticate(&atclient, repl_args.atsign, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, repl_args.atsign, &atkeys, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); goto exit; } diff --git a/packages/atauth/CMakeLists.txt b/packages/atauth/CMakeLists.txt index 1c8f343d..54da6a7f 100644 --- a/packages/atauth/CMakeLists.txt +++ b/packages/atauth/CMakeLists.txt @@ -9,6 +9,7 @@ set( ${CMAKE_CURRENT_LIST_DIR}/src/send_enroll_request.c ${CMAKE_CURRENT_LIST_DIR}/src/atactivate_arg_parser.c ${CMAKE_CURRENT_LIST_DIR}/src/atactivate.c + ${CMAKE_CURRENT_LIST_DIR}/src/auth_cli.c ${CMAKE_CURRENT_LIST_DIR}/src/atauth_build_atkeys_file_path.c ${CMAKE_CURRENT_LIST_DIR}/src/atauth_fetch_home_dir.c ) @@ -125,7 +126,9 @@ if(NOT ESP_PLATFORM) atactivate PRIVATE cjson atlogger atcommons atchops atclient atauth ) - endif() + add_executable(at_auth_cli ${CMAKE_CURRENT_LIST_DIR}/src/auth_cli.c) + target_link_libraries(at_auth_cli PRIVATE cjson atlogger atcommons atchops atclient atauth) + endif () # EXPORT if(NOT ATAUTH_AS_SUBPROJECT) diff --git a/packages/atauth/include/atauth/atactivate_arg_parser.h b/packages/atauth/include/atauth/atactivate_arg_parser.h index 17646259..74e7522f 100644 --- a/packages/atauth/include/atauth/atactivate_arg_parser.h +++ b/packages/atauth/include/atauth/atactivate_arg_parser.h @@ -11,15 +11,18 @@ * * @param argc The number of arguments * @param argv The array of arguments - * @param atsign pointer to store the atsign value - * @param cram_secret pointer to store the cram_secret value - * @param otp - * @param atkeys_fp pointer to store the file path of the atkeys - * @param root_host pointer to store the root host server address - * @param root_port pointer to store the root port value + * @param atsign pointer to store the parsed atsign value + * @param cram_secret pointer to store the parsed cram_secret value + * @param otp OTP pointer to store the parsed OTP/SPP value (accepts OTP fetched from OTP verb) + * @param atkeys_fp pointer to store the parsed file path of the atkeys + * @param app_name pointer to store the parsed app_name for current enrollment + * @param device_name pointer to store the parsed device_name for current enrollment + * @param namespaces pointert to store the parsed namespaces list for current enrollment + * @param root_host pointer to store the parsed root server host + * @param root_port pointer to store the parsed root server port * @return int 0 on success, non-zero on error */ int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_secret, char **otp, char **atkeys_fp, - char **root_host, int *root_port); + char **app_name, char **device_name, char **namespaces, char **root_host, int *root_port); #endif // ATACTIVATE_ARG_PARSER_H diff --git a/packages/atauth/include/atauth/atauth_constants.h b/packages/atauth/include/atauth/atauth_constants.h new file mode 100644 index 00000000..06106ab3 --- /dev/null +++ b/packages/atauth/include/atauth/atauth_constants.h @@ -0,0 +1,12 @@ +#define ATAUTH_DEFAULT_FIRST_APP_NAME "firstApp" +#define ATAUTH_DEFAULT_FIRST_DEVICE_NAME "firstDevice" +#define ATAUTH_AES_256_KEY_BYTES 32 +#define ATAUTH_RSA_2048_PRIVKEY_BYTES 1300 // in PKCS#8 format includes padding + +#define ATAUTH_DEFAULT_APKAM_RETRY_INTERVAL 10 // seconds +#define ATAUTH_MAX_APKAM_AUTH_RETRY_ATTMEPTS 10 +#define ATAUTH_ENROLLMENT_DENIED_ERR_CODE "error:AT0025" +#define ATAUTH_ENROLLMENT_PENDING_ERR_CODE "error:AT0026" + +#define ATAUTH_ENCRYPTED_DEFAULT_ENC_PRIVKEY_NAME "default_enc_private_key" +#define ATAUTH_ENCRYPTED_SELF_ENC_KEY_NAME "default_self_enc_key" \ No newline at end of file diff --git a/packages/atauth/src/atactivate.c b/packages/atauth/src/atactivate.c index 03101fe8..232b56ef 100644 --- a/packages/atauth/src/atactivate.c +++ b/packages/atauth/src/atactivate.c @@ -1,5 +1,6 @@ #include "atauth/atactivate_arg_parser.h" #include "atauth/atauth_build_atkeys_file_path.h" +#include "atauth/atauth_constants.h" #include "atchops/base64.h" #include "atclient/atclient.h" #include "atclient/atkeys.h" @@ -11,20 +12,16 @@ #include #include +#include #include #include -#define TAG "atactivate" -#define DEFAULT_FIRST_APP_NAME "firstApp" -#define DEFAULT_FIRST_DEVICE_NAME "firstDevice" -#define AES_256_KEY_BYTES 32 -#define RSA_2048_PRIVKEY_BYTES 1300 // in PKCS#8 format includes padding +#define TAG "activate_cli" int main(int argc, char *argv[]) { - atlogger_set_logging_level(ATLOGGER_LOGGING_LEVEL_INFO); int ret = 0; - char *atsign = NULL, *cram_secret = NULL, *root_host = NULL, *atkeys_fp = NULL, *otp = NULL; - int *root_port = NULL; + char *atsign_temp = NULL, *cram_secret = NULL, *root_host = NULL, *atkeys_fp = NULL, *otp = NULL; + int root_port = 0; char enrollment_id[ENROLL_ID_MAX_LEN]; char status[ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN]; @@ -33,7 +30,7 @@ int main(int argc, char *argv[]) { // initialize apkam symmetric key and self encryption key (bytes) unsigned char *self_encryption_key_bytes, *apkam_symmetric_key_bytes; - size_t aes256_key_unsigned_char_bytes_size = sizeof(unsigned char) * AES_256_KEY_BYTES; + size_t aes256_key_unsigned_char_bytes_size = sizeof(unsigned char) * ATAUTH_AES_256_KEY_BYTES; self_encryption_key_bytes = malloc(aes256_key_unsigned_char_bytes_size); apkam_symmetric_key_bytes = malloc(aes256_key_unsigned_char_bytes_size); @@ -44,7 +41,7 @@ int main(int argc, char *argv[]) { unsigned char *apkam_symmetric_key_base64 = malloc(aes256_key_unsigned_char_base64_size); // intialize encrypted APKAM symmetric Key and encrypted default encryption private key (bytes) - const size_t rsa_2048_privkey_base64_len = atchops_base64_encoded_size(RSA_2048_PRIVKEY_BYTES); + const size_t rsa_2048_privkey_base64_len = atchops_base64_encoded_size(ATAUTH_RSA_2048_PRIVKEY_BYTES); const size_t aes256_encrypted_rsa_privkey_size = atchops_aes_ctr_ciphertext_size( rsa_2048_privkey_base64_len); // size for an AES256 encrypted RSA2048 privkey in bytes const size_t aes256_encrypted_rsa_privkey_unsigned_char_size = @@ -53,8 +50,9 @@ int main(int argc, char *argv[]) { aes_key_base64_size); // size of AES256 key encrypted with another AES256 key(bytes) const size_t aes256_encrypted_aes256_key_unsigned_char_size = sizeof(unsigned char) * aes256_encrypted_aes256_key_size; - unsigned char *encrypted_default_encryption_private_key = malloc(aes256_encrypted_rsa_privkey_unsigned_char_size); - unsigned char *encrypted_self_encryption_key = malloc(aes256_encrypted_aes256_key_unsigned_char_size); + unsigned char *encrypted_default_encryption_private_key_bytes = + malloc(aes256_encrypted_rsa_privkey_unsigned_char_size); + unsigned char *encrypted_self_encryption_key_bytes = malloc(aes256_encrypted_aes256_key_unsigned_char_size); // intialize base64 encoded encrypted APKAM symmetric Key and encrypted default encryption private key const size_t aes256_encrypted_rsa_2048_privkey_base64_len = atchops_base64_encoded_size(rsa_2048_privkey_base64_len); @@ -94,13 +92,13 @@ int main(int argc, char *argv[]) { ret = -1; goto aes_keys_bytes_exit; } - if (encrypted_default_encryption_private_key == NULL) { + if (encrypted_default_encryption_private_key_bytes == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for encrypted_default_encryption_private_key buffer\n"); ret = -1; goto aes_keys_bytes_exit; } - if (encrypted_self_encryption_key == NULL) { + if (encrypted_self_encryption_key_bytes == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for encrypted_self_encryption_key buffer\n"); ret = -1; @@ -129,8 +127,8 @@ int main(int argc, char *argv[]) { memset(apkam_symmetric_key_bytes, 0, aes256_key_unsigned_char_bytes_size); memset(self_encryption_key_base64, 0, aes256_key_unsigned_char_base64_size); memset(apkam_symmetric_key_base64, 0, aes256_key_unsigned_char_base64_size); - memset(encrypted_default_encryption_private_key, 0, aes256_encrypted_rsa_privkey_unsigned_char_size); - memset(encrypted_self_encryption_key, 0, aes256_encrypted_aes256_key_unsigned_char_size); + memset(encrypted_default_encryption_private_key_bytes, 0, aes256_encrypted_rsa_privkey_unsigned_char_size); + memset(encrypted_self_encryption_key_bytes, 0, aes256_encrypted_aes256_key_unsigned_char_size); memset(encrypted_default_encryption_private_key_base64, 0, sizeof(unsigned char) * aes256_encrypted_rsa_2048_privkey_base64_len); memset(encrypted_self_encryption_key_base64, 0, sizeof(unsigned char) * aes256_encrypted_aes_key_base64_len); @@ -139,10 +137,20 @@ int main(int argc, char *argv[]) { /* * 1. Parse args */ - if ((ret = atactivate_parse_args(argc, argv, &atsign, &cram_secret, &otp, &atkeys_fp, &root_host, root_port)) != 0) { + if ((ret = atactivate_parse_args(argc, argv, &atsign_temp, &cram_secret, &otp, &atkeys_fp, NULL, NULL, NULL, + &root_host, &root_port)) != 0) { goto exit; } - // 1.1 if atkeys filepath was not passed through args, build default atkeys file path + + // 1.1 Ensure atsign starts with '@' + char *atsign = NULL; + if ((ret = atclient_string_utils_atsign_with_at(atsign_temp, &atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_string_utils_atsign_with_at: %d\n", ret); + goto exit; + } + free(atsign_temp); // no longer needed + + // 1.2 if atkeys filepath was not passed through args, build default atkeys file path if (atkeys_fp == NULL) { if ((ret = atauth_build_atkeys_file_path(&atkeys_fp, atsign)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not build atkeys filepath\n"); @@ -243,11 +251,11 @@ int main(int argc, char *argv[]) { * 4. Encrypt the keys and send the onboarding enrollment request */ // 4.1 Encrypt default_encryption_private_key with APKAM Symmetric Key - size_t encrypted_def_encrypt_private_key_len = 0; + size_t encrypted_def_encrypt_private_key_bytes_len = 0; if ((ret = atchops_aes_ctr_encrypt( apkam_symmetric_key_bytes, ATCHOPS_AES_256, iv, encrypt_private_key_base64, - strlen((char *)encrypt_private_key_base64), encrypted_default_encryption_private_key, - aes256_encrypted_rsa_privkey_unsigned_char_size, &encrypted_def_encrypt_private_key_len)) != 0) { + strlen((char *)encrypt_private_key_base64), encrypted_default_encryption_private_key_bytes, + aes256_encrypted_rsa_privkey_unsigned_char_size, &encrypted_def_encrypt_private_key_bytes_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "AES encrypt default_encryption_private_key failed | ret: %d\n", ret); goto def_enc_keypair_free_exit; @@ -255,7 +263,8 @@ int main(int argc, char *argv[]) { // 4.1.1 Base64 encode the encrypted_default_encryption_private_key size_t encrypted_default_encryption_private_key_base64_len = 0; - if ((ret = atchops_base64_encode(encrypted_default_encryption_private_key, encrypted_def_encrypt_private_key_len, + if ((ret = atchops_base64_encode(encrypted_default_encryption_private_key_bytes, + encrypted_def_encrypt_private_key_bytes_len, encrypted_default_encryption_private_key_base64, sizeof(unsigned char) * aes256_encrypted_rsa_2048_privkey_base64_len, &encrypted_default_encryption_private_key_base64_len)) != 0) { @@ -265,18 +274,18 @@ int main(int argc, char *argv[]) { } // 4.2 Encrypt self_encryption_key with APKAM Symmetric Key - size_t encrypted_self_encrypt_key_len = 0; + size_t encrypted_self_encrypt_key_bytes_len = 0; if ((ret = atchops_aes_ctr_encrypt(apkam_symmetric_key_bytes, ATCHOPS_AES_256, iv, self_encryption_key_base64, - strlen((const char *)self_encryption_key_base64), encrypted_self_encryption_key, + strlen((char *)self_encryption_key_base64), encrypted_self_encryption_key_bytes, aes256_encrypted_aes256_key_unsigned_char_size, - &encrypted_self_encrypt_key_len)) != 0) { + &encrypted_self_encrypt_key_bytes_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "AES encrypt self_encryption_key failed\tret: %d\n", ret); goto def_enc_keypair_free_exit; } // 4.2.1 Base64 encode the encrypted_self_encryption_key size_t encrypted_self_encryption_key_base64_len = 0; - if ((ret = atchops_base64_encode(encrypted_self_encryption_key, encrypted_self_encrypt_key_len, + if ((ret = atchops_base64_encode(encrypted_self_encryption_key_bytes, encrypted_self_encrypt_key_bytes_len, encrypted_self_encryption_key_base64, sizeof(unsigned char) * aes256_encrypted_aes_key_base64_len, &encrypted_self_encryption_key_base64_len)) != 0) { @@ -287,8 +296,8 @@ int main(int argc, char *argv[]) { // 4.3 Initialize enrollment params atcommons_enroll_params_init(ep); - ep->app_name = DEFAULT_FIRST_APP_NAME; - ep->device_name = DEFAULT_FIRST_DEVICE_NAME; + ep->app_name = ATAUTH_DEFAULT_FIRST_APP_NAME; + ep->device_name = ATAUTH_DEFAULT_FIRST_DEVICE_NAME; ep->apkam_public_key = (unsigned char *)atkeys.pkam_public_key_base64; ep->encrypted_default_encryption_private_key = encrypted_default_encryption_private_key_base64; ep->encrypted_self_encryption_key = encrypted_self_encryption_key_base64; @@ -312,7 +321,7 @@ int main(int argc, char *argv[]) { /* * 6. Perform PKAM auth */ - if ((ret = atclient_pkam_authenticate(&at_client, atsign, &atkeys, &options)) != 0) { + if ((ret = atclient_pkam_authenticate(&at_client, atsign, &atkeys, &options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "PKAM auth failed | atclient_pkam_authenticate: %d\n", ret); goto atclient_exit; } @@ -330,7 +339,7 @@ int main(int argc, char *argv[]) { } atclient_atkey_metadata_set_is_public(&def_enc_pub_atkey.metadata, true); - if ((ret = atclient_put_public_key(&at_client, &def_enc_pub_atkey, atkeys.encrypt_private_key_base64, NULL, NULL)) != + if ((ret = atclient_put_public_key(&at_client, &def_enc_pub_atkey, atkeys.encrypt_public_key_base64, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to updating enc_public_key to server | atclient_put_public_key: %d\n", ret); @@ -393,8 +402,8 @@ args_exit: { enroll_params_exit: { free(ep); } enc_self_enc_key_base64_exit: { free(encrypted_self_encryption_key_base64); } enc_def_enc_privkey_base64_exit: { free(encrypted_default_encryption_private_key_base64); } -enc_self_enc_key_exit: { free(encrypted_self_encryption_key); } -enc_def_enc_privkey_exit: { free(encrypted_default_encryption_private_key); } +enc_self_enc_key_exit: { free(encrypted_self_encryption_key_bytes); } +enc_def_enc_privkey_exit: { free(encrypted_default_encryption_private_key_bytes); } aes_keys_bytes_exit: { free(apkam_symmetric_key_bytes); } self_enc_key_bytes_exit: { free(self_encryption_key_bytes); } iv_exit: { free(iv); } diff --git a/packages/atauth/src/atactivate_arg_parser.c b/packages/atauth/src/atactivate_arg_parser.c index 80de3f7e..f4e64106 100644 --- a/packages/atauth/src/atactivate_arg_parser.c +++ b/packages/atauth/src/atactivate_arg_parser.c @@ -1,33 +1,23 @@ #include "atauth/atactivate_arg_parser.h" +#include +#include #include #include #include #include -#define DEFAULT_ROOT_SERVER "root.atsign.org" -#define DEFAULT_ROOT_PORT 64 +int parse_root_domain(const char *root_domain_string, char **root_host, int *root_port); -int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_secret, char **otp, char **atkeys_fp, - char **root_host, int *root_port) { - int ret = 0; - int opt; - - // Initialize defaults - *root_host = malloc(sizeof(char) * strlen(DEFAULT_ROOT_SERVER) + 1); - if (*root_host == NULL) { - fprintf(stderr, "Memory allocation failed for root_host\n"); - return -1; - } - strcpy(*root_host, DEFAULT_ROOT_SERVER); - root_port = malloc(sizeof(int)); - if (root_port == NULL) { - fprintf(stderr, "Memory allocation failed for root_port\n"); - return -1; - } - *root_port = DEFAULT_ROOT_PORT; +int atactivate_parse_args(const int argc, char *argv[], char **atsign, char **cram_secret, char **otp, char **atkeys_fp, + char **app_name, char **device_name, char **namespaces, char **root_host, int *root_port) { + int ret = 0, opt = 0; + char *root_fqdn = NULL; + const char *usage = "Usage: \n\tActivate: \t./atactivate -a atsign -c cram-secret [-k path_to_store_keysfile] [-r root-domain]" + "\n\n\tNew enrollment: ./at_auth_cli -a atsign -s otp/spp -p app_name -d device_name -n " + "namespaces(\"wavi:rw,buzz:r\") [-k path_to_store_keysfile] [-r root-domain]\n"; // Parse command-line arguments - while ((opt = getopt(argc, argv, "a:c:k:o:r:p:h")) != -1) { + while ((opt = getopt(argc, argv, "a:c:k:s:p:d:n:r:vh")) != -1) { switch (opt) { case 'a': *atsign = malloc(sizeof(char) * strlen(optarg) + 1); @@ -39,6 +29,8 @@ int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_sec strcpy(*atsign, optarg); break; case 'c': + if (cram_secret == NULL) + break; *cram_secret = malloc(sizeof(char) * strlen(optarg) + 1); if (*cram_secret == NULL) { fprintf(stderr, "Memory allocation failed for cram_secret\n"); @@ -48,6 +40,8 @@ int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_sec strcpy(*cram_secret, optarg); break; case 'k': + if (atkeys_fp == NULL) + break; *atkeys_fp = malloc(sizeof(char) * strlen(optarg) + 1); if (*atkeys_fp == NULL) { fprintf(stderr, "Memory allocation failed for atkeys file path\n"); @@ -56,49 +50,103 @@ int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_sec } strcpy(*atkeys_fp, optarg); break; - case 'o': + case 's': + if (otp == NULL) + break; *otp = malloc(sizeof(char) * strlen(optarg)); - if(*otp == NULL) { - fprintf(stderr, "Memory allocation failed for atkeys file path\n"); + if (*otp == NULL) { + fprintf(stderr, "Memory allocation failed for OTP\n"); ret = -1; goto exit; } strcpy(*otp, optarg); break; + case 'p': + if (app_name == NULL) + break; + *app_name = malloc(sizeof(char) * strlen(optarg) + 1); + if (*app_name == NULL) { + fprintf(stderr, "Memory reallocation failed for app_name\n"); + ret = -1; + goto exit; + } + strcpy(*app_name, optarg); + break; + case 'd': + if (device_name == NULL) + break; + *device_name = malloc(sizeof(char) * strlen(optarg) + 1); + if (*device_name == NULL) { + fprintf(stderr, "Memory reallocation failed for device_name\n"); + ret = -1; + goto exit; + } + strcpy(*device_name, optarg); + break; + case 'n': + if (namespaces == NULL) + break; + *namespaces = malloc(sizeof(char) * strlen(optarg) + 1); + if (*namespaces == NULL) { + fprintf(stderr, "Memory reallocation failed for namespaces\n"); + ret = -1; + goto exit; + } + strcpy(*namespaces, optarg); + break; case 'r': - *root_host = realloc(*root_host, sizeof(char) * strlen(optarg) + 1); - if (*root_host == NULL) { - fprintf(stderr, "Memory reallocation failed for root_host\n"); + root_fqdn = malloc(sizeof(char) * strlen(optarg) + 1); + if (root_fqdn == NULL) { + fprintf(stderr, "Memory allocation failed for root_host\n"); ret = -1; goto exit; } - strcpy(*root_host, optarg); + strcpy(root_fqdn, optarg); break; - case 'p': - *root_port = atoi(optarg); + case 'v': + atlogger_set_logging_level(ATLOGGER_LOGGING_LEVEL_DEBUG); break; case 'h': - fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); - exit(0); // force exit to display usage + fprintf(stdout, usage); + ret = 0; + goto exit; default: - fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + fprintf(stderr, usage); ret = -1; goto exit; } } - if (*atsign == NULL) { + // set default root server address if not provided through CLI + if (root_fqdn == NULL || parse_root_domain(root_fqdn, root_host, root_port) != 0) { + *root_host = strdup(ATCLIENT_ATDIRECTORY_PRODUCTION_HOST); + *root_port = ATCLIENT_ATDIRECTORY_PRODUCTION_PORT; + } + + if (atsign == NULL) { fprintf(stderr, "Error: -a (atsign) is mandatory.\n"); - fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + fprintf(stderr, usage); ret = 1; } - if(*cram_secret == NULL && *otp == NULL) { - fprintf(stderr, "Cannot proceed without either of CRAM secret on enroll OTP.\n"); - fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + if (cram_secret == NULL && otp == NULL) { + fprintf(stderr, "Cannot proceed without either of CRAM secret or enroll OTP.\n"); + fprintf(stderr, usage); ret = 1; } exit: return ret; } + +int parse_root_domain(const char *root_domain_string, char **root_host, int *root_port) { + if(root_domain_string == NULL) { + return 1; + } + *root_host = strdup(strtok((char *)root_domain_string, ":")); + *root_port = atoi(strtok(NULL, ":")); + if(*root_host == NULL || root_port == NULL) { + return 1; + } + return 0; +} diff --git a/packages/atauth/src/auth_cli.c b/packages/atauth/src/auth_cli.c new file mode 100644 index 00000000..c858256e --- /dev/null +++ b/packages/atauth/src/auth_cli.c @@ -0,0 +1,560 @@ +#include "atauth/atauth_constants.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAG "auth_cli" + +int is_enrollment_denied(const char *err_msg); +int retry_pkam_auth_until_success(atclient *ctx, const char *atsign, const atclient_atkeys *atkeys, + const atclient_authenticate_options *opts); +int get_apkam_key(char **key, const char *key_name, atclient_connection *ctx, const char *enrollment_id, + const char *atsign); +int create_new_atserver_connection(atclient *ctx, const char *atsign, const atclient_authenticate_options *options); +int atauth_validate_args(const char *otp, const char *app_name, const char *device_name, const char *namespaces_str); + +int main(int argc, char *argv[]) { + atlogger_set_logging_level(ATLOGGER_LOGGING_LEVEL_INFO); + int ret = 0, root_port = 0; + char *atsign_temp = NULL, *root_host = NULL, *atkeys_fp = NULL, *otp = NULL, *app_name = NULL, *device_name = NULL, + *namespaces_str = NULL; + + char enrollment_id[ENROLL_ID_MAX_LEN]; + char status[ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN]; + + // initialize apkam symmetric key buffer (bytes) + size_t aes256_key_unsigned_char_bytes_size = sizeof(unsigned char) * ATAUTH_AES_256_KEY_BYTES; + unsigned char apkam_symmetric_key_bytes[aes256_key_unsigned_char_bytes_size]; + + // initialize apkam symmetric key buffer (base64) + size_t aes_key_base64_size = atchops_base64_encoded_size(aes256_key_unsigned_char_bytes_size); + size_t aes256_key_unsigned_char_base64_size = sizeof(unsigned char) * aes_key_base64_size; + unsigned char apkam_symmetric_key_base64[aes256_key_unsigned_char_base64_size]; + + // init buffer to hold apkam symmetric key that is encrypted using at_server's default encryption public key (bytes) + const size_t rsa_2048_ciphertext_size = 256; + unsigned char encrypted_apkam_symmetric_key_bytes[rsa_2048_ciphertext_size]; + + // init buffer to hold apkam symmetric key that is encrypted using at_server's default encryption public key (base64) + const size_t base64_encoded_rsa2048_ciphertext_size = atchops_base64_encoded_size(rsa_2048_ciphertext_size); + unsigned char *encrypted_apkam_symmetric_key_base64[base64_encoded_rsa2048_ciphertext_size]; + + // init buffers for IV's that will be used to decrypt keys received from server + unsigned char enc_privkey_iv[ATCHOPS_IV_BUFFER_SIZE]; + unsigned char self_enc_key_iv[ATCHOPS_IV_BUFFER_SIZE]; + + memset(apkam_symmetric_key_bytes, 0, aes256_key_unsigned_char_bytes_size); + memset(apkam_symmetric_key_base64, 0, aes256_key_unsigned_char_base64_size); + memset(encrypted_apkam_symmetric_key_bytes, 0, sizeof(unsigned char) * rsa_2048_ciphertext_size); + memset(encrypted_apkam_symmetric_key_base64, 0, sizeof(unsigned char) * base64_encoded_rsa2048_ciphertext_size); + memset(enc_privkey_iv, 0, sizeof(unsigned char) * ATCHOPS_IV_BUFFER_SIZE); + memset(self_enc_key_iv, 0, sizeof(unsigned char) * ATCHOPS_IV_BUFFER_SIZE); + + /* + * 1. Parse + validate command-line arguments + */ + if ((ret = atactivate_parse_args(argc, argv, &atsign_temp, NULL, &otp, &atkeys_fp, &app_name, &device_name, + &namespaces_str, &root_host, &root_port)) != 0) { + goto exit; + } + + // 1.1 Validate arguments + if ((ret = atauth_validate_args(otp, app_name, device_name, namespaces_str)) != 0) { + goto exit; + } + + // 1.2 Ensure atsign starts with '@' + char *atsign = NULL; + if ((ret = atclient_string_utils_atsign_with_at(atsign_temp, &atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_string_utils_atsign_with_at: %d\n", ret); + goto exit; + } + free(atsign_temp); // no longer needed + + // 1.3 if atkeys filepath was not passed through args, build default atkeys file path + if (atkeys_fp == NULL) { + if ((ret = atauth_build_atkeys_file_path(&atkeys_fp, atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not build atkeys filepath\n"); + ret = -1; + goto args_exit; + } + } + + /* + * 2. Generate APKAM keypair + APKAM Symmetric key + */ + atclient_atkeys atkeys; + atclient_atkeys_init(&atkeys); + + // 2.1 Generate APKAM Keypair - RSA2048 + unsigned char *pkam_public_key_base64 = NULL, *pkam_private_key_base64 = NULL; + if ((ret = atchops_rsa_key_generate_base64(&pkam_public_key_base64, &pkam_private_key_base64)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed APKAM Keypair Generation\n"); + goto atkeys_fp_exit; + } + // 2.1.1 set base64 pkam public and private key in the atkeys struct + atclient_atkeys_set_pkam_public_key_base64(&atkeys, (const char *)pkam_public_key_base64, + strlen((const char *)pkam_public_key_base64)); + atclient_atkeys_set_pkam_private_key_base64(&atkeys, (const char *)pkam_private_key_base64, + strlen((const char *)pkam_private_key_base64)); + + // 2.1.2 populate the pkam public/private key bytes in the atkeys struct by parsing the base64 encoded keys + atclient_atkeys_populate_pkam_public_key(&atkeys, (const char *)pkam_public_key_base64, + strlen((const char *)pkam_public_key_base64)); + atclient_atkeys_populate_pkam_private_key(&atkeys, (const char *)pkam_private_key_base64, + strlen((const char *)pkam_private_key_base64)); + + // 2.2 Init atclient + atclient_authenticate_options opts; + atclient_authenticate_options_init(&opts); + atclient_authenticate_options_set_atdirectory_host(&opts, root_host); + atclient_authenticate_options_set_atdirectory_port(&opts, root_port); + + atclient at_client; + atclient_init(&at_client); + + // 2.2.1 Start new connection + if ((ret = create_new_atserver_connection(&at_client, atsign, &opts)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "create_new_atserver_connection: %d\n", ret); + goto pkam_pub_keys_exit; + } + + // 2.3 Fetch the default encryption public key from server + atclient_atkey enc_pub_key; + atclient_atkey_init(&enc_pub_key); + + // 2.3.1 Construct the encryption public atkey + char *enc_pubkey_base64 = NULL; + if ((ret = atclient_atkey_create_public_key(&enc_pub_key, "publickey", atsign, NULL)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed create enc pub atkey | atclient_atkey_create_public_key: %d\n", ret); + goto pkam_pub_keys_exit; + } + + // 2.3.2 Fetch the key from server + atclient_get_public_key_request_options pubkey_opts; + atclient_get_public_key_request_options_init(&pubkey_opts); + if ((ret = atclient_get_public_key(&at_client, &enc_pub_key, &enc_pubkey_base64, &pubkey_opts)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed fetching def enc pubkey | atclient_get_public_key: %d\n", + ret); + goto enc_pub_key_exit; + } + atclient_atkeys_set_encrypt_public_key_base64(&atkeys, enc_pubkey_base64, strlen(enc_pubkey_base64)); + + // 2.3.3 Parse base64 encoded Default Encryption PubKey into an atchops_rsa_key_public_key struct + atchops_rsa_key_public_key encrypt_public_key; + atchops_rsa_key_public_key_init(&encrypt_public_key); + if ((ret = atchops_rsa_key_populate_public_key(&encrypt_public_key, enc_pubkey_base64, strlen(enc_pubkey_base64))) != + 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed parsing encryption_public_key | atchops_rsa_key_populate_public_key: %d\n", ret); + goto enc_pub_key_exit; + } + + // 2.4 Generate APKAM Symmetric Key - AES256 + if ((ret = atchops_aes_generate_key(apkam_symmetric_key_bytes, ATCHOPS_AES_256)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed APKAM SymmetricKey Generation\n"); + goto enc_pub_key_exit; + } + + // 2.4.1 base64 encoding the APKAM symmetric key + populate the same into atkeys struct + size_t apkam_symmetric_key_base64_len = 0; + if ((ret = atchops_base64_encode(apkam_symmetric_key_bytes, aes256_key_unsigned_char_bytes_size, + apkam_symmetric_key_base64, aes256_key_unsigned_char_base64_size, + &apkam_symmetric_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed encoding APKAM SymmetricKey to base64\n"); + goto enc_pub_key_exit; + } + atclient_atkeys_set_apkam_symmetric_key_base64(&atkeys, (const char *)apkam_symmetric_key_base64, + apkam_symmetric_key_base64_len); + + // 2.5 Encrypt APKAM Symmetric Key using Default Encryption PublicKey + if ((ret = atchops_rsa_encrypt(&encrypt_public_key, apkam_symmetric_key_base64, apkam_symmetric_key_base64_len, + encrypted_apkam_symmetric_key_bytes)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed RSA2048 encrypting apkam symmetric key | atchops_rsa_encrypt: %d\n", ret); + goto enc_pub_key_exit; + } + + // 2.5.1 base64 encode the encrypted APKAM symmetric key + size_t encrypted_apkam_symmetric_key_base64_len = 0; + if ((ret = atchops_base64_encode((unsigned char *)encrypted_apkam_symmetric_key_bytes, + sizeof(unsigned char) * rsa_2048_ciphertext_size, + (unsigned char *)encrypted_apkam_symmetric_key_base64, + sizeof(unsigned char) * base64_encoded_rsa2048_ciphertext_size, + &encrypted_apkam_symmetric_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed base64 encoding encrypted_apkam_symmetric_key | atchops_base64_encode: %d\n", ret); + goto enc_pub_key_exit; + } + + /* + * 3. Construct enroll params + send enrollment requset + */ + // 3.1 Initialize and populate enrollment params structs + atcommons_enroll_namespace_list_t *ns_list = malloc(sizeof(atcommons_enroll_namespace_list_t)); + if((ret = atcommmons_init_enroll_namespace_list(ns_list)) != 0) { + goto enc_pub_key_exit; + } + + // 3.1.1 parse namespace list string passed through command-line args + if ((ret = atcommons_enroll_namespace_list_from_string(&ns_list, namespaces_str)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not parse namespace string\n"); + goto ns_list_exit; + } + + // 3.1.2 init enroll params struct and populate + atcommons_enroll_params_t ep; + atcommons_enroll_params_init(&ep); + ep.app_name = app_name; + ep.device_name = device_name; + ep.otp = otp; + ep.ns_list = ns_list; + ep.apkam_public_key = (unsigned char *)atkeys.pkam_public_key_base64; + ep.encrypted_apkam_symmetric_key = (unsigned char *)encrypted_apkam_symmetric_key_base64; + + // 3.2 Send enrollment request + if ((ret = atauth_send_enroll_request(&at_client, &ep, enrollment_id, status)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atauth_send_enroll_request: %d\n", ret); + goto exit; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Enrollment Response: enrollment_id: %s\tstatus: %s\n", enrollment_id, + status); + atclient_atkeys_set_enrollment_id(&atkeys, enrollment_id, strlen(enrollment_id)); + + // 3.2 Retry APKAM auth until success + if ((ret = retry_pkam_auth_until_success(&at_client, atsign, &atkeys, &opts)) != 0) { + goto ns_list_exit; + } + + /* + * 4. Fetch APKAM keys from server using get:keys verb and decrypt them (keys are encrypted with APKAM SymmetricKey) + */ + char *encrypted_default_encryption_private_key = NULL; + char *encrypted_default_self_encryption_key = NULL; + + // 4.1.1 Fetch encrypted default encryption private key + if ((ret = get_apkam_key(&encrypted_default_encryption_private_key, ATAUTH_ENCRYPTED_DEFAULT_ENC_PRIVKEY_NAME, + &at_client.atserver_connection, enrollment_id, atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed fetching def_encryption_privkey | get_apkam_key: %d\n", + ret); + ret = 1; + goto encrypted_enc_privkey_exit; + } + + // 4.1.2 Fetch encrypted self encryption key + if ((ret = get_apkam_key(&encrypted_default_self_encryption_key, ATAUTH_ENCRYPTED_SELF_ENC_KEY_NAME, + &at_client.atserver_connection, enrollment_id, atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed fetching def_encryption_privkey | get_apkam_key: %d\n", + ret); + ret = 1; + goto encrypted_enc_privkey_exit; + } + + // 4.2 Decrypt the default encryption private key using apkam symmetric key + // 4.2.1 base64 decode the encrypted DefaultEncryptionPrivateKey + const size_t encrypted_default_encryption_private_key_len = strlen(encrypted_default_encryption_private_key); + size_t encrypted_default_enc_privkey_base64_decoded_size = + atchops_base64_decoded_size(encrypted_default_encryption_private_key_len); + size_t encrypted_default_enc_privkey_base64_decoded_len = 0; + unsigned char *encrypted_default_enc_privkey_base64_decoded = + malloc(sizeof(unsigned char) * encrypted_default_enc_privkey_base64_decoded_size); + if (encrypted_default_enc_privkey_base64_decoded == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Unable to allocate memory for encrypted_default_enc_privkey_base64_decoded\n"); + goto exit; + } + memset(encrypted_default_enc_privkey_base64_decoded, 0, + sizeof(unsigned char) * encrypted_default_enc_privkey_base64_decoded_size); + + if ((ret = atchops_base64_decode((unsigned char *)encrypted_default_encryption_private_key, + encrypted_default_encryption_private_key_len, + encrypted_default_enc_privkey_base64_decoded, + sizeof(unsigned char) * encrypted_default_enc_privkey_base64_decoded_size, + &encrypted_default_enc_privkey_base64_decoded_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed base64 decoding encrypted_default_enc_privkey | atchops_base64_decode: %d\n", ret); + goto encrypted_enc_privkey_base64_decoded_exit; + } + + // 4.2.2 decrypt the default encryption private key using APKAM symmetric key + size_t decypted_def_enc_privkey_size = + atchops_aes_ctr_plaintext_size(encrypted_default_enc_privkey_base64_decoded_len); + unsigned char *decrypted_def_enc_privkey_bytes = malloc(sizeof(unsigned char) * decypted_def_enc_privkey_size); + if (decrypted_def_enc_privkey_bytes == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unable to allocate memory for decrypted_def_enc_privkey\n"); + goto exit; + } + memset(decrypted_def_enc_privkey_bytes, 0, sizeof(unsigned char) * decypted_def_enc_privkey_size); + size_t decrypted_def_enc_privkey_len = 0; + + if ((ret = atchops_aes_ctr_decrypt( + apkam_symmetric_key_bytes, ATCHOPS_AES_256, enc_privkey_iv, encrypted_default_enc_privkey_base64_decoded, + encrypted_default_enc_privkey_base64_decoded_len, decrypted_def_enc_privkey_bytes, + sizeof(unsigned char) * decypted_def_enc_privkey_size, &decrypted_def_enc_privkey_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed decrypting the def_enc_privkey | atchops_aes_ctr_decrypt: %d\n", ret); + goto decrypted_self_enc_key_bytes_exit; + } + + // 4.2.3 Base64 encode the decrypted default encryption private key + size_t def_enc_privkey_base64_size = atchops_base64_encoded_size(decrypted_def_enc_privkey_len); + size_t def_enc_privkey_base64_len = 0; + unsigned char *def_encryption_privkey_base64 = malloc(sizeof(char) * def_enc_privkey_base64_size); + if (def_encryption_privkey_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unable to allocate memory for def_encryption_privkey_base64\n"); + goto exit; + } + memset(def_encryption_privkey_base64, 0, sizeof(unsigned char) * def_enc_privkey_base64_size); + + if ((ret = atchops_base64_encode(decrypted_def_enc_privkey_bytes, decrypted_def_enc_privkey_len, + def_encryption_privkey_base64, def_enc_privkey_base64_size, + &def_enc_privkey_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed base64 encoding the default enc privkey | atchops_base64_encode: %d\n", ret); + goto decypted_def_enc_privkey_base64_exit; + } + // set the decrypted and base64 encoded EncryptionPrivateKey into the atkeys struct + atclient_atkeys_set_encrypt_private_key_base64(&atkeys, (const char *)def_encryption_privkey_base64, + def_enc_privkey_base64_len); + + // 4.3 Decrypt the default self encryption key + // 4.3.1 base64 decode the default self encryption key + size_t encrypted_default_self_enc_key_len = strlen(encrypted_default_self_encryption_key); + size_t encrypted_default_self_enc_key_base64_decoded_size = + atchops_base64_decoded_size(encrypted_default_self_enc_key_len); + size_t encrypted_self_enc_key_base64_decoded_len = 0; + unsigned char *encrypted_self_enc_key_base64_decoded = + malloc(sizeof(unsigned char) * encrypted_default_self_enc_key_base64_decoded_size); + if (encrypted_self_enc_key_base64_decoded == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Unable to allocate memory for encrypted_self_enc_key_base64_decoded\n"); + goto exit; + } + memset(encrypted_self_enc_key_base64_decoded, 0, + sizeof(unsigned char) * encrypted_default_self_enc_key_base64_decoded_size); + + if ((ret = atchops_base64_decode((unsigned char *)encrypted_default_self_encryption_key, + encrypted_default_self_enc_key_len, encrypted_self_enc_key_base64_decoded, + sizeof(unsigned char) * encrypted_default_self_enc_key_base64_decoded_size, + &encrypted_self_enc_key_base64_decoded_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed base64 decoding the encrypted_self_enc_key | atchops_base64_decode: %d\n", ret); + goto self_enc_key_base64_decoded_exit; + } + + // 4.3.2 Decrypt the default self encryption key using APKAM symmetric key + size_t decrypted_self_enc_key_size = atchops_aes_ctr_plaintext_size(encrypted_self_enc_key_base64_decoded_len); + unsigned char *decrypted_self_enc_key_bytes = malloc(sizeof(unsigned char) * decrypted_self_enc_key_size); + if (decrypted_self_enc_key_bytes == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unable to allocate memory for decrypted_self_enc_key\n"); + goto exit; + } + memset(decrypted_self_enc_key_bytes, 0, sizeof(unsigned char) * decrypted_self_enc_key_size); + size_t decrypted_self_enc_key_len = 0; + + if ((ret = atchops_aes_ctr_decrypt(apkam_symmetric_key_bytes, ATCHOPS_AES_256, self_enc_key_iv, + encrypted_self_enc_key_base64_decoded, encrypted_self_enc_key_base64_decoded_len, + decrypted_self_enc_key_bytes, sizeof(unsigned char) * decrypted_self_enc_key_size, + &decrypted_self_enc_key_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed decrypting the self_enc_key | atchops_aes_ctr_decrypt: %d\n", ret); + goto decrypted_self_enc_key_exit; + } + // set the decrypted self encryption key in the atkeys struct + // Note: base64 encoding the key is not required as the key is base64 encoded on the server side before encryption + atclient_atkeys_set_self_encryption_key_base64(&atkeys, (const char *)decrypted_self_enc_key_bytes, + decrypted_self_enc_key_len); + + /* + * 5. Write the keys to an atkeys file + */ + if ((ret = atclient_atkeys_write_to_path(&atkeys, atkeys_fp)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_atkeys_write_to_path: %d\n", ret); + ret = 1; + goto ns_list_exit; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Success !!!\t Your atKeys file has been generated at \'%s\'\n", + atkeys_fp); + + // exits +decrypted_self_enc_key_exit: { free(decrypted_self_enc_key_bytes); } +self_enc_key_base64_decoded_exit: { free(encrypted_self_enc_key_base64_decoded); } +decypted_def_enc_privkey_base64_exit: { free(def_encryption_privkey_base64); } +decrypted_self_enc_key_bytes_exit: { free(decrypted_def_enc_privkey_bytes); } +encrypted_enc_privkey_base64_decoded_exit: { free(encrypted_default_enc_privkey_base64_decoded); } +encrypted_self_enc_key_exit: { free(encrypted_default_self_encryption_key); } +encrypted_enc_privkey_exit: { free(encrypted_default_encryption_private_key); } +ns_list_exit: { free(ns_list); } +enc_pub_key_exit: { free(enc_pubkey_base64); } +pkam_pub_keys_exit: { + free(pkam_public_key_base64); + free(pkam_private_key_base64); +} +atkeys_fp_exit: { free(atkeys_fp); } +args_exit: { + free(atsign); + free(root_host); + free(app_name); + free(device_name); + free(otp); + free(namespaces_str); +} +exit: { + if (ret != 0) + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Aborting with exit code: %d\n", ret); + + exit(ret); +} +} + +// retries APKAM auth using the set of atkeys provided until the authentication succeeds +// sleeps `ATAUTH_DEFAULT_APKAM_RETRY_INTERVAL` seconds after each attempt +int retry_pkam_auth_until_success(atclient *ctx, const char *atsign, const atclient_atkeys *atkeys, + const atclient_authenticate_options *opts) { + int ret = 1; + char *err_msg; + + while (true) { + ret = atclient_pkam_authenticate(ctx, atsign, atkeys, (atclient_authenticate_options *)opts, &err_msg); + + if (ret == 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "enrollment approved | APKAM auth success\n"); + return ret; + } + + if (err_msg != NULL && is_enrollment_denied(err_msg)) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "enrollment_id: %s is denied\n", atkeys->enrollment_id); + ret = 1; + return ret; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "APKAM auth failed. Retrying in %d secs\n", + ATAUTH_DEFAULT_APKAM_RETRY_INTERVAL); + sleep(ATAUTH_DEFAULT_APKAM_RETRY_INTERVAL); + } +} + +/** Fetches APKAM specific keys from server which has been encrypted using the current enrollment's APKAM SymmetricKey + * + * Note: It is assumed that the atclient instance has a valid authenticated connection + */ +int get_apkam_key(char **key, const char *key_name, atclient_connection *ctx, const char *enrollment_id, + const char *atsign) { + int ret = 0; + // Calculate command length + const size_t cmd_size = + snprintf(NULL, 0, "keys:get:keyName:%s.%s.__manage%s\r\n", enrollment_id, key_name, atsign) + 1; + char command[cmd_size]; + + // Construct command + snprintf(command, cmd_size, "keys:get:keyName:%s.%s.__manage%s\r\n", enrollment_id, key_name, atsign); + const size_t recv_size = 2400; + unsigned char recv[recv_size]; + memset(recv, 0, sizeof(char) * recv_size); + size_t recv_len = 0; + if ((ret = atclient_connection_send(ctx, (unsigned char *)command, strlen(command), recv, recv_size, &recv_len)) != + 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret); + return ret; + } + + // Parse response + char *response_trimmed = NULL; + // below method points the response_trimmed variable to the position of 'data:' substring + if (atclient_string_utils_get_substring_position((char *)recv, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", + (int)recv_len, recv); + return ret; + } + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); + + // Parse response json + cJSON *json_server_resp = cJSON_Parse(response_trimmed); + if (json_server_resp == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Error parsing server response JSON\n"); + ret = 1; + return ret; + } + // extract the key from the json + cJSON *key_json = cJSON_GetObjectItemCaseSensitive(json_server_resp, "value"); + if (cJSON_IsString(key_json) && key_json->valuestring != NULL) { + *key = strdup(key_json->valuestring); + } + +exit: { + cJSON_Delete(json_server_resp); + return ret; +} +} + +// returns 1 if the error_message contains the ENROLLMENT_DENIED error code, otherwise 0 +int is_enrollment_denied(const char *err_msg) { + return strncmp(err_msg, ATAUTH_ENROLLMENT_DENIED_ERR_CODE, strlen(ATAUTH_ENROLLMENT_DENIED_ERR_CODE)) == 0 ? 1 : 0; +} + +int create_new_atserver_connection(atclient *ctx, const char *atsign, const atclient_authenticate_options *options) { + char *atserver_host = NULL; + int atserver_port = 0, ret = 0; + + if (atserver_host == NULL || atserver_port == 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Fetching secondary server address for atsign: %s\n", atsign); + if ((ret = atclient_utils_find_atserver_address(options->atdirectory_host, options->atdirectory_port, atsign, + &atserver_host, &atserver_port)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "atclient_utils_find_atserver_address: %d\n", ret); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Could not fetch secondary address for atsign: %s on root directory: %s:%d\n", atsign, + options->atdirectory_host, options->atdirectory_port); + goto exit; + } + } + + if ((ret = atclient_start_atserver_connection(ctx, atserver_host, atserver_port)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "atclient_start_atserver_connection: %d\n", ret); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not connect to secondary server at %s:%d\n", atserver_host, + atserver_port); + } + +exit: { return ret; } +} + +int atauth_validate_args(const char *otp, const char *app_name, const char *device_name, const char *namespaces_str) { + int ret = 0; + if (otp == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "otp cannot be NULL\n"); + goto exit; + } + + if (app_name == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "app_name cannot be NULL\n"); + goto exit; + } + + if (device_name == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "device_name cannot be NULL\n"); + goto exit; + } + + if (namespaces_str == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "namespaces_str cannot be NULL\n"); + } + +exit: { return ret; } +} diff --git a/packages/atauth/src/send_enroll_request.c b/packages/atauth/src/send_enroll_request.c index d3fb5951..164c0e19 100644 --- a/packages/atauth/src/send_enroll_request.c +++ b/packages/atauth/src/send_enroll_request.c @@ -13,16 +13,18 @@ #define TAG "send_enroll_request" -int atauth_send_enroll_request(atclient *client, const atcommons_enroll_params_t *ep, char *enroll_id, char *enroll_status) { +int atauth_validate_send_enroll_request_arguments(const atclient *client, const atcommons_enroll_params_t *ep, + const char *enroll_id, const char *enroll_status); + +int atauth_send_enroll_request(atclient *client, const atcommons_enroll_params_t *ep, char *enroll_id, + char *enroll_status) { int ret = 0; - const size_t recv_size = 100; // to hold the response for enroll request + const size_t recv_size = 300; // to hold the response for enroll request unsigned char recv[recv_size]; char *recv_trimmed = NULL; size_t recv_len; - if (enroll_id == NULL) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "enroll_id is unallocated\n"); - ret = -1; + if ((ret = atauth_validate_send_enroll_request_arguments(client, ep, enroll_id, enroll_status)) != 0) { goto exit; } @@ -103,7 +105,7 @@ int atauth_send_enroll_request(atclient *client, const atcommons_enroll_params_t } strncpy(enroll_status, enroll_status_cjson->valuestring, strlen(enroll_status_cjson->valuestring)); enroll_status[strlen(enroll_status_cjson->valuestring)] = '\0'; - + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Enrollment request sent successfully\n"); ret = 0; cjson_delete_exit: @@ -113,3 +115,31 @@ int atauth_send_enroll_request(atclient *client, const atcommons_enroll_params_t exit: return ret; } + +int atauth_validate_send_enroll_request_arguments(const atclient *client, const atcommons_enroll_params_t *ep, + const char *enroll_id, const char *enroll_status) { + int ret = 0; + + if (client == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient is null\n"); + ret = -1; + return ret; + } + if (ep == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "ep(enroll_params) is null\n"); + ret = -1; + return ret; + } + if (enroll_id == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "enroll_id is unallocated\n"); + ret = -1; + return ret; + } + if (enroll_status == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "enroll_status is unallocated\n"); + ret = -1; + return ret; + } + + return ret; +} diff --git a/packages/atclient/include/atclient/atclient.h b/packages/atclient/include/atclient/atclient.h index 81440979..6ba6acd0 100644 --- a/packages/atclient/include/atclient/atclient.h +++ b/packages/atclient/include/atclient/atclient.h @@ -122,10 +122,12 @@ void atclient_stop_atserver_connection(atclient *ctx); * @param atkeys populated atkeys, especially with the pkam private key * @param atsign the atsign the atkeys belong to, this string is assumed to be null terminated * @param options pointer to an initialized atclient_authenticate_options struct that stored auth params + * @param err_msg pointer a char buffer that will hold the error response from server. This can be NULL if not needed. + * Need not be allocated; caller should free this after use * @return int 0 on success, non-zero on error */ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient_atkeys *atkeys, - atclient_authenticate_options *options); + atclient_authenticate_options *options, char **err_msg); /** * @brief authenticate with secondary server with AES CRAM key. This is supposed to be a one-time auth, to activate the diff --git a/packages/atclient/include/atclient/constants.h b/packages/atclient/include/atclient/constants.h index 7b7e5a82..ada5a654 100755 --- a/packages/atclient/include/atclient/constants.h +++ b/packages/atclient/include/atclient/constants.h @@ -20,10 +20,6 @@ extern "C" { #define ATCLIENT_ERR_AT0015_KEY_NOT_FOUND -0x1980 -// default param values for ATCLIENT PKAM AUTHENTICATE OPTIONS -#define ATCLIENT_DEFAULT_AT_DIRECTORY_HOST "root.atsign.org" -#define ATCLIENT_DEFAULT_AT_DIRECTORY_PORT 64 - #define ATCLIENT_DATA_TOKEN "data:" #define ATCLIENT_CRAM_PREFIX "cram" diff --git a/packages/atclient/include/atclient/request_options.h b/packages/atclient/include/atclient/request_options.h index 69741cda..9a968941 100644 --- a/packages/atclient/include/atclient/request_options.h +++ b/packages/atclient/include/atclient/request_options.h @@ -52,6 +52,9 @@ extern "C" { #define ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INDEX 0 #define ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INITIALIZED (VALUE_INITIALIZED << 0) +#define ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INDEX 0 +#define ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INITIALIZED (VALUE_INITIALIZED << 0) + /* * 1A. Put SelfKey */ @@ -125,7 +128,7 @@ typedef struct atclient_get_atkeys_request_options { } atclient_get_atkeys_request_options; /* - * 5. Pkam auhtenticate Request Options + * 5. Pkam authenticate Request Options */ typedef struct atclient_authenticate_options { char *atdirectory_host; diff --git a/packages/atclient/src/atclient.c b/packages/atclient/src/atclient.c index 1f91ff77..7b19ed95 100755 --- a/packages/atclient/src/atclient.c +++ b/packages/atclient/src/atclient.c @@ -189,7 +189,7 @@ bool atclient_is_atsign_initialized(const atclient *ctx) { } int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient_atkeys *atkeys, - atclient_authenticate_options *options) { + atclient_authenticate_options *options, char **err_msg) { int ret = 1; // error by default @@ -328,8 +328,8 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient char *str_with_data_prefix = NULL; if (atclient_string_utils_get_substring_position((char *)recv, ATCLIENT_DATA_TOKEN, &str_with_data_prefix) != 0) { ret = 1; - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", - (int)recv_len, recv); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv: \"%.*s\" \n", (int)recv_len, recv); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "recv did not have prefix \"data:\"\n"); goto exit; } @@ -391,6 +391,10 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:success\"\n", (int)recv_len, recv); + + if (*err_msg != NULL) { + *err_msg = (char *)recv; + } goto exit; } @@ -742,7 +746,7 @@ static int atclient_pkam_authenticate_validate_arguments(const atclient *ctx, co goto exit; } - if (NULL == atsign || strlen(atsign) == 0) { + if (atsign == NULL || strlen(atsign) == 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atsign is NULL or the length is 0\n"); goto exit; } diff --git a/packages/atclient/src/atclient_get_public_key.c b/packages/atclient/src/atclient_get_public_key.c index 887ce8d5..a87be362 100755 --- a/packages/atclient/src/atclient_get_public_key.c +++ b/packages/atclient/src/atclient_get_public_key.c @@ -35,7 +35,7 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va size_t recv_len = 0; cJSON *root = NULL; - char *plookup_cmd = NULL; + char *lookup_cmd = NULL; char *metadata_str = NULL; /* @@ -48,6 +48,7 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va char *atkey_str_without_public = NULL; char *ptr = strstr(atkey_str, "public:"); + if (ptr != NULL) { atkey_str_without_public = ptr + strlen("public:"); } else { @@ -56,27 +57,31 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va goto exit; } - const bool bypass_cache = request_options != NULL && - atclient_get_public_key_request_options_is_bypass_cache_initialized(request_options) && + const bool bypass_cache = atclient_get_public_key_request_options_is_bypass_cache_initialized(request_options) && request_options->bypass_cache; + // use plookup verb if atclient instance is authenticated (or) lookup verb otherwise + // if the atsign var is set in the atclient instance, that is considered authenticated + const bool authenticated_lookup = atclient->atsign == NULL ? false : true; + char *verb = authenticated_lookup ? "plookup" : "lookup"; + + const size_t lookup_cmd_size = strlen(verb) + strlen(":all:\r\n") + (bypass_cache ? strlen("bypassCache:true:") : 0) + + strlen(atkey_str_without_public) + 1; - const size_t plookup_cmd_size = strlen("plookup:all:\r\n") + (bypass_cache ? strlen("bypassCache:true:") : 0) + - strlen(atkey_str_without_public) + 1; - if ((plookup_cmd = malloc(sizeof(char) * plookup_cmd_size)) == NULL) { + if ((lookup_cmd = malloc(sizeof(char) * lookup_cmd_size)) == NULL) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for plookup_cmd\n"); goto exit; } - memset(plookup_cmd, 0, plookup_cmd_size); - snprintf(plookup_cmd, plookup_cmd_size, "plookup:%sall:%s\r\n", bypass_cache ? "bypassCache:true:" : "", + memset(lookup_cmd, 0, lookup_cmd_size); + snprintf(lookup_cmd, lookup_cmd_size, "%s:%sall:%s\r\n", verb, bypass_cache ? "bypassCache:true:" : "", atkey_str_without_public); - const size_t cmdbufferlen = strlen(plookup_cmd); + const size_t cmdbufferlen = strlen(lookup_cmd); /* * 4. Send `plookup:` command */ - if ((ret = atclient_connection_send(&(atclient->atserver_connection), (unsigned char *)plookup_cmd, cmdbufferlen, - recv, recv_size, &recv_len)) != 0) { + if ((ret = atclient_connection_send(&(atclient->atserver_connection), (unsigned char *)lookup_cmd, cmdbufferlen, recv, + recv_size, &recv_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret); goto exit; } @@ -84,10 +89,9 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va /* * 5. Parse response */ - char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if (atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { + if (atclient_string_utils_get_substring_position((char *)recv, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); @@ -126,7 +130,7 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va metadata_str = cJSON_Print(metadata); - if ((ret = atclient_atkey_metadata_from_json_str(&(atkey->metadata), metadata_str)) != 0) { + if ((ret = atclient_atkey_metadata_from_json_str(&atkey->metadata, metadata_str)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_atkey_metadata_from_json_str: %d\n", ret); goto exit; } @@ -143,13 +147,12 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va } ret = 0; - goto exit; exit: { if (root != NULL) { cJSON_Delete(root); } free(metadata_str); - free(plookup_cmd); + free(lookup_cmd); free(atkey_str); return ret; } @@ -171,12 +174,6 @@ static int atclient_get_public_key_validate_arguments(const atclient *atclient, goto exit; } - if (!atclient_is_atsign_initialized(atclient)) { - ret = 1; - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atsign not initialized\n"); - goto exit; - } - if (atkey == NULL) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey is NULL\n"); diff --git a/packages/atclient/src/monitor.c b/packages/atclient/src/monitor.c index 9eadbae6..22af05d4 100644 --- a/packages/atclient/src/monitor.c +++ b/packages/atclient/src/monitor.c @@ -43,7 +43,7 @@ int atclient_monitor_pkam_authenticate(atclient *monitor_conn, const char *atsig atclient_authenticate_options *options) { int ret = 1; - if ((ret = atclient_pkam_authenticate(monitor_conn, atsign, atkeys, options)) != 0) { + if ((ret = atclient_pkam_authenticate(monitor_conn, atsign, atkeys, options, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate with PKAM\n"); goto exit; } diff --git a/packages/atclient/tests/test_atkeys_write.c b/packages/atclient/tests/test_atkeys_write.c index b2050631..22766fe7 100644 --- a/packages/atclient/tests/test_atkeys_write.c +++ b/packages/atclient/tests/test_atkeys_write.c @@ -181,7 +181,7 @@ int main(int argc, char *argv[]) { goto exit; } - if ((ret = atclient_pkam_authenticate(&atclient1, "@8incanteater", &atkeys1, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient1, "@8incanteater", &atkeys1, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "failed to pkam auth\n"); goto exit; } diff --git a/packages/atcommons/include/atcommons/enroll_namespace.h b/packages/atcommons/include/atcommons/enroll_namespace.h index 28e411f8..202afa3f 100644 --- a/packages/atcommons/include/atcommons/enroll_namespace.h +++ b/packages/atcommons/include/atcommons/enroll_namespace.h @@ -1,6 +1,7 @@ #ifndef ATCOMMONS_ENROLL_NAMESPACE_H #define ATCOMMONS_ENROLL_NAMESPACE_H +#include #include typedef struct { @@ -13,6 +14,14 @@ typedef struct { atcommons_enroll_namespace_t *namespaces[]; } atcommons_enroll_namespace_list_t; +/** + * @brief intializes the provided atcommons_enroll_namespace_list_t struc + * + * @param ns_list pointer to the namespace list struct that needs to be initialized + * @return int 0 on success, non-zero int on failure + */ +int atcommmons_init_enroll_namespace_list(atcommons_enroll_namespace_list_t *ns_list); + /** * @brief serializes enroll_namespace struct to JSON string * @@ -59,4 +68,13 @@ int atcommons_enroll_namespace_list_to_json(char **ns_list_string, size_t *ns_li int atcommons_enroll_namespace_list_append(atcommons_enroll_namespace_list_t **ns_list, atcommons_enroll_namespace_t *ns); +/** + * @brief Parses a namespace list string and populates these namespaces into the enroll_namespace_list_t struct provided + * + * @param ns_list Double pointer to a enroll_namespace_list_t struct which would hold the list of namespaces + * @param json_str The namespace list string that is to be parsed. (Expected format: "ns1:rw,ns2:r") + * @return int 0 on success, non-zero int on failure + */ +int atcommons_enroll_namespace_list_from_string(atcommons_enroll_namespace_list_t **ns_list, char *json_str); + #endif diff --git a/packages/atcommons/src/enroll_namespace.c b/packages/atcommons/src/enroll_namespace.c index 0a284aa0..43f67a55 100644 --- a/packages/atcommons/src/enroll_namespace.c +++ b/packages/atcommons/src/enroll_namespace.c @@ -5,19 +5,38 @@ #include #include #include - +#include #include #define TAG "enroll_namespace" +int atcommmons_init_enroll_namespace_list(atcommons_enroll_namespace_list_t *ns_list) { + if(ns_list == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Memory not allocated for namespace list struct\n"); + return -1; + } + + memset(ns_list, 0, sizeof(atcommons_enroll_namespace_list_t)); + + return 0; +} + int atcommons_enroll_namespace_list_append(atcommons_enroll_namespace_list_t **ns_list, atcommons_enroll_namespace_t *ns) { - // allocate enough memory for enroll_namespace_list struct, and the number of atcommons_enroll_namespace_t structs - // that are in the list - atcommons_enroll_namespace_list_t *temp = - realloc(*ns_list, sizeof(atcommons_enroll_namespace_list_t) + - sizeof(atcommons_enroll_namespace_t) * ((*ns_list)->length + 1)); + if (ns == NULL) { + atlogger_log(TAG, 0, "Namespace to append cannot be null\n"); + return -1; + } + // If the list's length is uninitialized (SIZE_MAX), set it to 0 + if ((*ns_list)->length == SIZE_MAX) { + (*ns_list)->length = 0; + } + + const size_t new_length = (*ns_list)->length + 1; + // Try reallocating memory for the array of enroll_namespace_t structs + atcommons_enroll_namespace_list_t *temp = realloc(*ns_list, sizeof(atcommons_enroll_namespace_list_t) + + sizeof(atcommons_enroll_namespace_t *) * new_length); if (temp == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unable to realloc memory for enroll namespace list\n"); return -1; @@ -83,7 +102,47 @@ int atcommons_enroll_namespace_list_to_json(char **ns_list_string, size_t *ns_li cJSON_Delete(json_obj); return 0; } - #else -#error "JSON provider not supported" + #error "JSON provider not supported" #endif + +int atcommons_enroll_namespace_list_from_string(atcommons_enroll_namespace_list_t **ns_list, char *json_str) { + int sep_count = 0; + const int ns_string_end = strlen(json_str); + int ret = 0; + + // Count seperator in the namespace list string. Replaces all occurences of ':' and ',' to '\0' + for (int i = 0; i < ns_string_end; i++) { + if (json_str[i] == ':') { + sep_count++; + json_str[i] = '\0'; + } + + if (json_str[i] == ',') { + json_str[i] = '\0'; + } + } + + int pos = 0; + + atcommons_enroll_namespace_t *ns_temp = NULL; + for (int i = 0; i < sep_count; i++) { + ns_temp = malloc(sizeof(atcommons_enroll_namespace_t)); + ns_temp->name = strdup(json_str + pos); + pos += strlen(json_str + pos) + 1; + if(json_str + pos == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Invalid namespace access value\n"); + ret = 1; + return ret; + } + ns_temp->access = strdup(json_str + pos); + + if ((ret = atcommons_enroll_namespace_list_append(ns_list, ns_temp)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed appending ns to ns_list | atcommons_enroll_namespace_list_append: %d", ret); + return ret; + } + pos += strlen(json_str + pos) + 1; + } + exit: { return ret; } +} \ No newline at end of file diff --git a/packages/atcommons/tests/at_expect.c b/packages/atcommons/tests/at_expect.c index 8d4b314b..0359cdfd 100644 --- a/packages/atcommons/tests/at_expect.c +++ b/packages/atcommons/tests/at_expect.c @@ -6,7 +6,8 @@ int atcommons_string_expect(char *actual, char *expected) { int ret = strcmp(actual, expected); if (ret != 0) { - printf("test failed\nexpected: %s\n*actual*: %s\n", expected, actual); + printf("test failed | ret: %d\nexpected: %s\n*actual*: %s\n", ret, expected, actual); + printf("expected_len: %lu \t actual_len: %lu", strlen(expected), strlen(actual)); } return ret; diff --git a/packages/atcommons/tests/test_enroll_command_builder.c b/packages/atcommons/tests/test_enroll_command_builder.c index df390cd9..443bc0ad 100644 --- a/packages/atcommons/tests/test_enroll_command_builder.c +++ b/packages/atcommons/tests/test_enroll_command_builder.c @@ -10,7 +10,7 @@ int main() { int ret = 1; char expected_string[] = "enroll:request:{\"appName\":\"test-app\",\"deviceName\":\"test-device\",\"otp\":\"XYZABC\"," - "\"namespaces\":{\"namespace1\":\"rw\",\"namespace2\":\"r\"}}"; + "\"namespaces\":{\"namespace1\":\"rw\",\"namespace2\":\"r\"}}\r\n"; atcommons_enroll_namespace_t namespace; namespace.name = "namespace1"; namespace.access = "rw"; diff --git a/packages/atcommons/tests/test_enroll_namespace_utils.c b/packages/atcommons/tests/test_enroll_namespace_utils.c index 860e83c1..e981870f 100644 --- a/packages/atcommons/tests/test_enroll_namespace_utils.c +++ b/packages/atcommons/tests/test_enroll_namespace_utils.c @@ -9,14 +9,23 @@ int test_enroll_namespace_to_json(); int test_enroll_namespace_list_to_json(); +int test_enroll_namespace_list_from_string(); int main() { int ret = test_enroll_namespace_to_json(); if (ret != 0) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "%s failed\n", "test_enroll_namespace_to_json"); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "%s failed\n", "test_enroll_namespace_to_json: %d", ret); return ret; } ret = test_enroll_namespace_list_to_json(); + if(ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "%s failed\n", "test_enroll_namespace_list_to_json: %d", ret); + return ret; + } + ret = test_enroll_namespace_list_from_string(); + if(ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "%s failed\n", "test_enroll_namespace_list_from_string: %d", ret); + } return ret; } @@ -82,5 +91,66 @@ int test_enroll_namespace_list_to_json() { ret = atcommons_string_expect(ns_list_json, en_expected_json); free(ns_list_json); + return ret; +} + +int test_enroll_namespace_list_from_string() { + char *nsl_str_1 = "ns1:rw,ns2:r"; + char *nsl_str_2 = "ns3:rw"; + char *nsl_invalid_str_1 = "ns4"; + char *nsl_invalid_str_2 = "ns5:"; + atcommons_enroll_namespace_list_t *nsl = malloc(sizeof(atcommons_enroll_namespace_list_t)); + + int ret = atcommons_enroll_namespace_list_from_string(&nsl, nsl_str_1); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_list_from_string(ns string 1): %d\n", ret); + return ret; + } + ret = atcommons_enroll_namespace_list_from_string(&nsl, nsl_str_2); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_list_from_string(ns string 2): %d\n", ret); + return ret; + } + ret = atcommons_enroll_namespace_list_from_string(&nsl, nsl_invalid_str_1); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_list_from_string(ns string 3): %d\n", ret); + return ret; + } + ret = atcommons_enroll_namespace_list_from_string(&nsl, nsl_invalid_str_2); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_list_from_string(ns string 4): %d\n", ret); + return ret; + } + + const size_t ns_name_len = 3; + const size_t ns_access_len = 2; + if(strncmp(nsl->namespaces[0]->name, "ns1", ns_name_len) || strncmp(nsl->namespaces[0]->access, "rw", ns_access_len)) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test_enroll_namespace_list_from_string case 1: failed\n"); + return ret; + } + if(strncmp(nsl->namespaces[1]->name, "ns2", ns_name_len) || strncmp(nsl->namespaces[1]->access, "r", ns_access_len - 1)) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test_enroll_namespace_list_from_string case 2: failed\n"); + return ret; + } + if(strncmp(nsl->namespaces[2]->name, "ns3", ns_name_len) || strncmp(nsl->namespaces[2]->access, "rw", ns_access_len)) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test_enroll_namespace_list_from_string case 3: failed\n"); + return ret; + } + + // following two test cases are negative. Them being NULL is expected behaviour + if(nsl->namespaces[3]->name != NULL || nsl->namespaces[3]->access != NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test_enroll_namespace_list_from_string case 4: failed\n"); + return ret; + } + if(nsl->namespaces[4]->name != NULL || nsl->namespaces[4]->access != NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test_enroll_namespace_list_from_string case 5: failed\n"); + return ret; + } + return ret; } \ No newline at end of file diff --git a/tests/functional_tests/lib/src/helpers.c b/tests/functional_tests/lib/src/helpers.c index c9f7c14c..ffc3c719 100644 --- a/tests/functional_tests/lib/src/helpers.c +++ b/tests/functional_tests/lib/src/helpers.c @@ -41,7 +41,7 @@ int functional_tests_pkam_auth(atclient *atclient, atclient_atkeys *atkeys, cons atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "functional_tests_pkam_auth Begin\n"); - if ((ret = atclient_pkam_authenticate(atclient, atsign, atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(atclient, atsign, atkeys, NULL, NULL)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_pkam_authenticate: %d\n", ret); goto exit; } diff --git a/tests/functional_tests/tests/test_atclient_pkam_authenticate.c b/tests/functional_tests/tests/test_atclient_pkam_authenticate.c index 8d4776fd..fec0c940 100644 --- a/tests/functional_tests/tests/test_atclient_pkam_authenticate.c +++ b/tests/functional_tests/tests/test_atclient_pkam_authenticate.c @@ -65,7 +65,7 @@ static int test1_pkam_no_options() { } atlogger_log(tag, ATLOGGER_LOGGING_LEVEL_INFO, "atclient_atkeys_populate_from_atkeys_file: %d\n", ret); - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, NULL, NULL)) != 0) { atlogger_log(tag, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); return ret; } else { @@ -108,7 +108,7 @@ static int test2_pkam_with_options() { return ret; } - if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, NULL)) != 0) { + if ((ret = atclient_pkam_authenticate(&atclient, atsign, &atkeys, NULL, NULL)) != 0) { atlogger_log(tag, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); return ret; } else {