/* get_version */ static PyObject * get_version(PyObject *self, PyObject *args) { fko_ctx_t ctx; char *ver_str; int res; if(!PyArg_ParseTuple(args, "k", &ctx)) return NULL; res = fko_get_version(ctx, &ver_str); if(res != FKO_SUCCESS) { PyErr_SetString(FKOError, fko_errstr(res)); return NULL; } return Py_BuildValue("s", ver_str); }
/* Popluate a spa_data struct from an initialized (and populated) FKO context. */ static int get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat) { int res = FKO_SUCCESS; res = fko_get_username(ctx, &(spdat->username)); if(res != FKO_SUCCESS) return(res); res = fko_get_timestamp(ctx, &(spdat->timestamp)); if(res != FKO_SUCCESS) return(res); res = fko_get_version(ctx, &(spdat->version)); if(res != FKO_SUCCESS) return(res); res = fko_get_spa_message_type(ctx, &(spdat->message_type)); if(res != FKO_SUCCESS) return(res); res = fko_get_spa_message(ctx, &(spdat->spa_message)); if(res != FKO_SUCCESS) return(res); res = fko_get_spa_nat_access(ctx, &(spdat->nat_access)); if(res != FKO_SUCCESS) return(res); res = fko_get_spa_server_auth(ctx, &(spdat->server_auth)); if(res != FKO_SUCCESS) return(res); res = fko_get_spa_client_timeout(ctx, (int *)&(spdat->client_timeout)); if(res != FKO_SUCCESS) return(res); return(res); }
/** * @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 */ }
/* 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; }
/** * @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); }
/* 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); }