/* get_spa_data */ static PyObject * get_spa_data(PyObject *self, PyObject *args) { fko_ctx_t ctx; char *spa_data; int res; if(!PyArg_ParseTuple(args, "k", &ctx)) return NULL; res = fko_get_spa_data(ctx, &spa_data); if(res != FKO_SUCCESS) { PyErr_SetString(FKOError, fko_errstr(res)); return NULL; } return Py_BuildValue("s", spa_data); }
/** * @brief Dump a FKO context to a buffer * * This function parses a FKO context and decodes each field to dump them to a * buffer in a comprehensible way. * * @param ctx FKO context to dump * @param dump_buf Buffer where to store the dump of the context * @param dump_buf_len Number of bytes available in the dump_buf array * * @return a FKO error code. FKO_SUCCESS if successful. */ int dump_ctx_to_buffer(fko_ctx_t ctx, char *dump_buf, size_t dump_buf_len) { int cp = 0; int err = FKO_LAST_ERROR; char *rand_val = NULL; char *username = NULL; char *version = NULL; char *spa_message = NULL; char *nat_access = NULL; char *server_auth = NULL; char *enc_data = NULL; char *hmac_data = NULL; char *spa_digest = NULL; char *spa_data = NULL; char digest_str[24] = {0}; char hmac_str[24] = {0}; char enc_mode_str[FKO_ENCRYPTION_MODE_BUFSIZE] = {0}; time_t timestamp = 0; short msg_type = -1; short digest_type = -1; short hmac_type = -1; short encryption_type = -1; int encryption_mode = -1; int client_timeout = -1; /* Zero-ed the buffer */ memset(dump_buf, 0, dump_buf_len); /* Make sure the FKO context is initialized before printing it */ if(!CTX_INITIALIZED(ctx)) err = FKO_ERROR_CTX_NOT_INITIALIZED; else { /* Parse the FKO context and collect data */ RETURN_ON_FKO_ERROR(err, fko_get_rand_value(ctx, &rand_val)); RETURN_ON_FKO_ERROR(err, fko_get_username(ctx, &username)); RETURN_ON_FKO_ERROR(err, fko_get_timestamp(ctx, ×tamp)); RETURN_ON_FKO_ERROR(err, fko_get_version(ctx, &version)); RETURN_ON_FKO_ERROR(err, fko_get_spa_message_type(ctx, &msg_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_message(ctx, &spa_message)); RETURN_ON_FKO_ERROR(err, fko_get_spa_nat_access(ctx, &nat_access)); RETURN_ON_FKO_ERROR(err, fko_get_spa_server_auth(ctx, &server_auth)); RETURN_ON_FKO_ERROR(err, fko_get_spa_client_timeout(ctx, &client_timeout)); RETURN_ON_FKO_ERROR(err, fko_get_spa_digest_type(ctx, &digest_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_hmac_type(ctx, &hmac_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_encryption_type(ctx, &encryption_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_encryption_mode(ctx, &encryption_mode)); RETURN_ON_FKO_ERROR(err, fko_get_encoded_data(ctx, &enc_data)); RETURN_ON_FKO_ERROR(err, fko_get_spa_hmac(ctx, &hmac_data)); RETURN_ON_FKO_ERROR(err, fko_get_spa_digest(ctx, &spa_digest)); RETURN_ON_FKO_ERROR(err, fko_get_spa_data(ctx, &spa_data)); /* Convert the digest integer to a string */ if (digest_inttostr(digest_type, digest_str, sizeof(digest_str)) != 0) return (FKO_ERROR_INVALID_DIGEST_TYPE); /* Convert the encryption mode integer to a string */ if (enc_mode_inttostr(encryption_mode, enc_mode_str, sizeof(enc_mode_str)) != 0) return (FKO_ERROR_INVALID_ENCRYPTION_TYPE); /* Convert the HMAC digest integer to a string if a HMAC message is available */ if (ctx->msg_hmac_len != 0) { if (hmac_digest_inttostr(hmac_type, hmac_str, sizeof(hmac_str)) != 0) return (FKO_ERROR_UNSUPPORTED_HMAC_MODE); } /* Fill in the buffer to dump */ cp = append_msg_to_buf(dump_buf, dump_buf_len, "SPA Field Values:\n=================\n"); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Random Value: %s\n", rand_val == NULL ? NULL_STRING : rand_val); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Username: %s\n", username == NULL ? NULL_STRING : username); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Timestamp: %u\n", (unsigned int) timestamp); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " FKO Version: %s\n", version == NULL ? NULL_STRING : version); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Message Type: %i (%s)\n", msg_type, msg_type_inttostr(msg_type)); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Message String: %s\n", spa_message == NULL ? NULL_STRING : spa_message); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Nat Access: %s\n", nat_access == NULL ? NULL_STRING : nat_access); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Server Auth: %s\n", server_auth == NULL ? NULL_STRING : server_auth); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Client Timeout: %u\n", client_timeout); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Digest Type: %u (%s)\n", digest_type, digest_str); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " HMAC Type: %u (%s)\n", hmac_type, hmac_str); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "Encryption Type: %d (%s)\n", encryption_type, enc_type_inttostr(encryption_type)); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_str); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Encoded Data: %s\n", enc_data == NULL ? NULL_STRING : enc_data); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "SPA Data Digest: %s\n", spa_digest == NULL ? NULL_STRING : spa_digest); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " HMAC: %s\n", hmac_data == NULL ? NULL_STRING : hmac_data); append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Final SPA Data: %s\n", spa_data); err = FKO_SUCCESS; } return (err); }
int main(int argc, char **argv) { fko_ctx_t ctx = NULL; fko_ctx_t ctx2 = NULL; int res; char *spa_data=NULL, *version=NULL; char access_buf[MAX_LINE_LEN] = {0}; char key[MAX_KEY_LEN+1] = {0}; char hmac_key[MAX_KEY_LEN+1] = {0}; int key_len = 0, orig_key_len = 0, hmac_key_len = 0, enc_mode; int tmp_port = 0; char dump_buf[CTX_DUMP_BUFSIZE]; fko_cli_options_t options; memset(&options, 0x0, sizeof(fko_cli_options_t)); /* Initialize the log module */ log_new(); /* Handle command line */ config_init(&options, argc, argv); #if HAVE_LIBFIU /* Set any fault injection points early */ if(! enable_fault_injections(&options)) clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); #endif /* Handle previous execution arguments if required */ if(prev_exec(&options, argc, argv) != 1) clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); if(options.show_last_command) clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_SUCCESS); /* Intialize the context */ res = fko_new(&ctx); if(res != FKO_SUCCESS) { errmsg("fko_new", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* Display version info and exit. */ if(options.version) { fko_get_version(ctx, &version); fprintf(stdout, "fwknop client %s, FKO protocol version %s\n", MY_VERSION, version); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_SUCCESS); } /* Set client timeout */ if(options.fw_timeout >= 0) { res = fko_set_spa_client_timeout(ctx, options.fw_timeout); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_client_timeout", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } /* Set the SPA packet message type based on command line options */ res = set_message_type(ctx, &options); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_message_type", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* Adjust the SPA timestamp if necessary */ if(options.time_offset_plus > 0) { res = fko_set_timestamp(ctx, options.time_offset_plus); if(res != FKO_SUCCESS) { errmsg("fko_set_timestamp", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } if(options.time_offset_minus > 0) { res = fko_set_timestamp(ctx, -options.time_offset_minus); if(res != FKO_SUCCESS) { errmsg("fko_set_timestamp", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } if(options.server_command[0] != 0x0) { /* Set the access message to a command that the server will * execute */ snprintf(access_buf, MAX_LINE_LEN, "%s%s%s", options.allow_ip_str, ",", options.server_command); } else { /* Resolve the client's public facing IP address if requestesd. * if this fails, consider it fatal. */ if (options.resolve_ip_http_https) { if(options.resolve_http_only) { if(resolve_ip_http(&options) < 0) { clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } else { /* Default to HTTPS */ if(resolve_ip_https(&options) < 0) { clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } } /* Set a message string by combining the allow IP and the * port/protocol. The fwknopd server allows no port/protocol * to be specified as well, so in this case append the string * "none/0" to the allow IP. */ if(set_access_buf(ctx, &options, access_buf) != 1) clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } res = fko_set_spa_message(ctx, access_buf); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_message", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* Set NAT access string */ if (options.nat_local || options.nat_access_str[0] != 0x0) { res = set_nat_access(ctx, &options, access_buf); if(res != FKO_SUCCESS) { errmsg("fko_set_nat_access_str", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } /* Set username */ if(options.spoof_user[0] != 0x0) { res = fko_set_username(ctx, options.spoof_user); if(res != FKO_SUCCESS) { errmsg("fko_set_username", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } /* Set up for using GPG if specified. */ if(options.use_gpg) { /* If use-gpg-agent was not specified, then remove the GPG_AGENT_INFO * ENV variable if it exists. */ #ifndef WIN32 if(!options.use_gpg_agent) unsetenv("GPG_AGENT_INFO"); #endif res = fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_encryption_type", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* Set gpg path if necessary */ if(strlen(options.gpg_exe) > 0) { res = fko_set_gpg_exe(ctx, options.gpg_exe); if(res != FKO_SUCCESS) { errmsg("fko_set_gpg_exe", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } /* If a GPG home dir was specified, set it here. Note: Setting * this has to occur before calling any of the other GPG-related * functions. */ if(strlen(options.gpg_home_dir) > 0) { res = fko_set_gpg_home_dir(ctx, options.gpg_home_dir); if(res != FKO_SUCCESS) { errmsg("fko_set_gpg_home_dir", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } res = fko_set_gpg_recipient(ctx, options.gpg_recipient_key); if(res != FKO_SUCCESS) { errmsg("fko_set_gpg_recipient", res); if(IS_GPG_ERROR(res)) log_msg(LOG_VERBOSITY_ERROR, "GPG ERR: %s", fko_gpg_errstr(ctx)); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } if(strlen(options.gpg_signer_key) > 0) { res = fko_set_gpg_signer(ctx, options.gpg_signer_key); if(res != FKO_SUCCESS) { errmsg("fko_set_gpg_signer", res); if(IS_GPG_ERROR(res)) log_msg(LOG_VERBOSITY_ERROR, "GPG ERR: %s", fko_gpg_errstr(ctx)); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } res = fko_set_spa_encryption_mode(ctx, FKO_ENC_MODE_ASYMMETRIC); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_encryption_mode", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } if(options.encryption_mode && !options.use_gpg) { res = fko_set_spa_encryption_mode(ctx, options.encryption_mode); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_encryption_mode", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } /* Set Digest type. */ if(options.digest_type) { res = fko_set_spa_digest_type(ctx, options.digest_type); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_digest_type", res); clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } /* Acquire the necessary encryption/hmac keys */ if(get_keys(ctx, &options, key, &key_len, hmac_key, &hmac_key_len) != 1) clean_exit(ctx, &options, key, &key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); orig_key_len = key_len; if(options.encryption_mode == FKO_ENC_MODE_CBC_LEGACY_IV && key_len > 16) { log_msg(LOG_VERBOSITY_ERROR, "WARNING: Encryption key in '-M legacy' mode must be <= 16 bytes"); log_msg(LOG_VERBOSITY_ERROR, "long - truncating before sending SPA packet. Upgrading remote"); log_msg(LOG_VERBOSITY_ERROR, "fwknopd is recommended."); key_len = 16; } /* Finalize the context data (encrypt and encode the SPA data) */ res = fko_spa_data_final(ctx, key, key_len, hmac_key, hmac_key_len); if(res != FKO_SUCCESS) { errmsg("fko_spa_data_final", res); if(IS_GPG_ERROR(res)) log_msg(LOG_VERBOSITY_ERROR, "GPG ERR: %s", fko_gpg_errstr(ctx)); clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* Display the context data. */ if (options.verbose || options.test) { res = dump_ctx_to_buffer(ctx, dump_buf, sizeof(dump_buf)); if (res == FKO_SUCCESS) log_msg(LOG_VERBOSITY_NORMAL, "%s", dump_buf); else log_msg(LOG_VERBOSITY_WARNING, "Unable to dump FKO context: %s", fko_errstr(res)); } /* Save packet data payload if requested. */ if (options.save_packet_file[0] != 0x0) write_spa_packet_data(ctx, &options); /* SPA packet random destination port handling */ if (options.rand_port) { tmp_port = get_rand_port(ctx); if(tmp_port < 0) clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); options.spa_dst_port = tmp_port; } /* If we are using one the "raw" modes (normally because * we're going to spoof the SPA packet source IP), then select * a random source port unless the source port is already set */ if ((options.spa_proto == FKO_PROTO_TCP_RAW || options.spa_proto == FKO_PROTO_UDP_RAW || options.spa_proto == FKO_PROTO_ICMP) && !options.spa_src_port) { tmp_port = get_rand_port(ctx); if(tmp_port < 0) clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); options.spa_src_port = tmp_port; } res = send_spa_packet(ctx, &options); if(res < 0) { log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet: packet not sent."); clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } else { log_msg(LOG_VERBOSITY_INFO, "send_spa_packet: bytes sent: %i", res); } /* Run through a decode cycle in test mode (--DSS XXX: This test/decode * portion should be moved elsewhere). */ if (options.test) { /************** Decoding now *****************/ /* Now we create a new context based on data from the first one. */ res = fko_get_spa_data(ctx, &spa_data); if(res != FKO_SUCCESS) { errmsg("fko_get_spa_data", res); clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* Pull the encryption mode. */ res = fko_get_spa_encryption_mode(ctx, &enc_mode); if(res != FKO_SUCCESS) { errmsg("fko_get_spa_encryption_mode", res); if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA) log_msg(LOG_VERBOSITY_ERROR, "[*] Could not zero out sensitive data buffer."); ctx = NULL; clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* If gpg-home-dir is specified, we have to defer decrypting if we * use the fko_new_with_data() function because we need to set the * gpg home dir after the context is created, but before we attempt * to decrypt the data. Therefore we either pass NULL for the * decryption key to fko_new_with_data() or use fko_new() to create * an empty context, populate it with the encrypted data, set our * options, then decode it. * * This also verifies the HMAC and truncates it if there are no * problems. */ res = fko_new_with_data(&ctx2, spa_data, NULL, 0, enc_mode, hmac_key, hmac_key_len, options.hmac_type); if(res != FKO_SUCCESS) { errmsg("fko_new_with_data", res); if(fko_destroy(ctx2) == FKO_ERROR_ZERO_OUT_DATA) log_msg(LOG_VERBOSITY_ERROR, "[*] Could not zero out sensitive data buffer."); ctx2 = NULL; clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } res = fko_set_spa_encryption_mode(ctx2, enc_mode); if(res != FKO_SUCCESS) { errmsg("fko_set_spa_encryption_mode", res); if(fko_destroy(ctx2) == FKO_ERROR_ZERO_OUT_DATA) log_msg(LOG_VERBOSITY_ERROR, "[*] Could not zero out sensitive data buffer."); ctx2 = NULL; clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } /* See if we are using gpg and if we need to set the GPG home dir. */ if(options.use_gpg) { if(strlen(options.gpg_home_dir) > 0) { res = fko_set_gpg_home_dir(ctx2, options.gpg_home_dir); if(res != FKO_SUCCESS) { errmsg("fko_set_gpg_home_dir", res); if(fko_destroy(ctx2) == FKO_ERROR_ZERO_OUT_DATA) log_msg(LOG_VERBOSITY_ERROR, "[*] Could not zero out sensitive data buffer."); ctx2 = NULL; clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } } } /* Decrypt */ res = fko_decrypt_spa_data(ctx2, key, key_len); if(res != FKO_SUCCESS) { errmsg("fko_decrypt_spa_data", res); if(IS_GPG_ERROR(res)) { /* we most likely could not decrypt the gpg-encrypted data * because we don't have access to the private key associated * with the public key we used for encryption. Since this is * expected, return 0 instead of an error condition (so calling * programs like the fwknop test suite don't interpret this as * an unrecoverable error), but print the error string for * debugging purposes. The test suite does run a series of * tests that use a single key pair for encryption and * authentication, so decryption become possible for these * tests. */ log_msg(LOG_VERBOSITY_ERROR, "GPG ERR: %s\n%s", fko_gpg_errstr(ctx2), "No access to recipient private key?"); } if(fko_destroy(ctx2) == FKO_ERROR_ZERO_OUT_DATA) log_msg(LOG_VERBOSITY_ERROR, "[*] Could not zero out sensitive data buffer."); ctx2 = NULL; clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_FAILURE); } res = dump_ctx_to_buffer(ctx2, dump_buf, sizeof(dump_buf)); if (res == FKO_SUCCESS) log_msg(LOG_VERBOSITY_NORMAL, "\nDump of the Decoded Data\n%s", dump_buf); else log_msg(LOG_VERBOSITY_WARNING, "Unable to dump FKO context: %s", fko_errstr(res)); if(fko_destroy(ctx2) == FKO_ERROR_ZERO_OUT_DATA) log_msg(LOG_VERBOSITY_ERROR, "[*] Could not zero out sensitive data buffer."); ctx2 = NULL; } clean_exit(ctx, &options, key, &orig_key_len, hmac_key, &hmac_key_len, EXIT_SUCCESS); return EXIT_SUCCESS; /* quiet down a gcc warning */ }
/* 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; }
/* JNI interface: constructs arguments and calls main function */ int fwknop_sendSPAPacket( const char *allowip_str, const char *access_str, const char *destip_str, const char *passwd_str, const char *fw_timeout_str ) { fko_ctx_t ctx; fwknop_options_t opts; int res; char res_msg[MSG_BUFSIZE+1] = {0}; char spa_msg[MSG_BUFSIZE+1] = {0}; printf("**** Init fwknop ****\n"); memset(&opts, 0, sizeof(fwknop_options_t)); /* 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; } /* 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; } /* Finalize the context data (Encrypt and encode). */ res = fko_spa_data_final(ctx, (char*)passwd_str); 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: /* Log and return a string of success or error message. * This can be enhanced semantically with codes. */ printf("%s\n", res_msg); printf("**** Closing fwknop ****\n"); return res; // (*env)->NewStringUTF(env, res_msg); }
/* Show the fields of the FKO context. */ static void display_ctx(fko_ctx_t ctx) { char *rand_val = NULL; char *username = NULL; char *version = NULL; char *spa_message = NULL; char *nat_access = NULL; char *server_auth = NULL; char *enc_data = NULL; char *hmac_data = NULL; char *spa_digest = NULL; char *spa_data = NULL; time_t timestamp = 0; short msg_type = -1; short digest_type = -1; short hmac_type = -1; int encryption_mode = -1; int client_timeout = -1; /* pass in NULL to each fko_get_* function first to ensure * that NULL is handled properly */ fko_get_rand_value(ctx, NULL); fko_get_rand_value(ctx, &rand_val); fko_get_username(ctx, NULL); fko_get_username(ctx, &username); fko_get_timestamp(ctx, NULL); fko_get_timestamp(ctx, ×tamp); fko_get_version(ctx, NULL); fko_get_version(ctx, &version); fko_get_spa_message_type(ctx, NULL); fko_get_spa_message_type(ctx, &msg_type); fko_get_spa_message(ctx, NULL); fko_get_spa_message(ctx, &spa_message); fko_get_spa_nat_access(ctx, NULL); fko_get_spa_nat_access(ctx, &nat_access); fko_get_spa_server_auth(ctx, NULL); fko_get_spa_server_auth(ctx, &server_auth); fko_get_spa_client_timeout(ctx, NULL); fko_get_spa_client_timeout(ctx, &client_timeout); fko_get_spa_digest_type(ctx, NULL); fko_get_spa_digest_type(ctx, &digest_type); fko_get_spa_hmac_type(ctx, NULL); fko_get_spa_hmac_type(ctx, &hmac_type); fko_get_spa_encryption_mode(ctx, NULL); fko_get_spa_encryption_mode(ctx, &encryption_mode); fko_get_encoded_data(ctx, NULL); fko_get_encoded_data(ctx, &enc_data); fko_get_spa_hmac(ctx, NULL); fko_get_spa_hmac(ctx, &hmac_data); fko_get_spa_digest(ctx, NULL); fko_get_spa_digest(ctx, &spa_digest); fko_get_spa_data(ctx, NULL); fko_get_spa_data(ctx, &spa_data); printf("\nFKO Field Values:\n=================\n\n"); printf(" Random Value: %s\n", rand_val == NULL ? "<NULL>" : rand_val); printf(" Username: %s\n", username == NULL ? "<NULL>" : username); printf(" Timestamp: %u\n", (unsigned int) timestamp); printf(" FKO Version: %s\n", version == NULL ? "<NULL>" : version); printf(" Message Type: %i\n", msg_type); printf(" Message String: %s\n", spa_message == NULL ? "<NULL>" : spa_message); printf(" Nat Access: %s\n", nat_access == NULL ? "<NULL>" : nat_access); printf(" Server Auth: %s\n", server_auth == NULL ? "<NULL>" : server_auth); printf(" Client Timeout: %d\n", client_timeout); printf(" Digest Type: %d\n", digest_type); printf(" HMAC Type: %d\n", hmac_type); printf("Encryption Mode: %d\n", encryption_mode); printf(" Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data); printf("SPA Data Digest: %s\n", spa_digest == NULL ? "<NULL>" : spa_digest); printf(" HMAC: %s\n", hmac_data == NULL ? "<NULL>" : hmac_data); printf(" Final SPA Data: %s\n", spa_data); spa_calls += 31; }
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; } }
static void test_loop(int new_ctx_flag, int destroy_ctx_flag) { fko_ctx_t ctx = NULL, decrypt_ctx = NULL; int i, j; char *spa_data = NULL, encode_buf[100], decode_buf[100]; printf("[+] test_loop(): %s, %s\n", new_ctx_flag == NEW_CTX ? "NEW_CTX" : "NO_NEW_CTX", destroy_ctx_flag == CTX_DESTROY ? "DESTROY_CTX" : "NO_DESTROY_CTX"); printf("fko_new(): %s\n", fko_errstr(fko_new(&ctx))); fko_destroy(ctx); ctx = NULL; printf("fko_new(): %s\n", fko_errstr(fko_new(&ctx))); spa_func_getset_int(&ctx, "fko_set_spa_client_timeout", &fko_set_spa_client_timeout, "fko_get_spa_client_timeout", &fko_get_spa_client_timeout, -F_INT, F_INT, 10, new_ctx_flag, destroy_ctx_flag); spa_func_getset_short(&ctx, "fko_set_spa_message_type", &fko_set_spa_message_type, "fko_get_spa_message_type", &fko_get_spa_message_type, FKO_COMMAND_MSG-F_INT, FKO_LAST_MSG_TYPE+F_INT, FKO_ACCESS_MSG, NO_DIGEST, new_ctx_flag, destroy_ctx_flag); spa_func_int(&ctx, "fko_set_timestamp", &fko_set_timestamp, -F_INT, F_INT, 10, new_ctx_flag, destroy_ctx_flag); for (i=0; i<FCN_CALLS; i++) { printf("fko_set_spa_message(1.1.1.1,tcp/22): %s\n", fko_errstr(fko_set_spa_message(ctx, "1.1.1.1,tcp/22"))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } for (i=0; i<FCN_CALLS; i++) { printf("fko_set_spa_nat_access(1.2.3.4,1234): %s\n", fko_errstr(fko_set_spa_nat_access(ctx, "1.2.3.4,1234"))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } for (i=0; i<FCN_CALLS; i++) { printf("fko_set_username(someuser): %s\n", fko_errstr(fko_set_username(ctx, "someuser"))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } spa_func_getset_short(&ctx, "fko_set_spa_encryption_type", &fko_set_spa_encryption_type, "fko_get_spa_encryption_type", &fko_get_spa_encryption_type, FKO_ENCRYPTION_INVALID_DATA-F_INT, FKO_LAST_ENCRYPTION_TYPE+F_INT, FKO_ENCRYPTION_RIJNDAEL, NO_DIGEST, new_ctx_flag, destroy_ctx_flag); spa_func_getset_int(&ctx, "fko_set_spa_encryption_mode", &fko_set_spa_encryption_mode, "fko_get_spa_encryption_mode", &fko_get_spa_encryption_mode, FKO_ENC_MODE_UNKNOWN-F_INT, FKO_LAST_ENC_MODE+F_INT, FKO_ENC_MODE_CBC, new_ctx_flag, destroy_ctx_flag); if (ENABLE_GPG_TESTS) { for (i=0; i<FCN_CALLS; i++) { printf("fko_set_spa_encryption_type(FKO_ENCRYPTION_GPG): %s\n", fko_errstr(fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } for (i=0; i<FCN_CALLS; i++) { printf("fko_set_gpg_home_dir(/home/mbr/.gnupg): %s\n", fko_errstr(fko_set_gpg_home_dir(ctx, "/home/mbr/.gnupg"))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } for (i=0; i<FCN_CALLS; i++) { printf("fko_set_gpg_recipient(1234asdf): %s\n", fko_errstr(fko_set_gpg_recipient(ctx, "1234asdf"))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } } spa_func_getset_short(&ctx, "fko_set_spa_digest_type", &fko_set_spa_digest_type, "fko_get_spa_digest_type", &fko_get_spa_digest_type, FKO_DIGEST_INVALID_DATA-F_INT, FKO_LAST_DIGEST_TYPE+F_INT, FKO_DEFAULT_DIGEST, DO_DIGEST, new_ctx_flag, destroy_ctx_flag); spa_func_getset_short(&ctx, "fko_set_raw_spa_digest_type", &fko_set_spa_digest_type, "fko_get_raw_spa_digest_type", &fko_get_spa_digest_type, FKO_DIGEST_INVALID_DATA-F_INT, FKO_LAST_DIGEST_TYPE+F_INT, FKO_DEFAULT_DIGEST, RAW_DIGEST, new_ctx_flag, destroy_ctx_flag); spa_func_getset_short(&ctx, "fko_set_spa_hmac_type", &fko_set_spa_hmac_type, "fko_get_spa_hmac_type", &fko_get_spa_hmac_type, FKO_HMAC_INVALID_DATA-F_INT, FKO_LAST_HMAC_MODE+F_INT, FKO_HMAC_SHA256, NO_DIGEST, new_ctx_flag, destroy_ctx_flag); printf("Trying encrypt / authenticate step with bogus key lengths...\n"); for (i=-100; i < 200; i += 10) { for (j=-100; j < 200; j += 10) { fko_spa_data_final(ctx, ENC_KEY, i, HMAC_KEY, j); fko_spa_data_final(ctx, NULL, i, HMAC_KEY, j); fko_spa_data_final(ctx, ENC_KEY, i, NULL, j); fko_spa_data_final(ctx, NULL, i, NULL, j); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, NO_PRINT); spa_calls += 4; } } for (i=0; i<FCN_CALLS; i++) { printf("fko_spa_data_final(ENC_KEY, 16, HMAC_KEY, 16): %s\n", fko_errstr(fko_spa_data_final(ctx, ENC_KEY, 16, HMAC_KEY, 16))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } for (i=0; i<FCN_CALLS; i++) { printf("fko_get_spa_data(): %s\n", fko_errstr(fko_get_spa_data(ctx, &spa_data))); printf(" SPA DATA: %s\n", spa_data == NULL ? "<NULL>" : spa_data); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } printf("fko_new_with_data(): %s (data: %s)\n", fko_errstr(fko_new_with_data(&decrypt_ctx, spa_data, NULL, 0, FKO_ENC_MODE_CBC, NULL, 0, FKO_HMAC_SHA256)), spa_data); /* verify hmac, decrypt, and display ctx all together*/ for (i=0; i<FCN_CALLS; i++) { display_ctx(decrypt_ctx); printf("fko_verify_hmac() (1): %s\n", fko_errstr(fko_verify_hmac(decrypt_ctx, HMAC_KEY, 16))); printf("fko_decrypt_spa_data() (1): %s\n", fko_errstr(fko_decrypt_spa_data(decrypt_ctx, ENC_KEY, 16))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } /* now, separately verify hmac, decrypt, and display ctx */ for (i=0; i<FCN_CALLS; i++) { printf("fko_verify_hmac() (2): %s\n", fko_errstr(fko_verify_hmac(decrypt_ctx, HMAC_KEY, 16))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } /* now decrypt */ for (i=0; i<FCN_CALLS; i++) { printf("fko_decrypt_spa_data() (2): %s\n", fko_errstr(fko_decrypt_spa_data(decrypt_ctx, ENC_KEY, 16))); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } for (i=0; i<FCN_CALLS; i++) { display_ctx(decrypt_ctx); ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT); } /* NULL tests */ fko_set_rand_value(ctx, NULL); fko_set_rand_value(ctx, NULL); fko_set_username(ctx, NULL); fko_set_username(ctx, NULL); fko_set_spa_message(ctx, NULL); fko_set_spa_message(ctx, NULL); fko_set_spa_nat_access(ctx, NULL); fko_set_spa_nat_access(ctx, NULL); fko_set_spa_server_auth(ctx, NULL); fko_set_spa_server_auth(ctx, NULL); fko_set_spa_data(ctx, NULL); fko_set_spa_data(ctx, NULL); spa_calls += 12; for (i=0; i<FCN_CALLS; i++) { fko_destroy(ctx); ctx = NULL; } for (i=0; i<FCN_CALLS; i++) { fko_destroy(decrypt_ctx); decrypt_ctx = NULL; } /* exercise the base64 encode/decode wrapper */ fko_base64_encode((unsigned char *)ENC_KEY, encode_buf, 16); fko_base64_decode(encode_buf, (unsigned char *)decode_buf); /* call fko_errstr() across valid and invalid values */ for (i=-5; i < FKO_LAST_ERROR+5; i++) { printf("libfko error (%d): %s\n", i, fko_errstr(i)); spa_calls++; } return; }
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"); }
/** * @brief Dump a FKO context to a buffer * * This function parses a FKO context and decodes each field to dump them to a * buffer in a comprehensible way. * * @param ctx FKO context to dump * @param dump_buf Buffer where to store the dump of the context * @param dump_buf_len Number of bytes available in the dump_buf array * * @return a FKO error code. FKO_SUCCESS if successful. */ int dump_ctx_to_buffer(fko_ctx_t ctx, char *dump_buf, size_t dump_buf_len) { int cp = 0; int err = FKO_LAST_ERROR; char *rand_val = NULL; char *username = NULL; char *version = NULL; char *spa_message = NULL; char *nat_access = NULL; char *server_auth = NULL; char *enc_data = NULL; char *hmac_data = NULL; char *spa_digest = NULL; #if HAVE_LIBGPGME char *gpg_signer = NULL; char *gpg_recip = NULL; char *gpg_sig_id = NULL; unsigned char gpg_sig_verify = 0; unsigned char gpg_ignore_verify = 0; char *gpg_sig_fpr = NULL; char *gpg_home_dir = NULL; char *gpg_exe = NULL; int gpg_sigsum = -1; int gpg_sig_stat = -1; #endif char *spa_data = NULL; char digest_str[24] = {0}; char hmac_str[24] = {0}; char enc_mode_str[FKO_ENCRYPTION_MODE_BUFSIZE] = {0}; time_t timestamp = 0; short msg_type = -1; short digest_type = -1; short hmac_type = -1; short encryption_type = -1; int encryption_mode = -1; int client_timeout = -1; /* Zero-ed the buffer */ memset(dump_buf, 0, dump_buf_len); /* Make sure the FKO context is initialized before printing it */ if(!CTX_INITIALIZED(ctx)) err = FKO_ERROR_CTX_NOT_INITIALIZED; else { /* Parse the FKO context and collect data */ RETURN_ON_FKO_ERROR(err, fko_get_rand_value(ctx, &rand_val)); RETURN_ON_FKO_ERROR(err, fko_get_username(ctx, &username)); RETURN_ON_FKO_ERROR(err, fko_get_timestamp(ctx, ×tamp)); RETURN_ON_FKO_ERROR(err, fko_get_version(ctx, &version)); RETURN_ON_FKO_ERROR(err, fko_get_spa_message_type(ctx, &msg_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_message(ctx, &spa_message)); RETURN_ON_FKO_ERROR(err, fko_get_spa_nat_access(ctx, &nat_access)); RETURN_ON_FKO_ERROR(err, fko_get_spa_server_auth(ctx, &server_auth)); RETURN_ON_FKO_ERROR(err, fko_get_spa_client_timeout(ctx, &client_timeout)); RETURN_ON_FKO_ERROR(err, fko_get_spa_digest_type(ctx, &digest_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_hmac_type(ctx, &hmac_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_encryption_type(ctx, &encryption_type)); RETURN_ON_FKO_ERROR(err, fko_get_spa_encryption_mode(ctx, &encryption_mode)); RETURN_ON_FKO_ERROR(err, fko_get_encoded_data(ctx, &enc_data)); RETURN_ON_FKO_ERROR(err, fko_get_spa_hmac(ctx, &hmac_data)); RETURN_ON_FKO_ERROR(err, fko_get_spa_digest(ctx, &spa_digest)); RETURN_ON_FKO_ERROR(err, fko_get_spa_data(ctx, &spa_data)); #if HAVE_LIBGPGME if(encryption_mode == FKO_ENC_MODE_ASYMMETRIC) { /* Populate GPG variables */ RETURN_ON_FKO_ERROR(err, fko_get_gpg_signer(ctx, &gpg_signer)); RETURN_ON_FKO_ERROR(err, fko_get_gpg_recipient(ctx, &gpg_recip)); RETURN_ON_FKO_ERROR(err, fko_get_gpg_signature_verify(ctx, &gpg_sig_verify)); RETURN_ON_FKO_ERROR(err, fko_get_gpg_ignore_verify_error(ctx, &gpg_ignore_verify)); RETURN_ON_FKO_ERROR(err, fko_get_gpg_home_dir(ctx, &gpg_home_dir)); RETURN_ON_FKO_ERROR(err, fko_get_gpg_exe(ctx, &gpg_exe)); if(fko_get_gpg_signature_id(ctx, &gpg_sig_id) != FKO_SUCCESS) gpg_sig_id = NULL; if(fko_get_gpg_signature_summary(ctx, &gpg_sigsum) != FKO_SUCCESS) gpg_sigsum = -1; if(fko_get_gpg_signature_status(ctx, &gpg_sig_stat) != FKO_SUCCESS) gpg_sig_stat = -1; if(fko_get_gpg_signature_fpr(ctx, &gpg_sig_fpr) != FKO_SUCCESS) gpg_sig_fpr = NULL; } #endif /* Convert the digest integer to a string */ if (digest_inttostr(digest_type, digest_str, sizeof(digest_str)) != 0) return (FKO_ERROR_INVALID_DIGEST_TYPE); /* Convert the encryption mode integer to a string */ if (enc_mode_inttostr(encryption_mode, enc_mode_str, sizeof(enc_mode_str)) != 0) return (FKO_ERROR_INVALID_ENCRYPTION_TYPE); /* Convert the HMAC digest integer to a string if a HMAC message is available */ if (ctx->msg_hmac_len != 0) { if (hmac_digest_inttostr(hmac_type, hmac_str, sizeof(hmac_str)) != 0) return (FKO_ERROR_UNSUPPORTED_HMAC_MODE); } /* Fill in the buffer to dump */ cp = append_msg_to_buf(dump_buf, dump_buf_len, "SPA Field Values:\n=================\n"); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Random Value: %s\n", rand_val == NULL ? NULL_STRING : rand_val); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Username: %s\n", username == NULL ? NULL_STRING : username); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Timestamp: %u\n", (unsigned int) timestamp); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " FKO Version: %s\n", version == NULL ? NULL_STRING : version); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Message Type: %i (%s)\n", msg_type, msg_type_inttostr(msg_type)); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Message String: %s\n", spa_message == NULL ? NULL_STRING : spa_message); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Nat Access: %s\n", nat_access == NULL ? NULL_STRING : nat_access); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Server Auth: %s\n", server_auth == NULL ? NULL_STRING : server_auth); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Client Timeout: %u\n", client_timeout); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Digest Type: %u (%s)\n", digest_type, digest_str); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " HMAC Type: %u (%s)\n", hmac_type, hmac_type == 0 ? "None" : hmac_str); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "Encryption Type: %d (%s)\n", encryption_type, enc_type_inttostr(encryption_type)); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_str); #if HAVE_LIBGPGME if(encryption_mode == FKO_ENC_MODE_ASYMMETRIC) { cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG signer: %s\n", gpg_signer == NULL ? NULL_STRING : gpg_signer); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG recipient: %s\n", gpg_recip == NULL ? NULL_STRING : gpg_recip); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG sig verify: %s\n", gpg_sig_verify == 0 ? "No" : "Yes"); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG ignore sig: %s\n", gpg_ignore_verify == 0 ? "No" : "Yes"); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG sig ID: %s\n", gpg_sig_id == NULL ? NULL_STRING : gpg_sig_id); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG sig fpr: %s\n", gpg_sig_fpr == NULL ? NULL_STRING : gpg_sig_fpr); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "GPG sig summary: %d\n", gpg_sigsum); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG sig status: %d\n", gpg_sig_stat); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG home dir: %s\n", gpg_home_dir == NULL ? NULL_STRING : gpg_home_dir); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " GPG exe: %s\n", gpg_exe == NULL ? GPG_EXE : gpg_exe); } #endif cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Encoded Data: %s\n", enc_data == NULL ? NULL_STRING : enc_data); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, "SPA Data Digest: %s\n", spa_digest == NULL ? NULL_STRING : spa_digest); cp += append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " HMAC: %s\n", hmac_data == NULL ? NULL_STRING : hmac_data); append_msg_to_buf(dump_buf+cp, dump_buf_len-cp, " Final SPA Data: %s\n", spa_data); err = FKO_SUCCESS; } return (err); }
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"); }
/* Show the fields of the FKO context. */ char * dump_ctx(fko_ctx_t ctx) { static char buf[CTX_DUMP_BUFSIZE]; char *ndx; int cp; char *rand_val = NULL; char *username = NULL; char *version = NULL; char *spa_message = NULL; char *nat_access = NULL; char *server_auth = NULL; char *enc_data = NULL; char *spa_digest = NULL; char *spa_data = NULL; time_t timestamp = 0; short msg_type = -1; short digest_type = -1; int client_timeout = -1; /* Should be checking return values, but this is temp code. --DSS */ fko_get_rand_value(ctx, &rand_val); fko_get_username(ctx, &username); fko_get_timestamp(ctx, ×tamp); fko_get_version(ctx, &version); fko_get_spa_message_type(ctx, &msg_type); fko_get_spa_message(ctx, &spa_message); fko_get_spa_nat_access(ctx, &nat_access); fko_get_spa_server_auth(ctx, &server_auth); fko_get_spa_client_timeout(ctx, &client_timeout); fko_get_spa_digest_type(ctx, &digest_type); fko_get_encoded_data(ctx, &enc_data); fko_get_spa_digest(ctx, &spa_digest); fko_get_spa_data(ctx, &spa_data); memset(buf, 0x0, CTX_DUMP_BUFSIZE); ndx = buf; cp = sprintf(ndx, "SPA Field Values:\n=================\n"); ndx += cp; cp = sprintf(ndx, " Random Value: %s\n", rand_val == NULL ? "<NULL>" : rand_val); ndx += cp; cp = sprintf(ndx, " Username: %s\n", username == NULL ? "<NULL>" : username); ndx += cp; cp = sprintf(ndx, " Timestamp: %u\n", (unsigned int) timestamp); ndx += cp; cp = sprintf(ndx, " FKO Version: %s\n", version == NULL ? "<NULL>" : version); ndx += cp; cp = sprintf(ndx, " Message Type: %i\n", msg_type); ndx += cp; cp = sprintf(ndx, " Message String: %s\n", spa_message == NULL ? "<NULL>" : spa_message); ndx += cp; cp = sprintf(ndx, " Nat Access: %s\n", nat_access == NULL ? "<NULL>" : nat_access); ndx += cp; cp = sprintf(ndx, " Server Auth: %s\n", server_auth == NULL ? "<NULL>" : server_auth); ndx += cp; cp = sprintf(ndx, " Client Timeout: %u\n", client_timeout); ndx += cp; cp = sprintf(ndx, " Digest Type: %u\n", digest_type); ndx += cp; cp = sprintf(ndx, " Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data); ndx += cp; cp = sprintf(ndx, "SPA Data Digest: %s\n", spa_digest == NULL ? "<NULL>" : spa_digest); return(buf); }
/* 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); }