Added the GPG signature checking code. Added GPG_REQUIRE_SIG and GPG_IGNORE_SIG_VERIFY_ERROR parameters to access.conf. Implement the checking of GPG signature IDs against the GPG_REOMOTE_ID list.

git-svn-id: file:///home/mbr/svn/fwknop/trunk@227 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
Damien Stuart
2010-06-29 02:40:59 +00:00
parent b7ede1625d
commit b217c6a1fa
7 changed files with 150 additions and 71 deletions

View File

@@ -342,7 +342,7 @@ directive starts a new stanza.
data. This variable is optional and if not specified, the username data
in the SPA data is ignored.
*REQUIRE_SOURCE_ADDRESS:* '<Y/N>'::
*REQUIRE_SOURCE_ADDRESS*: '<Y/N>'::
Force all SPA packets to contain a real IP address within the
encrypted data. This makes it impossible to use the *-s* command
line argument on the *fwknop* client command line, so either *-R* has
@@ -376,12 +376,25 @@ directive starts a new stanza.
``GPG_DECRYPT_ID'' above. This is a required field for gpg-based
authentication.
*GPG_REQUIRE_SIG*: '<Y/N>'::
With this setting set to 'Y', fwknopd check all GPG-encrypted SPA
messages for a signature (signed by the sender's key). If the incoming
message is not signed, the decryption process will fail. If not set, the
default is 'N'.
*GPG_IGNORE_SIG_VERIFY_ERROR*: '<Y/N>'::
Setting this will allow fwknopd to accept incoming GPG-encrypted packets
that are signed, but the signature did not pass verification (i.e. the
signer key was expired, etc.). This setting only applies if the
GPG_REQUIRE_SIG is also set to 'Y'.
*GPG_REMOTE_ID*: '<keyID,...,keyID>'::
Define a list of gpg key ID's that are required to have signed
any incoming SPA message that has been encrypted with the
*fwknopd* server key. This ensures that the verification of the
remote user is accomplished via a strong cryptographic
mechanism.
remote user is accomplished via a strong cryptographic mechanism.
This setting only applies if the ``GPG_REQUIRE_SIG'' is set to 'Y'.
Separate multiple entries with a comma.
FILES

View File

@@ -670,11 +670,12 @@ parse_access_file(fko_srv_options_t *opts)
*ndx = '\0';
/*
fprintf(stderr,
"ACCESS FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n",
opts->config[CONF_ACCESS_FILE], access_line_buf, var, val
);
*/
if(opts->verbose > 3)
fprintf(stderr,
"ACCESS FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n",
opts->config[CONF_ACCESS_FILE], access_line_buf, var, val
);
/* Process the entry.
*
@@ -781,6 +782,14 @@ parse_access_file(fko_srv_options_t *opts)
}
add_acc_string(&(curr_acc->gpg_decrypt_pw), val);
}
else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG"))
{
add_acc_bool(&(curr_acc->gpg_require_sig), val);
}
else if(CONF_VAR_IS(var, "GPG_IGNORE_SIG_VERIFY_ERROR"))
{
add_acc_bool(&(curr_acc->gpg_ignore_sig_error), val);
}
else if(CONF_VAR_IS(var, "GPG_REMOTE_ID"))
{
add_acc_string(&(curr_acc->gpg_remote_id), val);
@@ -956,6 +965,23 @@ 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, 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
@@ -979,18 +1005,20 @@ dump_access_list(fko_srv_options_t *opts)
fprintf(stderr,
"SOURCE (%i): %s\n"
"==============================================================\n"
" OPEN_PORTS: %s\n"
" RESTRICT_PORTS: %s\n"
" KEY: %s\n"
" FW_ACCESS_TIMEOUT: %i\n"
" ENABLE_CMD_EXEC: %s\n"
" CMD_EXEC_USER: %s\n"
" REQUIRE_USERNAME: %s\n"
" REQUIRE_SOURCE_ADDRESS: %s\n"
" GPG_HOME_DIR: %s\n"
" GPG_DECRYPT_ID: %s\n"
" GPG_DECRYPT_PW: %s\n"
" GPG_REMOTE_ID: %s\n",
" OPEN_PORTS: %s\n"
" RESTRICT_PORTS: %s\n"
" KEY: %s\n"
" FW_ACCESS_TIMEOUT: %i\n"
" ENABLE_CMD_EXEC: %s\n"
" CMD_EXEC_USER: %s\n"
" REQUIRE_USERNAME: %s\n"
" REQUIRE_SOURCE_ADDRESS: %s\n"
" GPG_HOME_DIR: %s\n"
" GPG_DECRYPT_ID: %s\n"
" GPG_DECRYPT_PW: %s\n"
" GPG_REQUIRE_SIG: %s\n"
"GPG_IGNORE_SIG_VERIFY_ERROR: %s\n"
" GPG_REMOTE_ID: %s\n",
++i,
acc->source,
(acc->open_ports == NULL) ? "<not set>" : acc->open_ports,
@@ -1004,6 +1032,8 @@ dump_access_list(fko_srv_options_t *opts)
(acc->gpg_home_dir == NULL) ? "<not set>" : acc->gpg_home_dir,
(acc->gpg_decrypt_id == NULL) ? "<not set>" : acc->gpg_decrypt_id,
(acc->gpg_decrypt_pw == NULL) ? "<not set>" : acc->gpg_decrypt_pw,
acc->gpg_require_sig ? "Yes" : "No",
acc->gpg_ignore_sig_error ? "Yes" : "No",
(acc->gpg_remote_id == NULL) ? "<not set>" : acc->gpg_remote_id
);

View File

@@ -134,16 +134,27 @@
# authentication.
#
# GPG_REQUIRE_SIG: <Y/N>;
#
# With this setting set to 'Y', fwknopd check all GPG-encrypted SPA
# messages for a signature (signed by the sender's key). If the incoming
# message is not signed, the decryption process will fail. If not set, the
# default is 'N'.
# GPG_IGNORE_SIG_VERIFY_ERROR: <Y/N>;
#
# Setting this will allow fwknopd to accept incoming GPG-encrypted packets
# that are signed, but the signature did not pass verification (i.e. the
# signer key was expired, etc.). This setting only applies if the
# GPG_REQUIRE_SIG is also set to 'Y'.
# GPG_REMOTE_ID: <keyID,...,keyID>;
#
# Define a list of gpg key IDs that are required to have signed any
# incoming SPA messages that have been encrypted with the fwknopd server
# key.
#
# This ensures that the verification of the remote user is accomplished
# via a strong cryptographic mechanism.
#
# Note that you can use either keyIDs or their corresponding email addresses.
# key. This ensures that the verification of the remote user is accomplished
# via a strong cryptographic mechanism. This setting only applies if the
# GPG_REQUIRE_SIG is set to 'Y'.
#
#### fwknopd access.conf stanzas ###

View File

@@ -34,6 +34,7 @@
void parse_access_file(fko_srv_options_t *opts);
acc_stanza_t* acc_check_source(fko_srv_options_t *opts, 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, char *gpg_id);
void dump_access_list(fko_srv_options_t *opts);
void expand_acc_port_list(acc_port_list_t **plist, char *plist_str);
void free_acc_port_list(acc_port_list_t *plist);

View File

@@ -2,12 +2,12 @@
.\" Title: fwknopd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 06/23/2010
.\" Manual:
.\" Source:
.\" Date: 06/28/2010
.\" Manual: Fwknop Server
.\" Source: Fwknop Server
.\" Language: English
.\"
.TH "FWKNOPD" "8" "06/23/2010" "" ""
.TH "FWKNOPD" "8" "06/28/2010" "Fwknop Server" "Fwknop Server"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
@@ -27,7 +27,7 @@ fwknopd \- Firewall Knock Operator Daemon
.sp
\fBfwknopd\fR is the server component for the FireWall Knock Operator, and is responsible for monitoring Single Packet Authorization (SPA) packets that are generated by \fBfwknop\fR clients, modifying a firewall or acl policy to allow the desired access after decrypting a valid SPA packet, and removing access after a configurable timeout\&. The main application of this program is to protect services such as \fISSH\fR with an additional layer of security in order to make the exploitation of vulnerabilities (both 0\-day and unpatched code) much more difficult\&.
.sp
The main configuration for \fBfwknopd\fR is maintained within two files: \fIfwknopd\&.conf\fR and \fIaccess\&.conf\fR\&. The default location for these files is determined at package configuration (typically \fI/etc/fwknop\fR)The configuration variables within these files are desribed below\&.
The main configuration for \fBfwknopd\fR is maintained within two files: \fIfwknopd\&.conf\fR and \fIaccess\&.conf\fR\&. The default location for these files is determined at package configuration (typically \fI<prefix>/etc/fwknop\fR)The configuration variables within these files are desribed below\&.
.SH "COMMAND-LINE OPTIONS"
.PP
\fB\-a, \-\-access\-file\fR=\fI<access\-file>\fR
@@ -36,8 +36,8 @@ Specify the location of the
\fIaccess\&.conf\fR
file\&. If this option is not given,
\fIfwkopd\fR
will use the default location (typically
\fI/etc/fwknop/access\&.conf\fR\&.
will use the compile\-time default location (typically
\fI<prefix>/etc/fwknop/access\&.conf\fR\&.
.RE
.PP
\fB\-c, \-\-config\fR=\fI<config\-file>\fR
@@ -47,7 +47,7 @@ Specify the location of the
file\&. If this option is not given,
\fIfwkopd\fR
will use the default location (typically
\fI/etc/fwknop/fwknopd\&.conf\fR\&.
\fI<prefix>/etc/fwknop/fwknopd\&.conf\fR\&.
.RE
.PP
\fB\-C, \-\-packet\-limit\fR=\fI<n>\fR
@@ -106,7 +106,8 @@ files\&. This will also force a flush of the current \(lqFWKNOP\(rq Netfilter ch
.PP
\fB\-\-rotate\-digest\-cache\fR
.RS 4
Rotate the digest cache file by renaming it to \(lq<name>\-old\(rq, and starting a new one\&.
Rotate the digest cache file by renaming it to \(lq<name>\-old\(rq, and starting a new one\&. The digest cache file is typically found in
\fI<prefix>/var/run/fwknop/digest\&.cache\fR\&.
.RE
.PP
\fB\-S, \-\-Status\fR
@@ -349,13 +350,6 @@ This gets used if AUTH_MODE is set to "FILE_PCAP"\&. This file must be created b
Define a comma\-separated set of IP addresses and/or networks that should be globally blacklisted\&. That is, any SPA packet that is from a source IP (or has an internal \-\-allow\-ip) within a blacklisted network will be ignored\&.
.RE
.PP
\fBMAX_HOPS\fR \fI<num_hops>\fR
.RS 4
TTL values are decremented depending on the number of hops the packet has taken before it hits the firewall\&. We will assume packets will not jump through more than
\fInum_hops\fR
hops on average\&.
.RE
.PP
\fBENABLE_SPA_OVER_HTTP\fR \fI<Y/N>\fR
.RS 4
Allow
@@ -367,16 +361,12 @@ mode)\&. Note that the \(lqPCAP_FILTER\(rq variable would need to be updated whe
.PP
\fBENABLE_TCP_SERVER\fR \fI<Y/N>\fR
.RS 4
Note that
\fBfwknopd\fR
still only gets its data via pcap, so the filter defined by \(lqPCAP_FILTER\(rq needs to be updated to include this TCP port\&.
Enable the fwknopd TCP server\&. This is a "dummy" TCP server that will accept TCP connection requests on the specified TCPSERV_PORT\&. If set to "Y", fwknopd will fork off a child process to listen for, and accept incoming TCP request\&. This server only accepts the request\&. It does not otherwise communicate\&. This is only to allow the incoming SPA over TCP packet which is detected via PCAP\&. The connection is closed after 1 second regardless\&. Note that fwknopd still only gets its data via pcap, so the filter defined by PCAP_FILTER needs to be updated to include this TCP port\&.
.RE
.PP
\fBTCPSERV_PORT\fR \fI<port>\fR
.RS 4
Set the default port number that the
\fIfwknopd_serv\fR
\(lqdummy\(rq TCP server listens on\&. This server is only spawned when \(lqENABLE_TCP_SERVER\(rq is set to \(lqY\(rq\&.
Set the port number that the \(lqdummy\(rq TCP server listens on\&. This server is only spawned when \(lqENABLE_TCP_SERVER\(rq is set to \(lqY\(rq\&.
.RE
.PP
\fBSYSLOG_IDENTITY\fR \fI<identity>\fR
@@ -389,13 +379,6 @@ Override syslog identity on message logged by
.RS 4
Override syslog facility\&. The \(lqSYSLOG_FACILITY\(rq variable can be set to
.RE
.PP
\fBIPT_EXEC_TRIES\fR \fI<num_tries>\fR
.RS 4
Define the number of times that
\fBfwknopd\fR
will run certain critical iptables commands (such as adding a new access rule) if any problems are encountered\&.
.RE
.SS "ACCESS\&.CONF VARIABLES"
.sp
This section describes the access control directives in the \fIaccess\&.conf\fR file\&. Theses directives define encryption keys and level of access that is granted to \fBfwknop\fR clients that have generated the appropriate encrypted message\&.
@@ -432,7 +415,7 @@ Define the key used for decrypting an incoming SPA packet that is using its buil
.RS 4
Define the length of time access will be granted by
\fBfwknopd\fR
through the firewall after a valid knock sequence from a source IP address\&. If \(lqFW_ACCESS_TIMEOUT\(rq is not set then the default timeout of 120 seconds (2 minutes) will automatically be set\&.
through the firewall after a valid knock sequence from a source IP address\&. If \(lqFW_ACCESS_TIMEOUT\(rq is not set then the default timeout of 60 seconds will automatically be set\&.
.RE
.PP
\fBENABLE_CMD_EXEC\fR: \fI<Y/N>\fR
@@ -444,12 +427,17 @@ to accept complete commands that are contained within an authorization packet\&.
server\&.
.RE
.PP
\fBCMD_EXEC_USER\fR: \fI<username>\fR
.RS 4
This specifies the user that will execute commands contained within a SPA packet\&. If not specified, fwknopd will execute it as the user it is running as (most likely root)\&. Setting this to a non\-root user is highly recommended\&.
.RE
.PP
\fBREQUIRE_USERNAME\fR: \fI<username>\fR
.RS 4
Require a specific username from the client system as encoded in the SPA data\&. This variable is optional and if not specified, the username data in the SPA data is ignored\&.
.RE
.PP
\fBREQUIRE_SOURCE_ADDRESS:\fR \fI<Y/N>\fR
\fBREQUIRE_SOURCE_ADDRESS\fR: \fI<Y/N>\fR
.RS 4
Force all SPA packets to contain a real IP address within the encrypted data\&. This makes it impossible to use the
\fB\-s\fR
@@ -495,20 +483,34 @@ to function (it has to be able to decrypt SPA messages that have been encrypted
Specify the decryption password for the gpg key defined by the \(lqGPG_DECRYPT_ID\(rq above\&. This is a required field for gpg\-based authentication\&.
.RE
.PP
\fBGPG_REQUIRE_SIG\fR: \fI<Y/N>\fR
.RS 4
With this setting set to
\fIY\fR, fwknopd check all GPG\-encrypted SPA messages for a signature (signed by the sender\(cqs key)\&. If the incoming message is not signed, the decryption process will fail\&. If not set, the default is
\fIN\fR\&.
.RE
.PP
\fBGPG_IGNORE_SIG_VERIFY_ERROR\fR: \fI<Y/N>\fR
.RS 4
Setting this will allow fwknopd to accept incoming GPG\-encrypted packets that are signed, but the signature did not pass verification (i\&.e\&. the signer key was expired, etc\&.)\&. This setting only applies if the GPG_REQUIRE_SIG is also set to
\fIY\fR\&.
.RE
.PP
\fBGPG_REMOTE_ID\fR: \fI<keyID,\&...,keyID>\fR
.RS 4
Define a list of gpg key ID\(cqs that are required to have signed any incoming SPA message that has been encrypted with the
\fBfwknopd\fR
server key\&. This ensures that the verification of the remote user is accomplished via a strong cryptographic mechanism\&.
server key\&. This ensures that the verification of the remote user is accomplished via a strong cryptographic mechanism\&. This setting only applies if the \(lqGPG_REQUIRE_SIG\(rq is set to
\fIY\fR\&. Separate multiple entries with a comma\&.
.RE
.SH "FILES"
.PP
\fB/etc/fwknop/fwknop\&.conf\fR
\fBfwknop\&.conf\fR
.RS 4
The main configuration file for fwknop\&.
.RE
.PP
\fB/etc/fwknop/access\&.conf\fR
\fBaccess\&.conf\fR
.RS 4
Defines all knock sequences and access control directives\&.
.RE

View File

@@ -323,6 +323,8 @@ typedef struct acc_stanza
char *gpg_home_dir;
char *gpg_decrypt_id;
char *gpg_decrypt_pw;
unsigned char gpg_require_sig;
unsigned char gpg_ignore_sig_error;
char *gpg_remote_id;
acc_string_list_t *gpg_remote_id_list;
struct acc_stanza *next;

View File

@@ -169,7 +169,7 @@ incoming_spa(fko_srv_options_t *opts)
*/
fko_ctx_t ctx = NULL;
char *spa_ip_demark;
char *spa_ip_demark, *gpg_id;
time_t now_ts;
int res, status, ts_diff, enc_type;
uid_t myuid;
@@ -251,20 +251,17 @@ incoming_spa(fko_srv_options_t *opts)
if(acc->gpg_decrypt_id != NULL)
fko_set_gpg_recipient(ctx, acc->gpg_decrypt_id);
/* If REMOTE_ID is set, validate and check the signer. Otherwise,
* skip and ignore verify errors.
*
* TODO: At present we are not checking signatures.
/* If GPG_REQUIRE_SIG is set for this acc stanza, then set
* the FKO context accordingly and check the other GPG Sig-
* related parameters.
*/
if(acc->gpg_remote_id != NULL)
if(acc->gpg_require_sig)
{
/* TODO: Add sig verify code */
/** --DSS replace these with the real code **/
/**/ fko_set_gpg_signature_verify(ctx, 0); /**/
/**/ fko_set_gpg_ignore_verify_error(ctx, 1); /**/
/** --DSS replace these with the real code **/
fko_set_gpg_signature_verify(ctx, 1);
/* Set whether or not to ignore signature verification errors.
*/
fko_set_gpg_ignore_verify_error(ctx, acc->gpg_ignore_sig_error);
}
else
{
@@ -310,6 +307,29 @@ incoming_spa(fko_srv_options_t *opts)
if(opts->verbose > 2)
log_msg(LOG_INFO, "SPA Decode (res=%i):\n%s", res, dump_ctx(ctx));
/* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
* then we need to make sure this incoming message is signer ID matches
* an entry in the list.
*/
if(enc_type == FKO_ENCRYPTION_GPG && acc->gpg_remote_id != NULL)
{
res = fko_get_gpg_signature_id(ctx, &gpg_id);
if(res != FKO_SUCCESS)
{
log_msg(LOG_WARNING, "Error pulling the GPG signature ID from the context: %s",
fko_gpg_errstr(ctx));
goto clean_and_bail;
}
if(!acc_check_gpg_remote_id(acc, gpg_id))
{
log_msg(LOG_WARNING,
"Incoming SPA packet signed by ID: %s, but that ID is not the GPG_REMOTE_ID list.",
gpg_id);
goto clean_and_bail;
}
}
/* Check for replays if so configured.
*/
if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)