static PyObject * set_spa_hmac_type(PyObject *self, PyObject *args) { fko_ctx_t ctx; short hmac_type; int res; if(!PyArg_ParseTuple(args, "kh", &ctx, &hmac_type)) return NULL; res = fko_set_spa_hmac_type(ctx, hmac_type); if(res != FKO_SUCCESS) { PyErr_SetString(FKOError, fko_errstr(res)); return NULL; } return Py_BuildValue("", NULL); }
static void spa_default_ctx(fko_ctx_t *ctx) { fko_new(ctx); fko_set_rand_value(*ctx, NULL); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_spa_message(*ctx, "123.123.123.123,tcp/22"); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_spa_message_type(*ctx, FKO_ACCESS_MSG); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_username(*ctx, "someuser"); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_spa_encryption_type(*ctx, FKO_ENCRYPTION_RIJNDAEL); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_spa_encryption_mode(*ctx, FKO_ENC_MODE_CBC); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_spa_digest_type(*ctx, FKO_DEFAULT_DIGEST); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); fko_set_spa_hmac_type(*ctx, FKO_HMAC_SHA256); fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16); // display_ctx(*ctx); spa_calls += 16; return; }
int fko_verify_hmac(fko_ctx_t ctx, const char * const hmac_key, const int hmac_key_len) { char *hmac_digest_from_data = NULL; char *tbuf = NULL; int res = FKO_SUCCESS; int hmac_b64_digest_len = 0, zero_free_rv = FKO_SUCCESS; /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if (! is_valid_encoded_msg_len(ctx->encrypted_msg_len)) return(FKO_ERROR_INVALID_DATA_HMAC_MSGLEN_VALIDFAIL); if(hmac_key_len > MAX_DIGEST_BLOCK_LEN) return(FKO_ERROR_INVALID_HMAC_KEY_LEN); if(ctx->hmac_type == FKO_HMAC_MD5) hmac_b64_digest_len = MD5_B64_LEN; else if(ctx->hmac_type == FKO_HMAC_SHA1) hmac_b64_digest_len = SHA1_B64_LEN; else if(ctx->hmac_type == FKO_HMAC_SHA256) hmac_b64_digest_len = SHA256_B64_LEN; else if(ctx->hmac_type == FKO_HMAC_SHA384) hmac_b64_digest_len = SHA384_B64_LEN; else if(ctx->hmac_type == FKO_HMAC_SHA512) hmac_b64_digest_len = SHA512_B64_LEN; else return(FKO_ERROR_UNSUPPORTED_HMAC_MODE); if((ctx->encrypted_msg_len - hmac_b64_digest_len) < MIN_SPA_ENCODED_MSG_SIZE) return(FKO_ERROR_INVALID_DATA_HMAC_ENCMSGLEN_VALIDFAIL); /* Get digest value */ hmac_digest_from_data = strndup((ctx->encrypted_msg + ctx->encrypted_msg_len - hmac_b64_digest_len), hmac_b64_digest_len); if(hmac_digest_from_data == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); /* Now we chop the HMAC digest off of the encrypted msg */ tbuf = strndup(ctx->encrypted_msg, ctx->encrypted_msg_len - hmac_b64_digest_len); if(tbuf == NULL) { if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data, MAX_SPA_ENCODED_MSG_SIZE)) == FKO_SUCCESS) return(FKO_ERROR_MEMORY_ALLOCATION); else return(FKO_ERROR_ZERO_OUT_DATA); } if(zero_free(ctx->encrypted_msg, ctx->encrypted_msg_len) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; ctx->encrypted_msg = tbuf; ctx->encrypted_msg_len -= hmac_b64_digest_len; if(ctx->encryption_mode == FKO_ENC_MODE_ASYMMETRIC) { /* See if we need to add the "hQ" string to the front of the * encrypted data. */ if(! ctx->added_gpg_prefix) { res = add_gpg_prefix(ctx); } } else { /* See if we need to add the "Salted__" string to the front of the * encrypted data. */ if(! ctx->added_salted_str) { res = add_salted_str(ctx); } } if (res != FKO_SUCCESS) { if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data, MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(zero_free_rv == FKO_SUCCESS) return(res); else return(zero_free_rv); } /* Calculate the HMAC from the encrypted data and then * compare */ res = fko_set_spa_hmac_type(ctx, ctx->hmac_type); if(res == FKO_SUCCESS) { res = fko_set_spa_hmac(ctx, hmac_key, hmac_key_len); if(res == FKO_SUCCESS) { if(constant_runtime_cmp(hmac_digest_from_data, ctx->msg_hmac, hmac_b64_digest_len) != 0) { res = FKO_ERROR_INVALID_DATA_HMAC_COMPAREFAIL; } } } if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data, MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS) zero_free_rv = FKO_ERROR_ZERO_OUT_DATA; if(res == FKO_SUCCESS) return(zero_free_rv); else return(res); }
/* Prompt for and receive a user password. */ static int get_keys(fko_ctx_t ctx, fko_cli_options_t *options, char *key, int *key_len, char *hmac_key, int *hmac_key_len) { #if !AFL_FUZZING char *key_tmp = NULL, *hmac_key_tmp = NULL; #endif int use_hmac = 0, res = 0; memset(key, 0x0, MAX_KEY_LEN+1); memset(hmac_key, 0x0, MAX_KEY_LEN+1); if(options->have_key) { strlcpy(key, options->key, MAX_KEY_LEN+1); *key_len = strlen(key); } else if(options->have_base64_key) { *key_len = fko_base64_decode(options->key_base64, (unsigned char *) options->key); if(*key_len > 0 && *key_len < MAX_KEY_LEN) { memcpy(key, options->key, *key_len); } else { log_msg(LOG_VERBOSITY_ERROR, "[*] Invalid key length: '%d', must be in [1,%d]", *key_len, MAX_KEY_LEN); return 0; } } else { /* If --get-key file was specified grab the key/password from it. */ if(options->get_key_file[0] != 0x0) { if(get_key_file(key, key_len, options->get_key_file, ctx, options) != 1) { return 0; } } else if(options->use_gpg) { if(options->use_gpg_agent) log_msg(LOG_VERBOSITY_NORMAL, "[+] GPG mode set, signing passphrase acquired via gpg-agent"); else if(options->gpg_no_signing_pw) log_msg(LOG_VERBOSITY_NORMAL, "[+] GPG mode set, signing passphrase not required"); else if(strlen(options->gpg_signer_key)) { #if AFL_FUZZING strlcpy(key, AFL_ENC_KEY, MAX_KEY_LEN+1); #else key_tmp = getpasswd("Enter passphrase for signing: ", options->input_fd); if(key_tmp == NULL) { log_msg(LOG_VERBOSITY_ERROR, "[*] getpasswd() key error."); return 0; } strlcpy(key, key_tmp, MAX_KEY_LEN+1); #endif *key_len = strlen(key); } } else { #if AFL_FUZZING strlcpy(key, AFL_ENC_KEY, MAX_KEY_LEN+1); #else key_tmp = getpasswd("Enter encryption key: ", options->input_fd); if(key_tmp == NULL) { log_msg(LOG_VERBOSITY_ERROR, "[*] getpasswd() key error."); return 0; } strlcpy(key, key_tmp, MAX_KEY_LEN+1); #endif *key_len = strlen(key); } } if(options->have_hmac_key) { strlcpy(hmac_key, options->hmac_key, MAX_KEY_LEN+1); *hmac_key_len = strlen(hmac_key); use_hmac = 1; } else if(options->have_hmac_base64_key) { *hmac_key_len = fko_base64_decode(options->hmac_key_base64, (unsigned char *) options->hmac_key); if(*hmac_key_len > MAX_KEY_LEN || *hmac_key_len < 0) { log_msg(LOG_VERBOSITY_ERROR, "[*] Invalid decoded key length: '%d', must be in [0,%d]", *hmac_key_len, MAX_KEY_LEN); return 0; } memcpy(hmac_key, options->hmac_key, *hmac_key_len); use_hmac = 1; } else if (options->use_hmac) { /* If --get-key file was specified grab the key/password from it. */ if(options->get_hmac_key_file[0] != 0x0) { if(get_key_file(hmac_key, hmac_key_len, options->get_hmac_key_file, ctx, options) != 1) { return 0; } use_hmac = 1; } else { #if AFL_FUZZING strlcpy(hmac_key, AFL_HMAC_KEY, MAX_KEY_LEN+1); #else hmac_key_tmp = getpasswd("Enter HMAC key: ", options->input_fd); if(hmac_key_tmp == NULL) { log_msg(LOG_VERBOSITY_ERROR, "[*] getpasswd() key error."); return 0; } strlcpy(hmac_key, hmac_key_tmp, MAX_KEY_LEN+1); #endif *hmac_key_len = strlen(hmac_key); use_hmac = 1; } } if (use_hmac) { if(*hmac_key_len < 0 || *hmac_key_len > MAX_KEY_LEN) { log_msg(LOG_VERBOSITY_ERROR, "[*] Invalid HMAC key length: '%d', must be in [0,%d]", *hmac_key_len, MAX_KEY_LEN); return 0; } /* Make sure the same key is not used for both encryption and the HMAC */ if(*hmac_key_len == *key_len) { if(memcmp(hmac_key, key, *key_len) == 0) { log_msg(LOG_VERBOSITY_ERROR, "[*] The encryption passphrase and HMAC key should not be identical, no SPA packet sent. Exiting."); return 0; } } res = fko_set_spa_hmac_type(ctx, options->hmac_type); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_hmac_type", res); return 0; } } return 1; }
/* JNI interface: constructs arguments and calls main function */ jstring Java_biz_incomsystems_fwknop2_SendSPA_sendSPAPacket(JNIEnv* env, jobject thiz) { fko_ctx_t ctx; fwknop_options_t opts; int res, hmac_str_len = 0; short message_type; short digest_type = FKO_DIGEST_SHA256; short hmac_type = FKO_HMAC_SHA256; int key_len, hmac_key_len; char res_msg[MSG_BUFSIZE+1] = {0}; char spa_msg[MSG_BUFSIZE+1] = {0}; char nat_msg[MSG_BUFSIZE+1] = {0}; jstring ourSpa; char *key_tmp[MAX_KEY_LEN+1] = {0}, *hmac_key_tmp[MAX_KEY_LEN+1] = {0}; LOGV("**** Init fwknop ****"); memset(&opts, 0, sizeof(fwknop_options_t)); /* Read the member values from the Java Object that called sendSPAPacket() method */ jclass c = (*env)->GetObjectClass(env,thiz); jfieldID fid = (*env)->GetFieldID(env, c, "access_str", "Ljava/lang/String;"); jstring jaccess = (*env)->GetObjectField(env, thiz, fid); const char *access_str = (*env)->GetStringUTFChars(env, jaccess, 0); fid = (*env)->GetFieldID(env, c, "allowip_str", "Ljava/lang/String;"); jstring jallowip = (*env)->GetObjectField(env, thiz, fid); const char *allowip_str = (*env)->GetStringUTFChars(env, jallowip, 0); fid = (*env)->GetFieldID(env, c, "passwd_str", "Ljava/lang/String;"); jstring jpasswd = (*env)->GetObjectField(env, thiz, fid); char *passwd_str = (*env)->GetStringUTFChars(env, jpasswd, 0); fid = (*env)->GetFieldID(env, c, "passwd_b64", "Ljava/lang/String;"); jstring jpasswd_b64 = (*env)->GetObjectField(env, thiz, fid); const char *passwd_b64 = (*env)->GetStringUTFChars(env, jpasswd_b64, 0); fid = (*env)->GetFieldID(env, c, "digest_type", "Ljava/lang/String;"); jstring jdigest_type = (*env)->GetObjectField(env, thiz, fid); char *set_digest_type = (*env)->GetStringUTFChars(env, jdigest_type, 0); fid = (*env)->GetFieldID(env, c, "hmac_str", "Ljava/lang/String;"); jstring jhmac = (*env)->GetObjectField(env, thiz, fid); char *hmac_str = (*env)->GetStringUTFChars(env, jhmac, 0); fid = (*env)->GetFieldID(env, c, "hmac_b64", "Ljava/lang/String;"); jstring jhmac_b64 = (*env)->GetObjectField(env, thiz, fid); const char *hmac_b64 = (*env)->GetStringUTFChars(env, jhmac_b64, 0); fid = (*env)->GetFieldID(env, c, "hmac_type", "Ljava/lang/String;"); jstring jhmac_type = (*env)->GetObjectField(env, thiz, fid); char *set_hmac_type = (*env)->GetStringUTFChars(env, jhmac_type, 0); fid = (*env)->GetFieldID(env, c, "fw_timeout_str", "Ljava/lang/String;"); jstring jfwtimeout = (*env)->GetObjectField(env, thiz, fid); const char *fw_timeout_str = (*env)->GetStringUTFChars(env, jfwtimeout, 0); fid = (*env)->GetFieldID(env, c, "nat_access_str", "Ljava/lang/String;"); jstring jnat_access_str = (*env)->GetObjectField(env, thiz, fid); const char *nat_access_str = (*env)->GetStringUTFChars(env, jnat_access_str, 0); fid = (*env)->GetFieldID(env, c, "nat_local", "Ljava/lang/String;"); jstring jnat_local = (*env)->GetObjectField(env, thiz, fid); const char *nat_local = (*env)->GetStringUTFChars(env, jnat_local, 0); fid = (*env)->GetFieldID(env, c, "server_cmd_str", "Ljava/lang/String;"); jstring jserver_cmd = (*env)->GetObjectField(env, thiz, fid); const char *server_cmd_str = (*env)->GetStringUTFChars(env, jserver_cmd, 0); fid = (*env)->GetFieldID(env, c, "legacy", "Ljava/lang/String;"); jstring jlegacy = (*env)->GetObjectField(env, thiz, fid); const char *legacy = (*env)->GetStringUTFChars(env, jlegacy, 0); /* Sanity checks */ if(access_str == NULL) { sprintf(res_msg, "Error: Invalid or missing access string"); goto cleanup2; } if(allowip_str == NULL) { sprintf(res_msg, "Error: Invalid or missing allow IP"); goto cleanup2; } if(passwd_str == NULL) { sprintf(res_msg, "Error: Invalid or missing password"); goto cleanup2; } if(fw_timeout_str == NULL) { sprintf(res_msg, "Error: Invalid or missing firewall timeout value"); goto cleanup2; } if(hmac_str != NULL) { hmac_str_len = (int)strlen(hmac_str); } key_len = (int)strlen(passwd_str); if(legacy == NULL) { sprintf(legacy, "false"); } if(strcmp(hmac_b64, "true") == 0) { hmac_str_len = fko_base64_decode( hmac_str, (unsigned char *)hmac_key_tmp); if(hmac_str_len > MAX_KEY_LEN || hmac_str_len < 0) { LOGV("[*] Invalid key length: '%d', must be in [1,%d]", hmac_str_len, MAX_KEY_LEN); goto cleanup2; } else { memcpy(hmac_str, hmac_key_tmp, hmac_str_len); } } if(strcmp(passwd_b64, "true") == 0) { LOGV("Detected key b64"); key_len = fko_base64_decode(passwd_str, (unsigned char *)key_tmp); if(key_len > MAX_KEY_LEN || key_len < 0) { LOGV( "[*] Invalid key length: '%d', must be in [1,%d]", key_len, MAX_KEY_LEN); goto cleanup2; } else { memcpy(passwd_str, key_tmp, key_len); } } /* Using an HMAC is optional in the pre-rfc mode. */ if (server_cmd_str[0] != 0x0) { message_type = FKO_COMMAND_MSG; } else { message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG; } /* Intialize the context */ res = fko_new(&ctx); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Unable to create FKO context", res)); goto cleanup2; } /* Set server command */ if (server_cmd_str[0] != 0x0) { message_type = FKO_COMMAND_MSG; fko_set_spa_message_type(ctx, message_type); res = fko_set_spa_message(ctx, server_cmd_str); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting SPA request message", res)); goto cleanup; } } else { /* Set client timeout */ res = fko_set_spa_client_timeout(ctx, atoi(fw_timeout_str)); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting FW timeout", res)); goto cleanup; } /* Set the spa message string */ snprintf(spa_msg, MSG_BUFSIZE, "%s,%s", allowip_str, access_str); res = fko_set_spa_message(ctx, spa_msg); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting SPA request message", res)); goto cleanup; } } /* Set the HMAC mode if necessary */ if (strcmp(legacy, "true") == 0) { res = fko_set_spa_encryption_mode(ctx, FKO_ENC_MODE_CBC_LEGACY_IV); if (key_len > 16) { key_len = 16; } } if (hmac_str_len > 0) { if (strcmp(set_hmac_type, "MD5") == 0) { hmac_type = FKO_HMAC_MD5; } else if (strcmp(set_hmac_type, "SHA1") == 0) { hmac_type = FKO_HMAC_SHA1; } else if (strcmp(set_hmac_type, "SHA256") == 0) { hmac_type = FKO_HMAC_SHA256; } else if (strcmp(set_hmac_type, "SHA384") == 0) { hmac_type = FKO_HMAC_SHA384; } else if (strcmp(set_hmac_type, "SHA512") == 0) { hmac_type = FKO_HMAC_SHA512; } res = fko_set_spa_hmac_type(ctx, hmac_type); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting SPA HMAC type", res)); goto cleanup; } } /* Set Nat */ if (nat_access_str[0] != 0x0){ // if nat_access_str is not blank, push it into fko context if (strncmp(nat_local, "true", 4) == 0) { message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG; fko_set_spa_message_type(ctx, message_type); LOGV("Finished setting local-nat."); } res = fko_set_spa_nat_access(ctx, nat_access_str); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting NAT string", res)); goto cleanup; } } LOGV("Setting digest type to %s.", set_digest_type); if (strcmp(set_digest_type, "MD5") == 0) { digest_type = FKO_HMAC_MD5; } else if (strcmp(set_digest_type, "SHA1") == 0) { digest_type = FKO_HMAC_SHA1; } else if (strcmp(set_digest_type, "SHA256") == 0) { digest_type = FKO_HMAC_SHA256; } else if (strcmp(set_digest_type, "SHA384") == 0) { digest_type = FKO_HMAC_SHA384; } else if (strcmp(set_digest_type, "SHA512") == 0) { digest_type = FKO_HMAC_SHA512; } res = fko_set_spa_digest_type(ctx, digest_type); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting SPA digest type", res)); goto cleanup; } LOGV("Finished setting digest type."); /* Finalize the context data (Encrypt and encode). */ res = fko_spa_data_final(ctx, (char*)passwd_str, key_len, (char *)hmac_str, hmac_str_len); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error generating SPA data", res)); goto cleanup; } LOGV("Finished finalize."); res = fko_get_spa_data(ctx, &opts.spa_data); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error getting SPA data", res)); goto cleanup; } /* Generate the spa data packet */ ourSpa = (*env)->NewStringUTF(env, opts.spa_data); cleanup: /* Release the resources used by the fko context. */ fko_destroy(ctx); cleanup2: /* Release mem */ (*env)->ReleaseStringUTFChars(env, jaccess, access_str); (*env)->ReleaseStringUTFChars(env, jallowip, allowip_str); (*env)->ReleaseStringUTFChars(env, jpasswd, passwd_str); (*env)->ReleaseStringUTFChars(env, jpasswd_b64, passwd_b64); (*env)->ReleaseStringUTFChars(env, jdigest_type, set_digest_type); (*env)->ReleaseStringUTFChars(env, jhmac, hmac_str); (*env)->ReleaseStringUTFChars(env, jhmac_b64, hmac_b64); (*env)->ReleaseStringUTFChars(env, jhmac_type, set_hmac_type); (*env)->ReleaseStringUTFChars(env, jfwtimeout, fw_timeout_str); (*env)->ReleaseStringUTFChars(env, jnat_access_str, nat_access_str); (*env)->ReleaseStringUTFChars(env, jnat_local, nat_local); return ourSpa; }
static void test_loop_compounded(void) { fko_ctx_t ctx = NULL, decrypt_ctx = NULL; char *spa_data = NULL; int i, j, k, l, res; for (i=0; i<FCN_CALLS; i++) { fko_new(&ctx); res = fko_set_spa_client_timeout(ctx, i); if (res != FKO_SUCCESS) printf("fko_set_spa_client_timeout(): %s\n", fko_errstr(res)); for (j=-1; j<FKO_LAST_MSG_TYPE+1; j++) { res = fko_set_spa_message_type(ctx, j); if (res != FKO_SUCCESS) printf("fko_set_spa_message_type(): %s\n", fko_errstr(res)); res = fko_set_timestamp(ctx, 100); if (res != FKO_SUCCESS) printf("fko_set_timestamp(): %s\n", fko_errstr(res)); fko_set_spa_message(ctx, "1.1.1.1,tcp/22"); res = fko_set_spa_message(ctx, "123.123.123.123,tcp/22"); if (res != FKO_SUCCESS) printf("fko_set_spa_message(): %s\n", fko_errstr(res)); res = fko_set_spa_nat_access(ctx, "1.2.3.4,1234"); if (res != FKO_SUCCESS) printf("fko_set_spa_nat_access(): %s\n", fko_errstr(res)); res = fko_set_username(ctx, "someuser"); if (res != FKO_SUCCESS) printf("fko_set_username(): %s\n", fko_errstr(res)); res = fko_set_spa_server_auth(ctx, "passwd"); if (res != FKO_SUCCESS) printf("fko_set_spa_server_auth(): %s\n", fko_errstr(res)); res = fko_set_spa_hmac_type(ctx, FKO_HMAC_SHA256); if (res != FKO_SUCCESS) printf("fko_set_spa_hmac_type(): %s\n", fko_errstr(res)); for (k=-4; k<=16; k+=4) { for (l=-4; l<=16; l+=4) { res = fko_spa_data_final(ctx, ENC_KEY, k, HMAC_KEY, l); if (res == FKO_SUCCESS) { res = fko_get_spa_data(ctx, &spa_data); if (res == FKO_SUCCESS) { res = fko_new_with_data(&decrypt_ctx, spa_data, NULL, 0, FKO_ENC_MODE_CBC, HMAC_KEY, l, FKO_HMAC_SHA256); if (res == FKO_SUCCESS) { res = fko_decrypt_spa_data(decrypt_ctx, ENC_KEY, k); if (res != FKO_SUCCESS) printf("fko_decrypt_spa_data(): %s\n", fko_errstr(res)); fko_destroy(decrypt_ctx); decrypt_ctx = NULL; spa_calls += 13; spa_compounded_calls += 13; } else { printf("fko_new_with_data(): %s\n", fko_errstr(res)); } } else { printf("fko_get_spa_data(): %s\n", fko_errstr(res)); } } else { printf("fko_spa_data_final(): %s\n", fko_errstr(res)); } } } } fko_destroy(ctx); ctx = NULL; spa_calls += 3; spa_compounded_calls += 3; } }
wxString Config::gen_SPA(wxString ip_resolver_url, wxString gpgEngine, wxString gpgHomeFolder, bool debug) { CURLcode curl_Res; fko_ctx_t ctx; fwknop_options_t opts; int key_len = 0; int res; int hmac_str_len = 0; short message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG; short digest_type = FKO_DIGEST_SHA256; short hmac_type = FKO_HMAC_SHA256; char key_str[129] = {0}, hmac_str[129] = {0}; char spa_msg[256] = {0}; // char spa_buf[4096] = {0}; // char * spa_buf_ptr; // char crypt_buf[4096] = {0}; char nat_access_str[25] = {0}; // char * hmac_buf; // char * spa_digest_ptr; memset(&opts, 0, sizeof(fwknop_options_t)); if (this->KEY.IsEmpty() && !this->USE_GPG_CRYPT) return _("Key cannot be blank!"); wxBusyInfo wait(_("Please wait, working...")); if (this->SERVER_PORT.CmpNoCase(wxT("random")) == 0) { srand((int)wxGetLocalTime()); this->SERVER_PORT.Empty(); this->SERVER_PORT << (rand()%55535 + 10000); // do this better, this isn't a horribly good random function } if (this->ACCESS_IP.CmpNoCase(wxT("Source IP")) == 0) this->ACCESS_IP = wxT("0.0.0.0"); else if (this->ACCESS_IP.CmpNoCase(wxT("Resolve IP")) == 0) { std::ostringstream oss; curl_Res = curl_read(std::string(ip_resolver_url.mb_str()), oss); if (curl_Res == CURLE_OK) { wxString result_tmp = wxString::FromUTF8(oss.str().c_str()); wxRegEx findIP( wxT("(([0-9]{1}|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]{1}|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])")); if (!findIP.Matches(result_tmp)) return _("Unable to resolve our IP!"); this->ACCESS_IP = findIP.GetMatch(result_tmp); } else return _("Libcurl returned the error: ") + wxString::FromUTF8(curl_easy_strerror(curl_Res)); } //end resolve ip if (fko_new(&ctx) != FKO_SUCCESS) return _("Could not get new FKO context"); if (USE_GPG_CRYPT) { fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG); fko_set_gpg_exe(ctx, gpgEngine.mb_str()); fko_set_gpg_home_dir(ctx, gpgHomeFolder.mb_str()); fko_set_gpg_recipient(ctx, GPG_CRYPT_ID.mb_str()); if (GPG_SIG_ID.CmpNoCase(_("None")) != 0) fko_set_gpg_signer(ctx, GPG_SIG_ID.mb_str()); fko_set_spa_encryption_mode(ctx, FKO_ENC_MODE_ASYMMETRIC); } else { if (this->KEY_BASE64) { key_len = fko_base64_decode(this->KEY.mb_str(), (unsigned char *)key_str); } else { strncpy(key_str, (const char*)this->KEY.mb_str(wxConvUTF8), 128); key_len = (int)strlen(key_str); } } if (this->HMAC_BASE64) { hmac_str_len = fko_base64_decode(this->HMAC.mb_str(), (unsigned char *)hmac_str); } else { strncpy(hmac_str, (const char*)this->HMAC.mb_str(wxConvUTF8), 128); hmac_str_len = (int)strlen(hmac_str); } if (MESS_TYPE.CmpNoCase(wxT("Server Command")) == 0) { message_type = FKO_COMMAND_MSG; if (fko_set_spa_message_type(ctx, message_type) != FKO_SUCCESS) return _("Could not set message type"); snprintf(spa_msg, 256, "%s,%s", (const char*)this->ACCESS_IP.mb_str(wxConvUTF8), (const char*)this->SERVER_CMD.mb_str(wxConvUTF8)); res = fko_set_spa_message(ctx, spa_msg); if (res != FKO_SUCCESS) return _("Could not set command message"); } else { if (fko_set_spa_client_timeout(ctx, wxAtoi(this->SERVER_TIMEOUT)) != FKO_SUCCESS) return _("Could not set SPA timeout"); snprintf(spa_msg, 256, "%s,%s", (const char*)this->ACCESS_IP.mb_str(wxConvUTF8), (const char*)this->PORTS.mb_str(wxConvUTF8)); if (fko_set_spa_message(ctx, spa_msg) != FKO_SUCCESS) return _("Could not set SPA Message"); } if (this->LEGACY) { // technically should trim hmac keys if (fko_set_spa_encryption_mode(ctx, FKO_ENC_MODE_CBC_LEGACY_IV) != FKO_SUCCESS) return _("Could not set Legacy mode."); } if (!this->HMAC.IsEmpty()){ if (this->HMAC_TYPE.CmpNoCase(wxT("MD5"))==0) hmac_type = FKO_HMAC_MD5; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA1"))==0) hmac_type = FKO_HMAC_SHA1; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA256"))==0) hmac_type = FKO_HMAC_SHA256; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA384"))==0) hmac_type = FKO_HMAC_SHA384; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA512"))==0) hmac_type = FKO_HMAC_SHA512; if (fko_set_spa_hmac_type(ctx, hmac_type) != FKO_SUCCESS) return _("Could not set HMAC type."); } if (this->MESS_TYPE.CmpNoCase(wxT("Nat Access")) == 0) { sprintf(nat_access_str, "%s,%s", (const char*)this->NAT_IP.mb_str(wxConvUTF8), (const char*)this->NAT_PORT.mb_str(wxConvUTF8)); if (fko_set_spa_nat_access(ctx, nat_access_str) != FKO_SUCCESS) return _("Could not set nat access string."); } else if (this->MESS_TYPE.CmpNoCase(wxT("Local Nat Access")) == 0) { message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG; if (fko_set_spa_message_type(ctx, message_type) != FKO_SUCCESS) return _("Chould not set message type"); sprintf(nat_access_str, "%s,%s", (const char*)this->SERVER_IP.mb_str(wxConvUTF8), (const char*)this->NAT_PORT.mb_str(wxConvUTF8)); if (fko_set_spa_nat_access(ctx, nat_access_str) != FKO_SUCCESS) return _("Could not set nat access string."); } if (this->DIGEST_TYPE.CmpNoCase(wxT("MD5"))==0) digest_type = FKO_DIGEST_MD5; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA1"))==0) digest_type = FKO_DIGEST_SHA1; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA256"))==0) digest_type = FKO_DIGEST_SHA256; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA384"))==0) digest_type = FKO_DIGEST_SHA384; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA512"))==0) digest_type = FKO_DIGEST_SHA512; if (fko_set_spa_digest_type(ctx, digest_type) != FKO_SUCCESS) return _("Could not set SPA digest type."); if (fko_spa_data_final(ctx, key_str, key_len, hmac_str, hmac_str_len) != FKO_SUCCESS) return _("Could not generate SPA data."); if (fko_get_spa_data(ctx, &opts.spa_data) != FKO_SUCCESS) return _("Could not retrieve SPA data."); // if (!USE_GPG_CRYPT) { this->SPA_STRING = wxString::FromUTF8(opts.spa_data); /*} else { //could retain this for libfko without gpg support fko_get_encoded_data(ctx, &spa_buf_ptr); fko_get_spa_digest(ctx, &spa_digest_ptr); sprintf(spa_buf,"%s:%s", spa_buf_ptr, spa_digest_ptr); ourGPG->encryptAndSign(GPG_CRYPT_ID, GPG_SIG_ID, spa_buf, crypt_buf); fko_set_spa_data(ctx, crypt_buf); fko_set_spa_hmac(ctx, hmac_str, hmac_str_len); fko_get_spa_hmac(ctx, &hmac_buf); strcat(crypt_buf, hmac_buf); this->SPA_STRING = wxString::FromUTF8(crypt_buf + 2); }*/ if (debug) { wxTextEntryDialog *debugMessage = new wxTextEntryDialog(NULL, _("Debug info"), _("Debug info"), "Source IP: " + this->ACCESS_IP +"\n" + "SPA String: " + this->SPA_STRING, wxOK | wxTE_MULTILINE ); debugMessage->SetSize(620, 320); debugMessage->ShowModal(); debugMessage->Destroy(); } return _("Success"); }
/* Initialize an fko context with external (encrypted/encoded) data. * This is used to create a context with the purpose of decoding * and parsing the provided data into the context data. */ int fko_new_with_data(fko_ctx_t *r_ctx, const char * const enc_msg, const char * const dec_key, const int dec_key_len, int encryption_mode, const char * const hmac_key, const int hmac_key_len, const int hmac_type) { fko_ctx_t ctx = NULL; int res = FKO_SUCCESS; /* Are we optimistic or what? */ int enc_msg_len; #if HAVE_LIBFIU fiu_return_on("fko_new_with_data_msg", FKO_ERROR_INVALID_DATA_FUNCS_NEW_ENCMSG_MISSING); #endif if(enc_msg == NULL) return(FKO_ERROR_INVALID_DATA_FUNCS_NEW_ENCMSG_MISSING); #if HAVE_LIBFIU fiu_return_on("fko_new_with_data_keylen", FKO_ERROR_INVALID_KEY_LEN); #endif if(dec_key_len < 0 || hmac_key_len < 0) return(FKO_ERROR_INVALID_KEY_LEN); ctx = calloc(1, sizeof *ctx); if(ctx == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); enc_msg_len = strnlen(enc_msg, MAX_SPA_ENCODED_MSG_SIZE); if(! is_valid_encoded_msg_len(enc_msg_len)) { free(ctx); return(FKO_ERROR_INVALID_DATA_FUNCS_NEW_MSGLEN_VALIDFAIL); } /* First, add the data to the context. */ ctx->encrypted_msg = strdup(enc_msg); ctx->encrypted_msg_len = enc_msg_len; if(ctx->encrypted_msg == NULL) { free(ctx); return(FKO_ERROR_MEMORY_ALLOCATION); } /* Default Encryption Mode (Rijndael in CBC mode) */ ctx->initval = FKO_CTX_INITIALIZED; res = fko_set_spa_encryption_mode(ctx, encryption_mode); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* HMAC digest type */ res = fko_set_spa_hmac_type(ctx, hmac_type); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Check HMAC if the access stanza had an HMAC key */ if(hmac_key_len > 0 && hmac_key != NULL) res = fko_verify_hmac(ctx, hmac_key, hmac_key_len); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Consider it initialized here. */ FKO_SET_CTX_INITIALIZED(ctx); /* If a decryption key is provided, go ahead and decrypt and decode. */ if(dec_key != NULL) { res = fko_decrypt_spa_data(ctx, dec_key, dec_key_len); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; *r_ctx = NULL; /* Make sure the caller ctx is null just in case */ return(res); } } #if HAVE_LIBGPGME /* Set gpg signature verify on. */ ctx->verify_gpg_sigs = 1; #endif /* HAVE_LIBGPGME */ *r_ctx = ctx; return(res); }
wxString Config::gen_SPA(wxString ip_resolver_url) { CURLcode curl_Res; fko_ctx_t ctx; fwknop_options_t opts; int key_len, res; int hmac_str_len = 0; short message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG; short digest_type = FKO_DIGEST_SHA256; short hmac_type = FKO_HMAC_SHA256; char key_str[129] = {0}, hmac_str[129] = {0}; char spa_msg[256] = {0}; char debug_buf[4096] = {0}; char nat_access_str[25] = {0}; memset(&opts, 0, sizeof(fwknop_options_t)); if (this->KEY.IsEmpty()) return _("Key cannot be blank!"); wxBusyInfo wait(_("Please wait, working...")); if (this->SERVER_PORT.CmpNoCase(wxT("random")) == 0) { srand((int)wxGetLocalTime()); this->SERVER_PORT.Empty(); this->SERVER_PORT << (rand()%55535 + 10000); // do this better, this isn't a horribly good random function } if (this->ACCESS_IP.CmpNoCase(wxT("Source IP")) == 0) this->ACCESS_IP = wxT("0.0.0.0"); else if (this->ACCESS_IP.CmpNoCase(wxT("Resolve IP")) == 0) { std::ostringstream oss; curl_Res = curl_read(std::string(ip_resolver_url.mb_str()), oss); //Eventually make this a user definable service. if (curl_Res == CURLE_OK) { wxString result_tmp = wxString::FromUTF8(oss.str().c_str()); wxRegEx findIP( wxT("(([0-9]{1}|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]{1}|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])")); if (!findIP.Matches(result_tmp)) return _("Unable to resolve our IP!"); this->ACCESS_IP = findIP.GetMatch(result_tmp); } else return _("Libcurl returned the error: ") + wxString::FromUTF8(curl_easy_strerror(curl_Res)); } //end resolve ip if (this->KEY_BASE64) { key_len = fko_base64_decode(this->KEY.mb_str(), (unsigned char *)key_str); } else { strncpy(key_str, (const char*)this->KEY.mb_str(wxConvUTF8), 128); key_len = (int)strlen(key_str); } if (this->HMAC_BASE64) { hmac_str_len = fko_base64_decode(this->HMAC.mb_str(), (unsigned char *)hmac_str); } else { strncpy(hmac_str, (const char*)this->HMAC.mb_str(wxConvUTF8), 128); hmac_str_len = (int)strlen(hmac_str); } if (fko_new(&ctx) != FKO_SUCCESS) return _("Could not get new FKO context"); if (MESS_TYPE.CmpNoCase(wxT("Server Command")) == 0) { message_type = FKO_COMMAND_MSG; if (fko_set_spa_message_type(ctx, message_type) != FKO_SUCCESS) return _("Could not set message type"); snprintf(spa_msg, 256, "%s,%s", (const char*)this->ACCESS_IP.mb_str(wxConvUTF8), (const char*)this->SERVER_CMD.mb_str(wxConvUTF8)); res = fko_set_spa_message(ctx, spa_msg); if (res != FKO_SUCCESS) return _("Could not set command message"); } else { if (fko_set_spa_client_timeout(ctx, wxAtoi(this->SERVER_TIMEOUT)) != FKO_SUCCESS) return _("Could not set SPA timeout"); snprintf(spa_msg, 256, "%s,%s", (const char*)this->ACCESS_IP.mb_str(wxConvUTF8), (const char*)this->PORTS.mb_str(wxConvUTF8)); if (fko_set_spa_message(ctx, spa_msg) != FKO_SUCCESS) return _("Could not set SPA Message"); } if (this->LEGACY) { // technically should trim hmac keys if (fko_set_spa_encryption_mode(ctx, FKO_ENC_MODE_CBC_LEGACY_IV) != FKO_SUCCESS) return _("Could not set Legacy mode."); } if (!this->HMAC.IsEmpty()){ if (this->HMAC_TYPE.CmpNoCase(wxT("MD5"))==0) hmac_type = FKO_HMAC_MD5; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA1"))==0) hmac_type = FKO_HMAC_SHA1; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA256"))==0) hmac_type = FKO_HMAC_SHA256; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA384"))==0) hmac_type = FKO_HMAC_SHA384; else if (this->HMAC_TYPE.CmpNoCase(wxT("SHA512"))==0) hmac_type = FKO_HMAC_SHA512; if (fko_set_spa_hmac_type(ctx, hmac_type) != FKO_SUCCESS) return _("Could not set HMAC type."); } if (this->MESS_TYPE.CmpNoCase(wxT("Nat Access")) == 0) { sprintf(nat_access_str, "%s,%s", (const char*)this->NAT_IP.mb_str(wxConvUTF8), (const char*)this->NAT_PORT.mb_str(wxConvUTF8)); if (fko_set_spa_nat_access(ctx, nat_access_str) != FKO_SUCCESS) return _("Could not set nat access string."); } else if (this->MESS_TYPE.CmpNoCase(wxT("Local Nat Access")) == 0) { message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG; if (fko_set_spa_message_type(ctx, message_type) != FKO_SUCCESS) return _("Chould not set message type"); sprintf(nat_access_str, "%s,%s", (const char*)this->SERVER_IP.mb_str(wxConvUTF8), (const char*)this->NAT_PORT.mb_str(wxConvUTF8)); if (fko_set_spa_nat_access(ctx, nat_access_str) != FKO_SUCCESS) return _("Could not set nat access string."); } if (this->DIGEST_TYPE.CmpNoCase(wxT("MD5"))==0) digest_type = FKO_DIGEST_MD5; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA1"))==0) digest_type = FKO_DIGEST_SHA1; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA256"))==0) digest_type = FKO_DIGEST_SHA256; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA384"))==0) digest_type = FKO_DIGEST_SHA384; else if (this->DIGEST_TYPE.CmpNoCase(wxT("SHA512"))==0) digest_type = FKO_DIGEST_SHA512; if (fko_set_spa_digest_type(ctx, digest_type) != FKO_SUCCESS) return _("Could not set SPA digest type."); if (fko_spa_data_final(ctx, key_str, key_len, hmac_str, hmac_str_len) != FKO_SUCCESS) return _("Could not generate SPA data."); if (fko_get_spa_data(ctx, &opts.spa_data) != FKO_SUCCESS) return _("Could not retrieve SPA data."); //dump_ctx_to_buffer(ctx, debug_buf, sizeof(debug_buf)); this->SPA_STRING = wxString::FromUTF8(opts.spa_data); return _("Success"); }
/* JNI interface: constructs arguments and calls main function */ jstring Java_com_max2idea_android_fwknop_Fwknop_sendSPAPacket(JNIEnv* env, jobject thiz) { fko_ctx_t ctx; fwknop_options_t opts; int res, hmac_str_len = 0; char res_msg[MSG_BUFSIZE+1] = {0}; char spa_msg[MSG_BUFSIZE+1] = {0}; LOGV("**** Init fwknop ****"); memset(&opts, 0, sizeof(fwknop_options_t)); /* Read the member values from the Java Object that called sendSPAPacket() method */ jclass c = (*env)->GetObjectClass(env, thiz); jfieldID fid = (*env)->GetFieldID(env, c, "access_str", "Ljava/lang/String;"); jstring jaccess = (*env)->GetObjectField(env, thiz, fid); const char *access_str = (*env)->GetStringUTFChars(env, jaccess, 0); fid = (*env)->GetFieldID(env, c, "allowip_str", "Ljava/lang/String;"); jstring jallowip = (*env)->GetObjectField(env, thiz, fid); const char *allowip_str = (*env)->GetStringUTFChars(env, jallowip, 0); fid = (*env)->GetFieldID(env, c, "destip_str", "Ljava/lang/String;"); jstring jdestip = (*env)->GetObjectField(env, thiz, fid); const char *destip_str = (*env)->GetStringUTFChars(env, jdestip, 0); fid = (*env)->GetFieldID(env, c, "passwd_str", "Ljava/lang/String;"); jstring jpasswd = (*env)->GetObjectField(env, thiz, fid); const char *passwd_str = (*env)->GetStringUTFChars(env, jpasswd, 0); fid = (*env)->GetFieldID(env, c, "hmac_str", "Ljava/lang/String;"); jstring jhmac = (*env)->GetObjectField(env, thiz, fid); const char *hmac_str = (*env)->GetStringUTFChars(env, jhmac, 0); fid = (*env)->GetFieldID(env, c, "fw_timeout_str", "Ljava/lang/String;"); jstring jfwtimeout = (*env)->GetObjectField(env, thiz, fid); const char *fw_timeout_str = (*env)->GetStringUTFChars(env, jfwtimeout, 0); /* Sanity checks */ if(access_str == NULL) { sprintf(res_msg, "Error: Invalid or missing access string"); goto cleanup2; } if(allowip_str == NULL) { sprintf(res_msg, "Error: Invalid or missing allow IP"); goto cleanup2; } if(destip_str == NULL) { sprintf(res_msg, "Error: Invalid or missing destination IP"); goto cleanup2; } if(passwd_str == NULL) { sprintf(res_msg, "Error: Invalid or missing password"); goto cleanup2; } if(fw_timeout_str == NULL) { sprintf(res_msg, "Error: Invalid or missing firewall timeout value"); goto cleanup2; } /* Using an HMAC is optional (currently) */ if(hmac_str != NULL) { hmac_str_len = (int)strlen(hmac_str); } /* Set our spa server info */ opts.spa_server_str = (char*)destip_str; opts.spa_dst_port = FKO_DEFAULT_PORT; /* Until we make this settable. */ /* Intialize the context */ res = fko_new(&ctx); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Unable to create FKO context", res)); goto cleanup2; } /* Set client timeout */ res = fko_set_spa_client_timeout(ctx, atoi(fw_timeout_str)); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting FW timeout", res)); goto cleanup; } /* Set the spa message string */ snprintf(spa_msg, MSG_BUFSIZE, "%s,%s", allowip_str, access_str); res = fko_set_spa_message(ctx, spa_msg); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting SPA request message", res)); goto cleanup; } /* Set the HMAC mode if necessary */ if (hmac_str_len > 0) { res = fko_set_spa_hmac_type(ctx, FKO_DEFAULT_HMAC_MODE); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error setting SPA HMAC type", res)); goto cleanup; } } /* Finalize the context data (Encrypt and encode). */ res = fko_spa_data_final(ctx, (char*)passwd_str, (int)strlen(passwd_str), (char *)hmac_str, hmac_str_len); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error generating SPA data", res)); goto cleanup; } res = fko_get_spa_data(ctx, &opts.spa_data); if (res != FKO_SUCCESS) { strcpy(res_msg, fko_errmsg("Error getting SPA data", res)); goto cleanup; } /* --DSS NOTE: At this point, we could just return the SPA data * to the caller and use the Java network libs to send * the packet and eliminate the spa_comm code altogether. */ /* Send the spa data packet */ res = send_spa_packet(&opts); if (res < 0) { sprintf(res_msg, "Error: send_spa_packet: packet not sent."); } else if (res == 0) { sprintf(res_msg, "Error: send_spa_packet: Empty packet sent."); } else { sprintf(res_msg, "SPA Packet sent successfully."); } cleanup: /* Release the resources used by the fko context. */ fko_destroy(ctx); cleanup2: /* Release mem */ (*env)->ReleaseStringUTFChars(env, jaccess, access_str); (*env)->ReleaseStringUTFChars(env, jallowip, allowip_str); (*env)->ReleaseStringUTFChars(env, jdestip, destip_str); (*env)->ReleaseStringUTFChars(env, jpasswd, passwd_str); (*env)->ReleaseStringUTFChars(env, jhmac, hmac_str); (*env)->ReleaseStringUTFChars(env, jfwtimeout, fw_timeout_str); /* Log and return a string of success or error message. * This can be enhanced semantically with codes. */ LOGV("%s", res_msg); return (*env)->NewStringUTF(env, res_msg); }