/* Set the SPA encryption mode. */ int fko_set_spa_encryption_mode(fko_ctx_t ctx, const int encrypt_mode) { #if HAVE_LIBFIU fiu_return_on("fko_set_spa_encryption_mode_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); #if HAVE_LIBFIU fiu_return_on("fko_set_spa_encryption_mode_val", FKO_ERROR_INVALID_DATA_ENCRYPT_MODE_VALIDFAIL); #endif if(encrypt_mode < 0 || encrypt_mode >= FKO_LAST_ENC_MODE) return(FKO_ERROR_INVALID_DATA_ENCRYPT_MODE_VALIDFAIL); ctx->encryption_mode = encrypt_mode; ctx->state |= FKO_ENCRYPT_MODE_MODIFIED; return(FKO_SUCCESS); }
/* Set the timestamp. */ int fko_set_timestamp(fko_ctx_t ctx, const int offset) { time_t ts; #if HAVE_LIBFIU fiu_return_on("fko_set_timestamp_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return FKO_ERROR_CTX_NOT_INITIALIZED; ts = time(NULL) + offset; #if HAVE_LIBFIU fiu_return_on("fko_set_timestamp_val", FKO_ERROR_INVALID_DATA_TIMESTAMP_VALIDFAIL); #endif if(ts < 0) return(FKO_ERROR_INVALID_DATA_TIMESTAMP_VALIDFAIL); ctx->timestamp = ts; ctx->state |= FKO_DATA_MODIFIED; return(FKO_SUCCESS); }
/* Set the SPA digest type. */ static int set_spa_digest_type(fko_ctx_t ctx, short *digest_type_field, const short digest_type) { #if HAVE_LIBFIU fiu_return_on("set_spa_digest_type_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); #if HAVE_LIBFIU fiu_return_on("set_spa_digest_type_val", FKO_ERROR_INVALID_DATA_ENCODE_DIGEST_VALIDFAIL); #endif if(digest_type < 1 || digest_type >= FKO_LAST_DIGEST_TYPE) return(FKO_ERROR_INVALID_DATA_ENCODE_DIGEST_VALIDFAIL); *digest_type_field = digest_type; ctx->state |= FKO_DIGEST_TYPE_MODIFIED; return(FKO_SUCCESS); }
/* Set the HMAC type */ int fko_set_spa_hmac_type(fko_ctx_t ctx, const short hmac_type) { #if HAVE_LIBFIU fiu_return_on("fko_set_spa_hmac_type_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); #if HAVE_LIBFIU fiu_return_on("fko_set_spa_hmac_type_val", FKO_ERROR_INVALID_DATA_HMAC_TYPE_VALIDFAIL); #endif if(hmac_type < 0 || hmac_type >= FKO_LAST_HMAC_MODE) return(FKO_ERROR_INVALID_DATA_HMAC_TYPE_VALIDFAIL); ctx->hmac_type = hmac_type; ctx->state |= FKO_HMAC_MODE_MODIFIED; return(FKO_SUCCESS); }
int strtol_wrapper(const char * const str, const int min, const int max, const int exit_upon_err, int *err) { int val; errno = 0; *err = FKO_SUCCESS; val = strtol(str, (char **) NULL, 10); if ((errno == ERANGE || (errno != 0 && val == 0))) { *err = errno; if(exit_upon_err == EXIT_UPON_ERR) { perror("strtol"); fprintf(stderr, "[*] Value %d out of range [(%d)-(%d)]\n", val, min, max); exit(EXIT_FAILURE); } } if(val < min) { *err = FKO_ERROR_INVALID_DATA_UTIL_STRTOL_LT_MIN; if(exit_upon_err == EXIT_UPON_ERR) { fprintf(stderr, "[*] Value %d out of range [(%d)-(%d)]\n", val, min, max); exit(EXIT_FAILURE); } } /* allow max == -1 to be an exception where we don't care about the * maximum - note that the ERANGE check is still in place above */ if((max >= 0) && (val > max)) { *err = FKO_ERROR_INVALID_DATA_UTIL_STRTOL_GT_MAX; if(exit_upon_err == EXIT_UPON_ERR) { fprintf(stderr, "[*] Value %d out of range [(%d)-(%d)]\n", val, min, max); exit(EXIT_FAILURE); } } #if HAVE_LIBFIU fiu_return_on("strtol_wrapper_lt_min", FKO_ERROR_INVALID_DATA_UTIL_STRTOL_LT_MIN); fiu_return_on("strtol_wrapper_gt_max", FKO_ERROR_INVALID_DATA_UTIL_STRTOL_GT_MAX); #endif return val; }
/* Return the fko SPA encrypted data. */ int fko_get_spa_data(fko_ctx_t ctx, char **spa_data) { #if HAVE_LIBFIU fiu_return_on("fko_get_spa_data_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(spa_data == NULL) return(FKO_ERROR_INVALID_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_spa_data_val", FKO_ERROR_INVALID_DATA); #endif /* We expect to have encrypted data to process. If not, we bail. */ if(ctx->encrypted_msg == NULL || ! is_valid_encoded_msg_len( strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE))) return(FKO_ERROR_MISSING_ENCODED_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_spa_data_encoded", FKO_ERROR_MISSING_ENCODED_DATA); #endif *spa_data = ctx->encrypted_msg; /* Notice we omit the first 10 bytes if Rijndael encryption is * used (to eliminate the consistent 'Salted__' string), and * in GnuPG mode we eliminate the consistent 'hQ' base64 encoded * prefix */ if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL) *spa_data += B64_RIJNDAEL_SALT_STR_LEN; else if(ctx->encryption_type == FKO_ENCRYPTION_GPG) *spa_data += B64_GPG_PREFIX_STR_LEN; return(FKO_SUCCESS); }
/* Validate plaintext input size */ int is_valid_pt_msg_len(const int len) { #if HAVE_LIBFIU fiu_return_on("is_valid_pt_msg_len_val", 0); #endif if(len < MIN_SPA_PLAINTEXT_MSG_SIZE || len >= MAX_SPA_PLAINTEXT_MSG_SIZE) return(0); return(1); }
/* Validate encoded message length */ int is_valid_encoded_msg_len(const int len) { #if HAVE_LIBFIU fiu_return_on("is_valid_encoded_msg_len_val", 0); #endif if(len < MIN_SPA_ENCODED_MSG_SIZE || len >= MAX_SPA_ENCODED_MSG_SIZE) return(0); return(1); }
int fko_get_spa_digest(fko_ctx_t ctx, char **md) { #if HAVE_LIBFIU fiu_return_on("fko_get_spa_digest_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); #if HAVE_LIBFIU fiu_return_on("fko_get_spa_digest_val", FKO_ERROR_INVALID_DATA); #endif if(md == NULL) return(FKO_ERROR_INVALID_DATA); *md = ctx->digest; return(FKO_SUCCESS); }
/* Set the SPA Server Auth data */ int fko_set_spa_server_auth(fko_ctx_t ctx, const char * const msg) { /**************************************** * --DSS This is not supported yet **************************************** */ //return(FKO_ERROR_UNSUPPORTED_FEATURE); #if HAVE_LIBFIU fiu_return_on("fko_set_spa_server_auth_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Context must be initialized. */ if(!CTX_INITIALIZED(ctx)) return FKO_ERROR_CTX_NOT_INITIALIZED; /* Gotta have a valid string. */ if(msg == NULL || strnlen(msg, MAX_SPA_SERVER_AUTH_SIZE) == 0) return(FKO_ERROR_INVALID_DATA_SRVAUTH_MISSING); /* --DSS XXX: Bail out for now. But consider just * truncating in the future... */ if(strnlen(msg, MAX_SPA_SERVER_AUTH_SIZE) == MAX_SPA_SERVER_AUTH_SIZE) return(FKO_ERROR_DATA_TOO_LARGE); /* --DSS TODO: ??? * Do we want to add message type and format checking here * or continue to leave it to the implementor? */ /**/ /* Just in case this is a subsquent call to this function. We * do not want to be leaking memory. */ if(ctx->server_auth != NULL) free(ctx->server_auth); ctx->server_auth = strdup(msg); ctx->state |= FKO_DATA_MODIFIED; if(ctx->server_auth == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); return(FKO_SUCCESS); }
int fko_set_raw_spa_digest(fko_ctx_t ctx) { #if HAVE_LIBFIU fiu_return_on("fko_set_raw_spa_digest_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); /* Must have encoded message data to start with. */ if(ctx->encrypted_msg == NULL) return(FKO_ERROR_MISSING_ENCODED_DATA); #if HAVE_LIBFIU fiu_return_on("fko_set_raw_spa_digest_val", FKO_ERROR_MISSING_ENCODED_DATA); #endif return set_digest(ctx->encrypted_msg, &ctx->raw_digest, ctx->raw_digest_type, &ctx->raw_digest_len); }
/* Return the SPA message data. */ int fko_get_spa_nat_access(fko_ctx_t ctx, char **nat_access) { #if HAVE_LIBFIU fiu_return_on("fko_get_spa_nat_access_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(nat_access == NULL) return(FKO_ERROR_INVALID_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_spa_nat_access_val", FKO_ERROR_INVALID_DATA); #endif *nat_access = ctx->nat_access; return(FKO_SUCCESS); }
/* Return the fko version */ int fko_get_version(fko_ctx_t ctx, char **version) { #if HAVE_LIBFIU fiu_return_on("fko_get_version_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(version == NULL) return(FKO_ERROR_INVALID_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_version_val", FKO_ERROR_INVALID_DATA); #endif *version = ctx->version; return(FKO_SUCCESS); }
/* Return the current timestamp. */ int fko_get_timestamp(fko_ctx_t ctx, time_t *timestamp) { #if HAVE_LIBFIU fiu_return_on("fko_get_timestamp_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(timestamp == NULL) return(FKO_ERROR_INVALID_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_timestamp_val", FKO_ERROR_INVALID_DATA); #endif *timestamp = ctx->timestamp; return(FKO_SUCCESS); }
/* Return the current username for this fko context. */ int fko_get_username(fko_ctx_t ctx, char **username) { #if HAVE_LIBFIU fiu_return_on("fko_get_username_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(username == NULL) return(FKO_ERROR_INVALID_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_username_val", FKO_ERROR_INVALID_DATA); #endif *username = ctx->username; return(FKO_SUCCESS); }
/* Return the SPA digest type. */ int fko_get_spa_digest_type(fko_ctx_t ctx, short *digest_type) { #if HAVE_LIBFIU fiu_return_on("fko_get_spa_digest_type_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); #if HAVE_LIBFIU fiu_return_on("fko_get_spa_digest_type_val", FKO_ERROR_INVALID_DATA); #endif if(digest_type == NULL) return(FKO_ERROR_INVALID_DATA); *digest_type = ctx->digest_type; return(FKO_SUCCESS); }
/* Return the SPA message data. */ int fko_get_spa_server_auth(fko_ctx_t ctx, char **server_auth) { #if HAVE_LIBFIU fiu_return_on("fko_get_spa_server_auth_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); if(server_auth == NULL) return(FKO_ERROR_INVALID_DATA); #if HAVE_LIBFIU fiu_return_on("fko_get_spa_server_auth_val", FKO_ERROR_INVALID_DATA); #endif *server_auth = ctx->server_auth; return(FKO_SUCCESS); }
/* Return the SPA digest type. */ int fko_get_raw_spa_digest_type(fko_ctx_t ctx, short *raw_digest_type) { #if HAVE_LIBFIU fiu_return_on("fko_get_raw_spa_digest_type_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); *raw_digest_type = ctx->raw_digest_type; return(FKO_SUCCESS); }
/* zero out a buffer before free() */ int zero_free(char *buf, int len) { int res = FKO_SUCCESS; if(buf == NULL) return res; if(len == 0) { free(buf); /* always free() if buf != NULL */ return res; } res = zero_buf(buf, len); free(buf); #if HAVE_LIBFIU fiu_return_on("zero_free_err", FKO_ERROR_ZERO_OUT_DATA); #endif return res; }
/* zero out sensitive information in a way that isn't optimized out by the compiler * since we force a comparision and return an error if there is a problem (though * the caller should do something with this information too). */ int zero_buf(char *buf, int len) { int i, res = FKO_SUCCESS; #if HAVE_LIBFIU fiu_return_on("zero_buf_err", FKO_ERROR_ZERO_OUT_DATA); #endif if(buf == NULL || len == 0) return res; if(len < 0 || len > MAX_SPA_ENCODED_MSG_SIZE) return FKO_ERROR_ZERO_OUT_DATA; for(i=0; i < len; i++) buf[i] = 0x0; for(i=0; i < len; i++) if(buf[i] != 0x0) res = FKO_ERROR_ZERO_OUT_DATA; return res; }
static int set_digest(char *data, char **digest, short digest_type, int *digest_len) { char *md = NULL; int data_len; data_len = strnlen(data, MAX_SPA_ENCODED_MSG_SIZE); #if HAVE_LIBFIU fiu_return_on("set_digest_toobig", FKO_ERROR_INVALID_DATA_ENCODE_DIGEST_TOOBIG); #endif if(data_len == MAX_SPA_ENCODED_MSG_SIZE) return(FKO_ERROR_INVALID_DATA_ENCODE_DIGEST_TOOBIG); #if HAVE_LIBFIU fiu_return_on("set_digest_invalidtype", FKO_ERROR_INVALID_DIGEST_TYPE); fiu_return_on("set_digest_calloc", FKO_ERROR_MEMORY_ALLOCATION); #endif switch(digest_type) { case FKO_DIGEST_MD5: md = calloc(1, MD_HEX_SIZE(MD5_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); md5_base64(md, (unsigned char*)data, data_len); *digest_len = MD5_B64_LEN; break; case FKO_DIGEST_SHA1: md = calloc(1, MD_HEX_SIZE(SHA1_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); sha1_base64(md, (unsigned char*)data, data_len); *digest_len = SHA1_B64_LEN; break; case FKO_DIGEST_SHA256: md = calloc(1, MD_HEX_SIZE(SHA256_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); sha256_base64(md, (unsigned char*)data, data_len); *digest_len = SHA256_B64_LEN; break; case FKO_DIGEST_SHA384: md = calloc(1, MD_HEX_SIZE(SHA384_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); sha384_base64(md, (unsigned char*)data, data_len); *digest_len = SHA384_B64_LEN; break; case FKO_DIGEST_SHA512: md = calloc(1, MD_HEX_SIZE(SHA512_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); sha512_base64(md, (unsigned char*)data, data_len); *digest_len = SHA512_B64_LEN; break; case FKO_DIGEST_SHA3_256: md = calloc(1, MD_HEX_SIZE(SHA3_256_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); sha3_256_base64(md, (unsigned char*)data, data_len); *digest_len = SHA3_256_B64_LEN; break; case FKO_DIGEST_SHA3_512: md = calloc(1, MD_HEX_SIZE(SHA3_512_DIGEST_LEN)+1); if(md == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); sha3_512_base64(md, (unsigned char*)data, data_len); *digest_len = SHA3_512_B64_LEN; break; default: return(FKO_ERROR_INVALID_DIGEST_TYPE); } /* Just in case this is a subsequent call to this function. We * do not want to be leaking memory. */ if(*digest != NULL) free(*digest); *digest = md; return(FKO_SUCCESS); }
int fw_config_init(fko_srv_options_t * const opts) { memset(&fwc, 0x0, sizeof(struct fw_config)); /* Set our firewall exe command path (iptables in most cases). */ strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], sizeof(fwc.fw_command)); #if HAVE_LIBFIU fiu_return_on("fw_config_init", 0); #endif /* Pull the fwknop chain config info and setup our internal * config struct. The IPT_INPUT is the only one that is * required. The rest are optional. */ if(set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]) != 1) return 0; /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS == Y */ if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0) if(set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]) != 1) return 0; /* The remaining access chains require ENABLE_IPT_FORWARDING = Y */ if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0) { if(set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]) != 1) return 0; if(set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]) != 1) return 0; /* Requires ENABLE_IPT_SNAT = Y */ if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0) { if(set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]) != 1) return 0; if(set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]) != 1) return 0; } } if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0) { fwc.use_destination = 1; } /* Let us find it via our opts struct as well. */ opts->fw_config = &fwc; return 1; }
/* Get or Set the username for the fko context spa data. */ int fko_set_username(fko_ctx_t ctx, const char * const spoof_user) { char *username = NULL; int res = FKO_SUCCESS, is_user_heap_allocated=0; #if HAVE_LIBFIU fiu_return_on("fko_set_username_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) return FKO_ERROR_CTX_NOT_INITIALIZED; /* If spoof_user was not passed in, check for a SPOOF_USER enviroment * variable. If it is set, use its value. */ if(spoof_user != NULL && spoof_user[0] != '\0') { #if HAVE_LIBFIU fiu_return_on("fko_set_username_strdup", FKO_ERROR_MEMORY_ALLOCATION); #endif username = strdup(spoof_user); if(username == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); is_user_heap_allocated = 1; } else username = getenv("SPOOF_USER"); /* Try to get the username from the system. */ if(username == NULL) { /* Since we've already tried looking at an env variable, try * LOGNAME next (and the cuserid() man page recommends this) */ if((username = getenv("LOGNAME")) == NULL) { #ifdef _XOPEN_SOURCE /* cuserid will return the effective user (i.e. su or setuid). */ username = cuserid(NULL); #else username = getlogin(); #endif /* if we still didn't get a username, continue falling back */ if(username == NULL) { if((username = getenv("USER")) == NULL) { username = strdup("NO_USER"); if(username == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); is_user_heap_allocated = 1; } } } } /* Truncate the username if it is too long. */ if(strnlen(username, MAX_SPA_USERNAME_SIZE) == MAX_SPA_USERNAME_SIZE) *(username + MAX_SPA_USERNAME_SIZE - 1) = '\0'; if((res = validate_username(username)) != FKO_SUCCESS) { if(is_user_heap_allocated == 1) free(username); #if HAVE_LIBFIU fiu_return_on("fko_set_username_valuser", FKO_ERROR_INVALID_DATA); #endif return res; } /* Just in case this is a subsquent call to this function. We * do not want to be leaking memory. */ if(ctx->username != NULL) free(ctx->username); ctx->username = strdup(username); ctx->state |= FKO_DATA_MODIFIED; if(is_user_heap_allocated == 1) free(username); if(ctx->username == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); return(FKO_SUCCESS); }
/* Set the SPA Nat Access data */ int fko_set_spa_nat_access(fko_ctx_t ctx, const char * const msg) { int res = FKO_SUCCESS; #if HAVE_LIBFIU fiu_return_on("fko_set_spa_nat_access_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Context must be initialized. */ if(!CTX_INITIALIZED(ctx)) return FKO_ERROR_CTX_NOT_INITIALIZED; /* Gotta have a valid string. */ if(msg == NULL || strnlen(msg, MAX_SPA_NAT_ACCESS_SIZE) == 0) return(FKO_ERROR_INVALID_DATA_NAT_EMPTY); #if HAVE_LIBFIU fiu_return_on("fko_set_spa_nat_access_empty", FKO_ERROR_INVALID_DATA_NAT_EMPTY); #endif /* --DSS XXX: Bail out for now. But consider just * truncating in the future... */ if(strnlen(msg, MAX_SPA_NAT_ACCESS_SIZE) == MAX_SPA_NAT_ACCESS_SIZE) return(FKO_ERROR_DATA_TOO_LARGE); #if HAVE_LIBFIU fiu_return_on("fko_set_spa_nat_access_large", FKO_ERROR_DATA_TOO_LARGE); #endif if((res = validate_nat_access_msg(msg)) != FKO_SUCCESS) return(res); /* Just in case this is a subsequent call to this function. We * do not want to be leaking memory. */ if(ctx->nat_access != NULL) free(ctx->nat_access); ctx->nat_access = strdup(msg); ctx->state |= FKO_DATA_MODIFIED; if(ctx->nat_access == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); /* If we set the nat_access message Then we force the message_type * as well. Technically, the message type should be set already. * This will serve a half-protective measure. * --DSS XXX: should do this better. */ if(ctx->client_timeout > 0) { if(ctx->message_type != FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG) ctx->message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG; } else if(ctx->message_type != FKO_LOCAL_NAT_ACCESS_MSG && ctx->message_type != FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG) ctx->message_type = FKO_NAT_ACCESS_MSG; return(FKO_SUCCESS); }
/* Initialize an fko context. */ int fko_new(fko_ctx_t *r_ctx) { fko_ctx_t ctx = NULL; int res; char *ver; #if HAVE_LIBFIU fiu_return_on("fko_new_calloc", FKO_ERROR_MEMORY_ALLOCATION); #endif ctx = calloc(1, sizeof *ctx); if(ctx == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); /* Set default values and state. * * Note: We initialize the context early so that the fko_set_xxx * functions can operate properly. If there are any problems during * initialization, then fko_destroy() is called which will clean up * the context. */ ctx->initval = FKO_CTX_INITIALIZED; /* Set the version string. */ ver = strdup(FKO_PROTOCOL_VERSION); if(ver == NULL) { fko_destroy(ctx); ctx = NULL; return(FKO_ERROR_MEMORY_ALLOCATION); } ctx->version = ver; /* Rand value. */ res = fko_set_rand_value(ctx, NULL); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Username. */ res = fko_set_username(ctx, NULL); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Timestamp. */ res = fko_set_timestamp(ctx, 0); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Default Digest Type. */ res = fko_set_spa_digest_type(ctx, FKO_DEFAULT_DIGEST); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Default Message Type. */ res = fko_set_spa_message_type(ctx, FKO_DEFAULT_MSG_TYPE); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Default Encryption Type. */ res = fko_set_spa_encryption_type(ctx, FKO_DEFAULT_ENCRYPTION); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Default is Rijndael in CBC mode */ res = fko_set_spa_encryption_mode(ctx, FKO_DEFAULT_ENC_MODE); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } #if HAVE_LIBGPGME /* Set gpg signature verify on. */ ctx->verify_gpg_sigs = 1; #endif /* HAVE_LIBGPGME */ FKO_SET_CTX_INITIALIZED(ctx); *r_ctx = ctx; return(FKO_SUCCESS); }
/* Set/Generate the SPA data random value string. */ int fko_set_rand_value(fko_ctx_t ctx, const char * const new_val) { #ifdef WIN32 struct _timeb tb; #else FILE *rfd; struct timeval tv; size_t amt_read; #endif unsigned long seed; char *tmp_buf; #if HAVE_LIBFIU fiu_return_on("fko_set_rand_value_init", FKO_ERROR_CTX_NOT_INITIALIZED); #endif /* Context must be initialized. */ if(!CTX_INITIALIZED(ctx)) return FKO_ERROR_CTX_NOT_INITIALIZED; /* If a valid value was given, use it and return happy. */ if(new_val != NULL) { #if HAVE_LIBFIU fiu_return_on("fko_set_rand_value_lenval", FKO_ERROR_INVALID_DATA_RAND_LEN_VALIDFAIL); #endif if(strnlen(new_val, FKO_RAND_VAL_SIZE+1) != FKO_RAND_VAL_SIZE) return(FKO_ERROR_INVALID_DATA_RAND_LEN_VALIDFAIL); if(ctx->rand_val != NULL) free(ctx->rand_val); #if HAVE_LIBFIU fiu_return_on("fko_set_rand_value_strdup", FKO_ERROR_MEMORY_ALLOCATION); #endif ctx->rand_val = strdup(new_val); if(ctx->rand_val == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); ctx->state |= FKO_DATA_MODIFIED; return(FKO_SUCCESS); } #ifdef WIN32 _ftime_s(&tb); seed = ((tb.time * 1000) + tb.millitm) & 0xFFFFFFFF; #else /* Attempt to read seed data from /dev/urandom. If that does not * work, then fall back to a time-based method (less secure, but * probably more portable). */ if((rfd = fopen(RAND_FILE, "r")) != NULL) { /* Read seed from /dev/urandom */ amt_read = fread(&seed, 4, 1, rfd); fclose(rfd); #if HAVE_LIBFIU fiu_return_on("fko_set_rand_value_read", FKO_ERROR_FILESYSTEM_OPERATION); #endif if (amt_read != 1) return(FKO_ERROR_FILESYSTEM_OPERATION); } else { /* Seed based on time (current usecs). */ gettimeofday(&tv, NULL); seed = tv.tv_usec; } #endif srand(seed); if(ctx->rand_val != NULL) free(ctx->rand_val); #if HAVE_LIBFIU fiu_return_on("fko_set_rand_value_calloc1", FKO_ERROR_MEMORY_ALLOCATION); #endif ctx->rand_val = calloc(1, FKO_RAND_VAL_SIZE+1); if(ctx->rand_val == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); #if HAVE_LIBFIU fiu_return_on("fko_set_rand_value_calloc2", FKO_ERROR_MEMORY_ALLOCATION); #endif tmp_buf = calloc(1, FKO_RAND_VAL_SIZE+1); if(tmp_buf == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); snprintf(ctx->rand_val, FKO_RAND_VAL_SIZE, "%u", rand()); while(strnlen(ctx->rand_val, FKO_RAND_VAL_SIZE+1) < FKO_RAND_VAL_SIZE) { snprintf(tmp_buf, FKO_RAND_VAL_SIZE, "%u", rand()); strlcat(ctx->rand_val, tmp_buf, FKO_RAND_VAL_SIZE+1); } free(tmp_buf); ctx->state |= FKO_DATA_MODIFIED; return(FKO_SUCCESS); }
/* Initialize an fko context with external (encrypted/encoded) data. * This is used to create a context with the purpose of decoding * and parsing the provided data into the context data. */ int fko_new_with_data(fko_ctx_t *r_ctx, const char * const enc_msg, const char * const dec_key, const int dec_key_len, int encryption_mode, const char * const hmac_key, const int hmac_key_len, const int hmac_type) { fko_ctx_t ctx = NULL; int res = FKO_SUCCESS; /* Are we optimistic or what? */ int enc_msg_len; #if HAVE_LIBFIU fiu_return_on("fko_new_with_data_msg", FKO_ERROR_INVALID_DATA_FUNCS_NEW_ENCMSG_MISSING); #endif if(enc_msg == NULL) return(FKO_ERROR_INVALID_DATA_FUNCS_NEW_ENCMSG_MISSING); #if HAVE_LIBFIU fiu_return_on("fko_new_with_data_keylen", FKO_ERROR_INVALID_KEY_LEN); #endif if(dec_key_len < 0 || hmac_key_len < 0) return(FKO_ERROR_INVALID_KEY_LEN); ctx = calloc(1, sizeof *ctx); if(ctx == NULL) return(FKO_ERROR_MEMORY_ALLOCATION); enc_msg_len = strnlen(enc_msg, MAX_SPA_ENCODED_MSG_SIZE); if(! is_valid_encoded_msg_len(enc_msg_len)) { free(ctx); return(FKO_ERROR_INVALID_DATA_FUNCS_NEW_MSGLEN_VALIDFAIL); } /* First, add the data to the context. */ ctx->encrypted_msg = strdup(enc_msg); ctx->encrypted_msg_len = enc_msg_len; if(ctx->encrypted_msg == NULL) { free(ctx); return(FKO_ERROR_MEMORY_ALLOCATION); } /* Default Encryption Mode (Rijndael in CBC mode) */ ctx->initval = FKO_CTX_INITIALIZED; res = fko_set_spa_encryption_mode(ctx, encryption_mode); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* HMAC digest type */ res = fko_set_spa_hmac_type(ctx, hmac_type); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Check HMAC if the access stanza had an HMAC key */ if(hmac_key_len > 0 && hmac_key != NULL) res = fko_verify_hmac(ctx, hmac_key, hmac_key_len); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; return res; } /* Consider it initialized here. */ FKO_SET_CTX_INITIALIZED(ctx); /* If a decryption key is provided, go ahead and decrypt and decode. */ if(dec_key != NULL) { res = fko_decrypt_spa_data(ctx, dec_key, dec_key_len); if(res != FKO_SUCCESS) { fko_destroy(ctx); ctx = NULL; *r_ctx = NULL; /* Make sure the caller ctx is null just in case */ return(res); } } #if HAVE_LIBGPGME /* Set gpg signature verify on. */ ctx->verify_gpg_sigs = 1; #endif /* HAVE_LIBGPGME */ *r_ctx = ctx; return(res); }