diff --git a/ChangeLog b/ChangeLog index 4f3efd7d..8eeecb20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,9 @@ fwknop-2.6.1 (//2014): - [libfko] Better SPA packet dumping output to include GnuPG specifics whenever SPA packets are encrypted/authenticated via GnuPG. + - [server] Validate SPA packet GnuPG signatures with the libfko + fko_gpg_signature_id_match() function instead of server code doing this + independently. - [client+server] Add --gpg-exe command line argument and GPG_EXE config variable to ~/.fwknoprc and the access.conf file so that the path to GnuPG can be changed from the default /usr/bin/gpg path. diff --git a/lib/fko_encryption.c b/lib/fko_encryption.c index dad47a6f..8803ceaf 100644 --- a/lib/fko_encryption.c +++ b/lib/fko_encryption.c @@ -1102,6 +1102,7 @@ fko_gpg_signature_id_match(fko_ctx_t ctx, const char * const id, { #if HAVE_LIBGPGME char *curr_id; + int rv = FKO_SUCCESS; /* Must be initialized */ @@ -1123,7 +1124,9 @@ fko_gpg_signature_id_match(fko_ctx_t ctx, const char * const id, if(ctx->gpg_sigs == NULL) return(FKO_ERROR_GPGME_NO_SIGNATURE); - fko_get_gpg_signature_id(ctx, &curr_id); + rv = fko_get_gpg_signature_id(ctx, &curr_id); + if(rv != FKO_SUCCESS) + return rv; *result = strcmp(id, curr_id) == 0 ? 1 : 0; diff --git a/server/access.c b/server/access.c index 0314021d..1dcc0f7f 100644 --- a/server/access.c +++ b/server/access.c @@ -1641,23 +1641,6 @@ cleanup_and_bail: return(res); } -/* Take a GPG ID string and check it against the list of allowed - * GPG_REMOTE_ID's. - * - * Return 1 if we are allowed -*/ -int -acc_check_gpg_remote_id(acc_stanza_t *acc, const char *gpg_id) -{ - acc_string_list_t *ndx; - - for(ndx = acc->gpg_remote_id_list; ndx != NULL; ndx=ndx->next) - if(strcasecmp(ndx->str, gpg_id) == 0) - return(1); - - return(0); -} - /* Dump the configuration */ void diff --git a/server/access.h b/server/access.h index b5941709..62289deb 100644 --- a/server/access.h +++ b/server/access.h @@ -43,7 +43,6 @@ void parse_access_file(fko_srv_options_t *opts); int compare_addr_list(acc_int_list_t *source_list, const uint32_t ip); int acc_check_port_access(acc_stanza_t *acc, char *port_str); -int acc_check_gpg_remote_id(acc_stanza_t *acc, const char *gpg_id); void dump_access_list(const fko_srv_options_t *opts); int expand_acc_port_list(acc_port_list_t **plist, char *plist_str); void free_acc_stanzas(fko_srv_options_t *opts); diff --git a/server/incoming_spa.c b/server/incoming_spa.c index fb2922ba..17fbd527 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -143,6 +143,7 @@ get_raw_digest(char **digest, char *pkt_data) fko_ctx_t ctx = NULL; char *tmp_digest = NULL; int res = FKO_SUCCESS; + short raw_digest_type = -1; /* initialize an FKO context with no decryption key just so * we can get the outer message digest @@ -169,6 +170,27 @@ get_raw_digest(char **digest, char *pkt_data) return(SPA_MSG_DIGEST_ERROR); } + res = fko_get_raw_spa_digest_type(ctx, &raw_digest_type); + if(res != FKO_SUCCESS) + { + log_msg(LOG_WARNING, "Error getting digest type for SPA data: %s", + fko_errstr(res)); + fko_destroy(ctx); + ctx = NULL; + return(SPA_MSG_DIGEST_ERROR); + } + + /* Make sure the digest type is what we expect + */ + if(raw_digest_type != FKO_DEFAULT_DIGEST) + { + log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s", + fko_errstr(res)); + fko_destroy(ctx); + ctx = NULL; + return(SPA_MSG_DIGEST_ERROR); + } + res = fko_set_raw_spa_digest(ctx); if(res != FKO_SUCCESS) { @@ -285,7 +307,9 @@ incoming_spa(fko_srv_options_t *opts) /* Loop through all access stanzas looking for a match */ - acc_stanza_t *acc = opts->acc_stanzas; + acc_stanza_t *acc = opts->acc_stanzas; + acc_string_list_t *gpg_id_ndx; + unsigned char is_gpg_match = 0; inet_ntop(AF_INET, &(spa_pkt->packet_src_ip), spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); @@ -593,13 +617,34 @@ incoming_spa(fko_srv_options_t *opts) log_msg(LOG_INFO, "[%s] (stanza #%d) Incoming SPA data signed by '%s'.", spadat.pkt_source_ip, stanza_num, gpg_id); - if(acc->gpg_remote_id != NULL && !acc_check_gpg_remote_id(acc, gpg_id)) + if(acc->gpg_remote_id != NULL) { - log_msg(LOG_WARNING, - "[%s] (stanza #%d) Incoming SPA packet signed by ID: %s, but that ID is not the GPG_REMOTE_ID list.", - spadat.pkt_source_ip, stanza_num, gpg_id); - acc = acc->next; - continue; + is_gpg_match = 0; + for(gpg_id_ndx = acc->gpg_remote_id_list; + gpg_id_ndx != NULL; gpg_id_ndx=gpg_id_ndx->next) + { + res = fko_gpg_signature_id_match(ctx, + gpg_id_ndx->str, &is_gpg_match); + if(res != FKO_SUCCESS) + { + log_msg(LOG_WARNING, + "[%s] (stanza #%d) Error in GPG siganture comparision: %s", + spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx)); + acc = acc->next; + continue; + } + if(is_gpg_match) + break; + } + + if(! is_gpg_match) + { + log_msg(LOG_WARNING, + "[%s] (stanza #%d) Incoming SPA packet signed by ID: %s, but that ID is not the GPG_REMOTE_ID list.", + spadat.pkt_source_ip, stanza_num, gpg_id); + acc = acc->next; + continue; + } } }