return(FKO_SUCCESS);
}
+/* For replay attack detection
+*/
+static int
+get_raw_digest(char **digest, char *pkt_data)
+{
+ fko_ctx_t ctx = NULL;
+ char *tmp_digest = NULL;
+ int res = FKO_SUCCESS;
+
+ /* initialize an FKO context with no decryption key just so
+ * we can get the outer message digest
+ */
+ res = fko_new_with_data(&ctx, (char *)pkt_data, NULL);
+ if(res != FKO_SUCCESS)
+ {
+ log_msg(LOG_WARNING, "Error initializing FKO context from SPA data: %s",
+ fko_errstr(res));
+ fko_destroy(ctx);
+ return(SPA_MSG_FKO_CTX_ERROR);
+ }
+
+ res = fko_set_raw_spa_digest_type(ctx, FKO_DEFAULT_DIGEST);
+ if(res != FKO_SUCCESS)
+ {
+ log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
+ fko_errstr(res));
+ fko_destroy(ctx);
+ return(SPA_MSG_DIGEST_ERROR);
+ }
+
+ res = fko_set_raw_spa_digest(ctx);
+ if(res != FKO_SUCCESS)
+ {
+ log_msg(LOG_WARNING, "Error setting digest for SPA data: %s",
+ fko_errstr(res));
+ fko_destroy(ctx);
+ return(SPA_MSG_DIGEST_ERROR);
+ }
+
+ res = fko_get_raw_spa_digest(ctx, &tmp_digest);
+ if(res != FKO_SUCCESS)
+ {
+ log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
+ fko_errstr(res));
+ fko_destroy(ctx);
+ return(SPA_MSG_DIGEST_ERROR);
+ }
+
+ *digest = strdup(tmp_digest);
+
+ if (digest == NULL)
+ return SPA_MSG_ERROR;
+
+ fko_destroy(ctx);
+ return res;
+}
+
+
/* Popluate a spa_data struct from an initialized (and populated) FKO context.
*/
static int
*/
fko_ctx_t ctx = NULL;
- char *spa_ip_demark, *gpg_id;
+ char *spa_ip_demark, *gpg_id, *raw_digest = NULL;
time_t now_ts;
- int res, status, ts_diff, enc_type, found_acc_sip=0, stanza_num=0;
+ int res, status, ts_diff, enc_type, stanza_num=0;
+ int added_replay_digest = 0;
spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
/* Check for a replay attack
*/
- if (is_replay(opts, spa_pkt->packet_data) != SPA_MSG_SUCCESS)
+ res = get_raw_digest(&raw_digest, (char *)spa_pkt->packet_data);
+ if(res != FKO_SUCCESS)
+ {
+ if (raw_digest != NULL)
+ free(raw_digest);
+ return;
+ }
+ if (raw_digest == NULL)
+ return;
+
+ if (is_replay(opts, raw_digest) != SPA_MSG_SUCCESS)
return;
}
else
continue;
}
- found_acc_sip = 1;
-
log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
stanza_num, spadat.pkt_source_ip);
continue;
}
- /* Do we have a valid FKO context?
+ /* Do we have a valid FKO context? Did the SPA decrypt properly?
*/
if(res != FKO_SUCCESS)
{
continue;
}
+ /* Add this SPA packet into the replay detection cache
+ */
+ if (! added_replay_digest)
+ {
+ res = add_replay(opts, raw_digest);
+ if (res != SPA_MSG_SUCCESS)
+ {
+ log_msg(LOG_WARNING, "(stanza #%d) Could not add digest to replay cache",
+ stanza_num);
+ if(ctx != NULL)
+ fko_destroy(ctx);
+ acc = acc->next;
+ continue;
+ }
+ added_replay_digest = 1;
+ }
+
/* At this point, we assume the SPA data is valid. Now we need to see
* if it meets our access criteria.
*/
break;
}
- if(! found_acc_sip)
- {
- log_msg(LOG_WARNING,
- "No access data found for source IP: %s", spadat.pkt_source_ip
- );
- }
+ if (raw_digest != NULL)
+ free(raw_digest);
return;
}
#define DATE_LEN 18
#define MAX_DIGEST_SIZE 64
-static int
-get_raw_digest(char **digest, char *pkt_data)
-{
- fko_ctx_t ctx = NULL;
- char *tmp_digest = NULL;
- int res = FKO_SUCCESS;
-
- /* initialize an FKO context with no decryption key just so
- * we can get the outer message digest
- */
- res = fko_new_with_data(&ctx, (char *)pkt_data, NULL);
- if(res != FKO_SUCCESS)
- {
- log_msg(LOG_WARNING, "Error initializing FKO context from SPA data: %s",
- fko_errstr(res));
- fko_destroy(ctx);
- return(SPA_MSG_FKO_CTX_ERROR);
- }
-
- res = fko_set_raw_spa_digest_type(ctx, FKO_DEFAULT_DIGEST);
- if(res != FKO_SUCCESS)
- {
- log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
- fko_errstr(res));
- fko_destroy(ctx);
- return(SPA_MSG_DIGEST_ERROR);
- }
-
- res = fko_set_raw_spa_digest(ctx);
- if(res != FKO_SUCCESS)
- {
- log_msg(LOG_WARNING, "Error setting digest for SPA data: %s",
- fko_errstr(res));
- fko_destroy(ctx);
- return(SPA_MSG_DIGEST_ERROR);
- }
-
- res = fko_get_raw_spa_digest(ctx, &tmp_digest);
- if(res != FKO_SUCCESS)
- {
- log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
- fko_errstr(res));
- fko_destroy(ctx);
- return(SPA_MSG_DIGEST_ERROR);
- }
-
- *digest = strdup(tmp_digest);
-
- if (digest == NULL)
- return SPA_MSG_ERROR;
-
- fko_destroy(ctx);
- return res;
-}
-
/* Rotate the digest file by simply renaming it.
*/
static void
#endif /* USE_FILE_CACHE */
/* Take an fko context, pull the digest and use it as the key to check the
- * replay db (digest cache). Returns 1 if there was a match (a replay),
- * 0 for no match, and -1 on error.
+ * replay db (digest cache).
*/
int
-is_replay(fko_srv_options_t *opts, unsigned char *pkt_data)
+is_replay(fko_srv_options_t *opts, char *digest)
{
#ifdef NO_DIGEST_CACHE
return(-1);
#else
#if USE_FILE_CACHE
- return is_replay_file_cache(opts, pkt_data);
+ return is_replay_file_cache(opts, digest);
#else
- return is_replay_dbm_cache(opts, pkt_data);
+ return is_replay_dbm_cache(opts, digest);
#endif
#endif /* NO_DIGEST_CACHE */
}
-#if USE_FILE_CACHE
int
-is_replay_file_cache(fko_srv_options_t *opts, unsigned char *pkt_data)
+add_replay(fko_srv_options_t *opts, char *digest)
{
- char *digest = NULL;
- char src_ip[INET_ADDRSTRLEN+1] = {0};
- char dst_ip[INET_ADDRSTRLEN+1] = {0};
- int res = 0, digest_len = 0;
- FILE *digest_file_ptr = NULL;
-
- struct digest_cache_list *digest_list_ptr = NULL, *digest_elm = NULL;
+#ifdef NO_DIGEST_CACHE
+ return(-1);
+#else
- res = get_raw_digest(&digest, (char *)pkt_data);
+#if USE_FILE_CACHE
+ return add_replay_file_cache(opts, digest);
+#else
+ return add_replay_dbm_cache(opts, digest);
+#endif
+#endif /* NO_DIGEST_CACHE */
+}
- if(res != FKO_SUCCESS)
- {
- if (digest != NULL)
- free(digest);
- return res;
- }
+#if USE_FILE_CACHE
+int
+is_replay_file_cache(fko_srv_options_t *opts, char *digest)
+{
+ int digest_len = 0;
- if (digest == NULL)
- return SPA_MSG_ERROR;
+ struct digest_cache_list *digest_list_ptr = NULL;
digest_len = strlen(digest);
replay_warning(opts, &(digest_list_ptr->cache_info));
- free(digest);
return(SPA_MSG_REPLAY);
}
}
+ return(SPA_MSG_SUCCESS);
+}
+
+int
+add_replay_file_cache(fko_srv_options_t *opts, char *digest)
+{
+ FILE *digest_file_ptr = NULL;
+ int digest_len = 0;
+ char src_ip[INET_ADDRSTRLEN+1] = {0};
+ char dst_ip[INET_ADDRSTRLEN+1] = {0};
+
+ struct digest_cache_list *digest_elm = NULL;
+
+ digest_len = strlen(digest);
- /* If we make it here, then this is a new SPA packet that needs to be
- * added to the cache. We've already decrypted the data, so we know that
- * the contents are valid.
- */
if ((digest_elm = calloc(1, sizeof(struct digest_cache_list))) == NULL)
{
log_msg(LOG_WARNING, "Error calloc() returned NULL for digest cache element",
fko_errstr(SPA_MSG_ERROR));
- free(digest);
return(SPA_MSG_ERROR);
}
if ((digest_elm->cache_info.digest = calloc(1, digest_len+1)) == NULL)
log_msg(LOG_WARNING, "Error calloc() returned NULL for digest cache string",
fko_errstr(SPA_MSG_ERROR));
free(digest_elm);
- free(digest);
return(SPA_MSG_ERROR);
}
{
log_msg(LOG_WARNING, "Could not open digest cache: %s",
opts->config[CONF_DIGEST_FILE]);
- free(digest);
return(SPA_MSG_DIGEST_CACHE_ERROR);
}
fclose(digest_file_ptr);
- free(digest);
return(SPA_MSG_SUCCESS);
}
#endif /* USE_FILE_CACHE */
#if !USE_FILE_CACHE
int
-is_replay_dbm_cache(fko_srv_options_t *opts, unsigned char *pkt_data)
+is_replay_dbm_cache(fko_srv_options_t *opts, char *digest)
{
#ifdef NO_DIGEST_CACHE
return 0;
datum db_key, db_ent;
char *digest = NULL;
- int digest_len, res;
+ int digest_len, res = SPA_MSG_SUCCESS;
digest_cache_info_t dc_info;
- res = get_raw_digest(&digest, (char *)pkt_data);
-
- if(res != FKO_SUCCESS)
- {
- if (digest != NULL)
- free(digest);
- return res;
- }
-
- if (digest == NULL)
- return SPA_MSG_ERROR;
-
digest_len = strlen(digest);
db_key.dptr = digest;
MY_DBM_STRERROR(errno)
);
- free(digest);
return(SPA_MSG_DIGEST_CACHE_ERROR);
}
#ifdef HAVE_LIBGDBM
free(db_ent.dptr);
#endif
-
res = SPA_MSG_REPLAY;
- } else {
+ }
+
+ MY_DBM_CLOSE(rpdb);
+
+ return(res);
+#endif /* NO_DIGEST_CACHE */
+}
+
+int
+add_replay_dbm_cache(fko_srv_options_t *opts, char *digest)
+{
+#ifdef NO_DIGEST_CACHE
+ return 0;
+#else
+
+#ifdef HAVE_LIBGDBM
+ GDBM_FILE rpdb;
+#elif HAVE_LIBNDBM
+ DBM *rpdb;
+#endif
+ datum db_key, db_ent;
+
+ char *digest = NULL;
+ int digest_len, res = SPA_MSG_SUCCESS;
+
+ digest_cache_info_t dc_info;
+
+ digest_len = strlen(digest);
+
+ db_key.dptr = digest;
+ db_key.dsize = digest_len;
+
+ /* Check the db for the key
+ */
+#ifdef HAVE_LIBGDBM
+ rpdb = gdbm_open(
+ opts->config[CONF_DIGEST_DB_FILE], 512, GDBM_WRCREAT, S_IRUSR|S_IWUSR, 0
+ );
+#elif HAVE_LIBNDBM
+ rpdb = dbm_open(opts->config[CONF_DIGEST_DB_FILE], O_RDWR, 0);
+#endif
+
+ if(!rpdb)
+ {
+ log_msg(LOG_WARNING, "Error opening digest_cache: '%s': %s",
+ opts->config[CONF_DIGEST_DB_FILE],
+ MY_DBM_STRERROR(errno)
+ );
+
+ return(SPA_MSG_DIGEST_CACHE_ERROR);
+ }
+
+ db_ent = MY_DBM_FETCH(rpdb, db_key);
+
+ /* If the datum is null, we have a new entry.
+ */
+ if(db_ent.dptr == NULL)
+ {
/* This is a new SPA packet that needs to be added to the cache.
*/
dc_info.src_ip = opts->spa_pkt.packet_src_ip;
res = SPA_MSG_SUCCESS;
}
+ else
+ res = SPA_MSG_DIGEST_CACHE_ERROR;
MY_DBM_CLOSE(rpdb);
- free(digest);
return(res);
#endif /* NO_DIGEST_CACHE */
-}
+
#endif /* USE_FILE_CACHE */
#if USE_FILE_CACHE