Added gpg-home-dir support to libfko and the fwknop program. Added the fko_set_spa_data() function. Documentation updates and other tweaks to support these changes.

git-svn-id: file:///home/mbr/svn/fwknop/trunk@75 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
Damien Stuart 2009-03-17 02:05:25 +00:00
parent b82f0e99dd
commit 6e90c5efc6
12 changed files with 294 additions and 57 deletions

View File

@ -31,7 +31,7 @@ AC_PROG_LIBTOOL
# Checks for header files.
#
AC_HEADER_STDC
AC_CHECK_HEADERS([ctype.h endian.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/byteorder.h sys/endian.h sys/socket.h sys/time.h termios.h unistd.h])
AC_CHECK_HEADERS([ctype.h endian.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/byteorder.h sys/endian.h sys/socket.h sys/stat.h sys/time.h termios.h unistd.h])
# Type checks.
#

View File

@ -548,7 +548,7 @@ is returned.
@end deftypefun
@noindent
The most common case...
The most common (simple) case...
@example
fko_ctx_t ctx;
@ -570,7 +570,9 @@ if(rc != FKO_SUCCESS)
@noindent
Or, perhaps you need to defer decryption and parsing to a later point
in the program...
in the program. We could use fko_new_with_data(), passing NULL for the
decryption key, or we could use fko_new() to create an empty context,
then use fko_set_spa_data() to add the encypted data (see code in comments).
@example
fko_ctx_t ctx;
@ -589,9 +591,19 @@ if(rc != FKO_SUCCESS)
exit(1);
@}
/* Assume we called other code and functions...
/* We could also just create and empty context and add the
* encrypted data as follows:
*
* rc = fko_new(&ctx);
* ... check rc ...
* rc = fko_set_spa_data(ctx, spa_data);
* ...
*/
/* Assume we called other code and functions... */
/* Decrypt and decode...
*/
rc = fko_decrypt_spa_data(ctx, key);
if(rc != FKO_SUCCESS)
@ -831,6 +843,13 @@ as it will be called automatically by other functions during normal
processing (most notably @code{fko_spa_data_final}).
@end deftypefun
@deftypefun int fko_set_spa_data (@w{fko_ctx_t @var{ctx}, char @var{*enc_data}});
This function is used to place encrypted @acronym{SPA} data into a newly
created empty context (i.e. with @code{fko_new}). In most cases, you would
use @code{fko_new_with_data} so you wouldn't have to take the extra step to
use this function. However, some may find a reason to do it in this way.
@end deftypefun
@cindex gpg-specific functions
@noindent
@emph{GPG-specific functions:}
@ -847,6 +866,11 @@ Sets the @acronym{GPG} key for signing the data. This would be the sender's
key used to sign the @acronym{SPA} data. You can use the user name or key ID.
@end deftypefun
@deftypefun int fko_set_gpg_home_dir (@w{fko_ctx_t @var{ctx}, const char @var{home_dir}});
Sets the @acronym{GPG} home directory for the current gpgme context. This
allows for using alternate keyrings, gpg configurations, etc.
@end deftypefun
@noindent
@strong{Note}: On a libfko build without @acronym{GPG} support, the
GPG-related functions above will simply return the FKO_ERROR_UNSUPPORTED_FEATURE
@ -968,9 +992,15 @@ Returns a pointer to the string containing the @acronym{GPG} key for the
signer of the @acronym{SPA} data (as set with @emph{fko_set_gpg_signer}).
@end deftypefun
@deftypefun char* fko_get_gpg_home_dir (@w{fko_ctx_t @var{ctx}});
Returns a pointer to the string containing the current @acronym{GPG}
home directory.
@end deftypefun
@noindent
@strong{Note}: On a libfko build without @acronym{GPG} support, the
GPG-related functions above will simply return NULL.
@strong{Note}: The GPG-related functions above will return NULL if the
value was not previously set, or the current libfko build does not have
@acronym{GPG} support.
@node Utility Functions
@section Utility Functions
@ -1077,10 +1107,10 @@ Invalid SPA nat_access mesage format
Invalid encryption type
@item FKO_ERROR_WRONG_ENCRYPTION_TYPE
Wrong or inappropriate encryption type for this operation
@item FKO_ERROR_MISSING_GPG_KEY_DATA
Missing GPG key data (signer or recipient not set)
@item FKO_ERROR_DECRYPTION_SIZE
Unexpected or invalid size for decrypted data
@item FKO_ERROR_DECRYPTION_FAILURE
Decryption failed or decrypted data is invalid
@item FKO_ERROR_DIGEST_VERIFICATION_FAILED
The computed digest did not match the digest in the spa data
@item FKO_ERROR_UNSUPPORTED_FEATURE
@ -1100,6 +1130,8 @@ These are:
@deftypevar int error_code (gpgme support only)
@table @code
@item FKO_ERROR_MISSING_GPG_KEY_DATA
Missing GPG key data (signer or recipient not set)
@item FKO_ERROR_GPGME_NO_OPENPGP
This GPGME implementation does not support OpenPGP
@item FKO_ERROR_GPGME_CONTEXT
@ -1134,6 +1166,11 @@ The key for the given recipient was not found
Ambiguous name/id for the recipient key (mulitple matches)
@item FKO_ERROR_GPGME_DECRYPT_FAILED
Decryption operation failed
@item FKO_ERROR_GPGME_BAD_HOME_DIR
Unable to stat the given GPG home directory
@item FKO_ERROR_GPGME_SET_HOME_DIR
Unable to set the given GPG home directory
@end table
@end deftypevar

View File

@ -82,7 +82,6 @@ typedef enum {
FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG,
FKO_ERROR_INVALID_ENCRYPTION_TYPE,
FKO_ERROR_WRONG_ENCRYPTION_TYPE,
FKO_ERROR_MISSING_GPG_KEY_DATA,
FKO_ERROR_DECRYPTION_SIZE,
FKO_ERROR_DECRYPTION_FAILURE,
FKO_ERROR_DIGEST_VERIFICATION_FAILED,
@ -91,6 +90,7 @@ typedef enum {
/* Start GPGME-related errors */
GPGME_ERR_START,
FKO_ERROR_MISSING_GPG_KEY_DATA,
FKO_ERROR_GPGME_NO_OPENPGP,
FKO_ERROR_GPGME_CONTEXT,
FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ,
@ -108,6 +108,8 @@ typedef enum {
FKO_ERROR_GPGME_RECIPIENT_KEY_NOT_FOUND,
FKO_ERROR_GPGME_RECIPIENT_KEY_AMBIGUOUS,
FKO_ERROR_GPGME_DECRYPT_FAILED,
FKO_ERROR_GPGME_BAD_HOME_DIR,
FKO_ERROR_GPGME_SET_HOME_DIR,
FKO_LAST_ERROR
} fko_error_codes_t;
@ -136,7 +138,6 @@ int fko_new_with_data(fko_ctx_t *ctx, char *enc_msg, char *dec_key);
void fko_destroy(fko_ctx_t ctx);
int fko_spa_data_final(fko_ctx_t ctx, char *enc_key);
char* fko_get_spa_data(fko_ctx_t ctx);
/* Set context data functions */
int fko_set_rand_value(fko_ctx_t ctx, const char *val);
@ -150,6 +151,7 @@ int fko_set_spa_client_timeout(fko_ctx_t ctx, int timeout);
int fko_set_spa_digest_type(fko_ctx_t ctx, short digest_type);
int fko_set_spa_digest(fko_ctx_t ctx);
int fko_set_spa_encryption_type(fko_ctx_t ctx, short encrypt_type);
int fko_set_spa_data(fko_ctx_t ctx, char *enc_msg);
/* Data processing and misc utility functions */
const char* fko_errstr(int err_code);
@ -172,6 +174,7 @@ int fko_get_spa_client_timeout(fko_ctx_t ctx);
short fko_get_spa_digest_type(fko_ctx_t ctx);
char* fko_get_spa_digest(fko_ctx_t ctx);
short fko_get_spa_encryption_type(fko_ctx_t ctx);
char* fko_get_spa_data(fko_ctx_t ctx);
char* fko_version(fko_ctx_t ctx);
@ -180,6 +183,8 @@ int fko_set_gpg_recipient(fko_ctx_t ctx, const char *recip);
char* fko_get_gpg_recipient(fko_ctx_t ctx);
int fko_set_gpg_signer(fko_ctx_t ctx, const char *signer);
char* fko_get_gpg_signer(fko_ctx_t ctx);
int fko_set_gpg_home_dir(fko_ctx_t ctx, const char *gpg_home_dir);
char* fko_get_gpg_home_dir(fko_ctx_t ctx);
const char* fko_gpg_errorstr(fko_ctx_t ctx);
#endif /* FKO_H */

View File

@ -61,6 +61,9 @@ struct fko_context {
/* For gpgme support */
char *gpg_recipient;
char *gpg_signer;
char *gpg_home_dir;
unsigned char have_gpgme_context;
gpgme_ctx_t gpg_ctx;
gpgme_key_t recipient_key;

View File

@ -30,6 +30,9 @@
#if HAVE_LIBGPGME
#include "gpgme_funcs.h"
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#endif
#define B64_RIJNDAEL_SALT "U2FsdGVkX1"
@ -539,4 +542,53 @@ fko_get_gpg_signer(fko_ctx_t ctx)
#endif /* HAVE_LIBGPGME */
}
/* Set the GPG home dir.
*/
int
fko_set_gpg_home_dir(fko_ctx_t ctx, const char *gpg_home_dir)
{
#if HAVE_LIBGPGME
struct stat st;
/* Must be initialized
*/
if(!CTX_INITIALIZED(ctx))
return(FKO_ERROR_CTX_NOT_INITIALIZED);
/* If we are unable to stat the given dir, then return with error.
*/
if(stat(gpg_home_dir, &st) != 0)
return(FKO_ERROR_GPGME_BAD_HOME_DIR);
if(!S_ISDIR(st.st_mode))
return(FKO_ERROR_GPGME_BAD_HOME_DIR);
ctx->gpg_home_dir = strdup(gpg_home_dir);
if(ctx->gpg_home_dir == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
return(FKO_SUCCESS);
#else
return(FKO_ERROR_UNSUPPORTED_FEATURE);
#endif /* HAVE_LIBGPGME */
}
/* Get the GPG home dir.
*/
char*
fko_get_gpg_home_dir(fko_ctx_t ctx)
{
#if HAVE_LIBGPGME
/* Must be initialized
*/
if(!CTX_INITIALIZED(ctx))
return(NULL);
return(ctx->gpg_home_dir);
#else
//--DSS we should make this an error
return(NULL);
#endif /* HAVE_LIBGPGME */
}
/***EOF***/

View File

@ -82,9 +82,6 @@ fko_errstr(int err_code)
case FKO_ERROR_WRONG_ENCRYPTION_TYPE:
return("Wrong or inappropriate encryption type for this operation");
case FKO_ERROR_MISSING_GPG_KEY_DATA:
return("Missing GPG key data (signer or recipient not set)");
case FKO_ERROR_DECRYPTION_SIZE:
return("Unexpected or invalid size for decrypted data");
@ -103,6 +100,9 @@ fko_errstr(int err_code)
#if HAVE_LIBGPGME
/* Start GPGME-related errors
*/
case FKO_ERROR_MISSING_GPG_KEY_DATA:
return("Missing GPG key data (signer or recipient not set)");
case FKO_ERROR_GPGME_NO_OPENPGP:
return("This GPGME implementation does not support OpenPGP");
@ -153,6 +153,12 @@ fko_errstr(int err_code)
case FKO_ERROR_GPGME_DECRYPT_FAILED:
return("Decryption operation failed");
case FKO_ERROR_GPGME_BAD_HOME_DIR:
return("Unable to stat the given GPG home directory");
case FKO_ERROR_GPGME_SET_HOME_DIR:
return("Unable to set the given GPG home directory");
#endif /* HAVE_LIBGPGME */
}

View File

@ -152,9 +152,11 @@ fko_new_with_data(fko_ctx_t *r_ctx, char *enc_msg, char *dec_key)
{
fko_ctx_t ctx;
ctx = calloc(1, sizeof *ctx);
if(ctx == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
int res = fko_new(r_ctx);
if(res != FKO_SUCCESS)
return res;
ctx = *r_ctx;
/* First, add the data to the context.
*/
@ -165,10 +167,9 @@ fko_new_with_data(fko_ctx_t *r_ctx, char *enc_msg, char *dec_key)
return(FKO_ERROR_MEMORY_ALLOCATION);
}
FKO_SET_CTX_INITIALIZED(ctx);
*r_ctx = ctx;
/* If a decryption password is provided, go ahead and decrypt and
* decode.
*/
if(dec_key != NULL)
return(fko_decrypt_spa_data(ctx, dec_key));
@ -283,4 +284,23 @@ fko_get_spa_data(fko_ctx_t ctx)
return(ctx->encrypted_msg);
}
/* Return the fko SPA encrypted data.
*/
int
fko_set_spa_data(fko_ctx_t ctx, char *enc_msg)
{
/* Must be initialized
*/
if(!CTX_INITIALIZED(ctx))
return NULL;
/* First, add the data to the context.
*/
ctx->encrypted_msg = strdup(enc_msg);
if(ctx->encrypted_msg == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
return(FKO_SUCCESS);
}
/***EOF***/

View File

@ -31,9 +31,15 @@
#include "gpgme_funcs.h"
int
init_gpgme(void)
init_gpgme(fko_ctx_t fko_ctx)
{
gpgme_error_t err;
gpgme_engine_info_t eng_info;
gpgme_error_t err;
/* If we already have a context, we are done.
*/
if(fko_ctx->have_gpgme_context)
return(FKO_SUCCESS);
/* Because the gpgme manual says you should.
*/
@ -45,9 +51,44 @@ init_gpgme(void)
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
{
/* GPG engine is not available. */
fko_ctx->gpg_err = err;
return(FKO_ERROR_GPGME_NO_OPENPGP);
}
/* Create our gpgme context
*/
err = gpgme_new(&(fko_ctx->gpg_ctx));
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
{
fko_ctx->gpg_err = err;
return(FKO_ERROR_GPGME_CONTEXT);
}
/* Extract the current gpgme engine information.
*/
eng_info = gpgme_ctx_get_engine_info(fko_ctx->gpg_ctx);
/* If a gpg_home_dir was not given or the given dir does not
* match what we already have, then add the new dir to the context.
*/
if(fko_ctx->gpg_home_dir != NULL)
{
err = gpgme_ctx_set_engine_info(
fko_ctx->gpg_ctx,
eng_info->protocol,
eng_info->file_name,
fko_ctx->gpg_home_dir
);
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
{
fko_ctx->gpg_err = err;
return(FKO_ERROR_GPGME_SET_HOME_DIR);
}
}
fko_ctx->have_gpgme_context = 1;
return(FKO_SUCCESS);
}
@ -75,6 +116,7 @@ passphrase_cb(
int
get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, int signer)
{
int res;
const char *name;
gpgme_ctx_t list_ctx = NULL;
@ -84,17 +126,19 @@ get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, int signer)
/* Create a gpgme context for the list
*/
err = gpgme_new(&list_ctx);
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
/* Initialize gpgme
*/
res = init_gpgme(fko_ctx);
if(res != FKO_SUCCESS)
{
fko_ctx->gpg_err = err;
if(signer)
return(FKO_ERROR_GPGME_CONTEXT_SIGNER_KEY);
else
return(FKO_ERROR_GPGME_CONTEXT_RECIPIENT_KEY);
}
list_ctx = fko_ctx->gpg_ctx;
if(signer)
name = fko_ctx->gpg_signer;
else
@ -120,8 +164,6 @@ get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, int signer)
{
/* Key not found
*/
gpgme_release(list_ctx);
fko_ctx->gpg_err = err;
if(signer)
@ -140,7 +182,6 @@ get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, int signer)
*/
gpgme_key_unref(key);
gpgme_key_unref(key2);
gpgme_release(list_ctx);
fko_ctx->gpg_err = err;
@ -156,8 +197,6 @@ get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, int signer)
*mykey = key;
gpgme_release(list_ctx);
return(FKO_SUCCESS);
}
@ -177,20 +216,10 @@ gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const cha
/* Initialize gpgme
*/
res = init_gpgme();
res = init_gpgme(fko_ctx);
if(res != FKO_SUCCESS)
return(res);
/* Create our gpgme context
*/
err = gpgme_new(&(fko_ctx->gpg_ctx));
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
{
fko_ctx->gpg_err = err;
return(FKO_ERROR_GPGME_CONTEXT);
}
gpg_ctx = fko_ctx->gpg_ctx;
/* Initialize the plaintext data (place into gpgme_data object)
@ -298,7 +327,6 @@ gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const cha
}
gpgme_free(tmp_buf);
//gpgme_release(gpg_ctx);
return(res);
}
@ -318,20 +346,10 @@ gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const cha
/* Initialize gpgme
*/
res = init_gpgme();
res = init_gpgme(fko_ctx);
if(res != FKO_SUCCESS)
return(res);
/* Create our gpgme context
*/
err = gpgme_new(&(fko_ctx->gpg_ctx));
if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
{
fko_ctx->gpg_err = err;
return(FKO_ERROR_GPGME_CONTEXT);
}
gpg_ctx = fko_ctx->gpg_ctx;
err = gpgme_data_new(&plaintext);
@ -403,7 +421,6 @@ gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const cha
}
gpgme_free(tmp_buf);
//gpgme_release(gpg_ctx);
return(res);
}

View File

@ -299,6 +299,10 @@ config_init(fko_cli_options_t *options, int argc, char **argv)
options->use_gpg = 1;
strlcpy(options->gpg_signer_key, optarg, MAX_GPG_KEY_ID);
break;
case GPG_HOME_DIR:
options->use_gpg = 1;
strlcpy(options->gpg_home_dir, optarg, MAX_PATH_LEN);
break;
case GPG_AGENT:
options->use_gpg = 1;
options->use_gpg_agent = 1;
@ -356,6 +360,7 @@ usage(void)
" --gpg-encryption - Use GPG encyrption (default is Rijndael).\n"
" --gpg-recipient-key - Specify the recipient GPG key name or ID.\n"
" --gpg-signer-key - Specify the signer's GPG key name or ID.\n"
" --gpg-home-dir - Specify the GPG home directory.\n"
" --gpg-agent - Use GPG agent if available.\n"
"\n"
);

View File

@ -37,6 +37,7 @@ enum {
GPG_ENCRYPTION = 0x200,
GPG_RECIP_KEY,
GPG_SIGNER_KEY,
GPG_HOME_DIR,
GPG_AGENT,
NOOP /* Just to be a marker for the end */
};
@ -65,6 +66,7 @@ static struct option cmd_opts[] =
{"gpg-encryption", 0, NULL, 'g'},
{"gpg-recipient-key", 1, NULL, GPG_RECIP_KEY },
{"gpg-signer-key", 1, NULL, GPG_SIGNER_KEY },
{"gpg-home-dir", 1, NULL, GPG_HOME_DIR },
{"gpg-agent", 0, NULL, GPG_AGENT },
{0, 0, 0, 0}
};

View File

@ -81,6 +81,23 @@ main(int argc, char **argv)
exit(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(options.gpg_home_dir != NULL && strlen(options.gpg_home_dir) > 0)
{
res = fko_set_gpg_home_dir(ctx, options.gpg_home_dir);
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"Error #%i from fko_set_gpg_home_dir: %s\n",
res, fko_errstr(res)
);
exit(EXIT_FAILURE);
}
}
res = fko_set_gpg_recipient(ctx, options.gpg_recipient_key);
if(res != FKO_SUCCESS)
{
@ -195,14 +212,86 @@ main(int argc, char **argv)
/* Now we create a new context based on data from the first one.
*/
res = fko_new_with_data(&ctx2, fko_get_spa_data(ctx),
get_user_pw(&options, CRYPT_OP_DECRYPT));
/* 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.
*/
res = fko_new_with_data(&ctx2, fko_get_spa_data(ctx), NULL);
//get_user_pw(&options, CRYPT_OP_DECRYPT));
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"Error #%i from fko_new_with_data: %s\n",
res, fko_errstr(res)
);
exit(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.
res = fko_new(&ctx2);
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"Error #%i from fko_new: %s\n",
res, fko_errstr(res)
);
exit(EXIT_FAILURE);
}
*/
/* Populate the new context with the encrypted data from the
* old context.
res = fko_set_spa_data(ctx2, fko_get_spa_data(ctx));
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"Error #%i from fko_set_spa_data: %s\n",
res, fko_errstr(res)
);
exit(EXIT_FAILURE);
}
*/
if(options.use_gpg)
{
if(options.gpg_home_dir != NULL && strlen(options.gpg_home_dir) > 0)
{
res = fko_set_gpg_home_dir(ctx2, options.gpg_home_dir);
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"Error #%i from fko_set_gpg_home_dir: %s\n",
res, fko_errstr(res)
);
exit(EXIT_FAILURE);
}
}
}
res = fko_decrypt_spa_data(
ctx2, get_user_pw(&options, CRYPT_OP_DECRYPT)
);
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"Error #%i from fko_decrypt_spa_data: %s\n",
res, fko_errstr(res)
);
if(IS_GPG_ERROR(res))
fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errorstr(ctx));

View File

@ -92,6 +92,7 @@ typedef struct fko_cli_options
char spoof_user[MAX_USERNAME_LEN];
char gpg_recipient_key[MAX_GPG_KEY_ID];
char gpg_signer_key[MAX_GPG_KEY_ID];
char gpg_home_dir[MAX_PATH_LEN];
int proto;
unsigned int port;