Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First cut at GPG encrytion support (decryption and doc update are pen…

…ding).

git-svn-id: file:///home/mbr/svn/fwknop/trunk@39 510a4753-2344-4c79-9c09-4d669213fbeb
  • Loading branch information...
commit e846cdd44d4c9e12b102d3e72ad8302ba886921e 1 parent 0467407
Damien Stuart authored
View
14 configure.ac
@@ -3,11 +3,12 @@ dnl Process thie file with autoconf to produce teh configure script
AC_PREREQ(2.53)
m4_define(my_package, [fwknop])
-m4_define(my_version, [2.0.0-alpha])
+m4_define(my_version, [1.10.0-alpha])
m4_define(my_bug_email, [dstuart@dstuart.org])
AC_INIT(my_package, my_version, my_bug_email)
AC_CONFIG_AUX_DIR(config)
+
AM_INIT_AUTOMAKE(my_package, my_version)
dnl AM_MAINTAINER_MODE
@@ -53,9 +54,20 @@ AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([bzero gettimeofday memmove memset strchr strcspn strdup strndup strrchr strspn])
+# Check for gpgme
+AM_PATH_GPGME
+GPGME_SUPPORT="yes"
+AC_CHECK_LIB(gpgme, gpgme_check_version, , GPGME_SUPPORT="no")
+
AC_CONFIG_FILES([Makefile
fko/Makefile
doc/Makefile
src/Makefile])
AC_OUTPUT
+
+echo "
+ libfko v${VERSION} has been configured.
+
+ GPG encryption support: $GPGME_SUPPORT
+"
View
2  doc/libfko.texi
@@ -354,7 +354,7 @@ gcc -o foo foo.c -I/opt/fko/include -L/opt/fko/lib -lfko
@cindex message digest types
@cindex default message digest
-The fwknop system employs an message digest hash of the @acronym{SPA}
+The fwknop system employs a message digest hash of the @acronym{SPA}
data as one of the data fields to act a signature which can be used
at the receiving end to verify the data is valid. This provides a means
to ensure the data was not modified in-transit. The resulting digest
View
2  fko/Makefile.am
@@ -7,7 +7,7 @@ libfko_source_files = \
fko_nat_access.c fko_rand_value.c fko_server_auth.c fko.h fko_limits.h \
fko_timestamp.c fko_types.h fko_user.c fko_util.h md5.c md5.h \
rijndael.c rijndael.h sha1.c sha256.c sha.h strlcat.c \
- strlcpy.c fko_state.h fko_context.h
+ strlcpy.c fko_state.h fko_context.h gpgme_funcs.c gpgme_funcs.h
libfko_la_SOURCES = $(libfko_source_files)
libfko_la_LDFLAGS = -version-info 0:1:0
View
29 fko/cipher_funcs.c
@@ -35,7 +35,7 @@
/* Get random data.
*/
void
-get_random_data(unsigned char *data, int len)
+get_random_data(unsigned char *data, size_t len)
{
FILE *rfd;
struct timeval tv;
@@ -64,20 +64,23 @@ get_random_data(unsigned char *data, int len)
}
}
-/* Function to generate initial salt and initialization vector (iv).
- * This is is done to be compatible with the data produced via
+
+/*** These are Rijndael-specific functions ***/
+
+/* Rijndael function to generate initial salt and initialization vector
+ * (iv). This is is done to be compatible with the data produced via
* the Perl Crypt::CBC module's use of Rijndael.
*/
void
-salt_and_iv(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
+rij_salt_and_iv(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
{
char pw_buf[16];
unsigned char tmp_buf[64]; /* How big does this need to be? */
unsigned char kiv_buf[48]; /* Key and IV buffer */
unsigned char md5_buf[16]; /* Buffer for computed md5 hash */
- int kiv_len = 0;
- int plen = strlen(pass);
+ size_t kiv_len = 0;
+ size_t plen = strlen(pass);
/* First make pw 16 bytes (pad with "0" (ascii 0x30)) or truncate.
* Note: pw_buf was initialized with '0' chars (again, not the value
@@ -144,7 +147,7 @@ rijndael_init(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
/* Generate the salt and initialization vector.
*/
- salt_and_iv(ctx, pass, data);
+ rij_salt_and_iv(ctx, pass, data);
/* Intialize our rinjdael context.
*/
@@ -154,8 +157,8 @@ rijndael_init(RIJNDAEL_context *ctx, const char *pass, unsigned char *data)
/* Take a chunk of data, encrypt it in the same way the perl Crypt::CBC
* module would.
*/
-int
-fko_encrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
+size_t
+rij_encrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *out)
{
RIJNDAEL_context ctx;
unsigned char plaintext[16];
@@ -208,8 +211,8 @@ fko_encrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
/* Decrypt the given data.
*/
-int
-fko_decrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
+size_t
+rij_decrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *out)
{
RIJNDAEL_context ctx;
unsigned char plaintext[16];
@@ -271,5 +274,9 @@ fko_decrypt(unsigned char *in, int in_len, const char *pass, unsigned char *out)
return(ondx - out);
}
+/*** These are GPG-specific functions ***/
+
+//--DSS TODO: Finish me
+
/***EOF***/
View
11 fko/cipher_funcs.h
@@ -26,6 +26,7 @@
#include "fko_common.h"
#include "rijndael.h"
+#include "gpgme_funcs.h"
/* Provide the predicted encrypted data size for given input data based
* on a 16-byte block size (for Rijndael implementation,this also accounts
@@ -33,9 +34,13 @@
*/
#define PREDICT_ENCSIZE(x) (1+(x>>4)+(x&0xf?1:0))<<4
-int fko_encrypt(uchar *in, int len, const char *key, uchar *out);
-int fko_decrypt(uchar *in, int len, const char *key, uchar *out);
-void hex_dump(uchar *data, int size);
+size_t rij_encrypt(unsigned char *in, size_t len, const char *key, unsigned char *out);
+size_t rij_decrypt(unsigned char *in, size_t len, const char *key, unsigned char *out);
+
+#if HAVE_LIBGPGME
+int gpg_encrypt(unsigned char *in, size_t len, const char *signer, const char *recip, unsigned char **out, size_t *out_sz);
+int gpg_decrypt(unsigned char *in, size_t len, const char *key, unsigned char **out, size_t *out_sz);
+#endif /* HAVE_LIBGPGME */
#endif /* CIPHER_FUNCS_H */
View
8 fko/fko.h
@@ -81,6 +81,8 @@ typedef enum {
FKO_ERROR_INVALID_SPA_ACCESS_MSG,
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_ERROR,
FKO_ERROR_DIGEST_VERIFICATION_FAILED,
/* Add more errors above this line */
@@ -147,6 +149,12 @@ short fko_get_spa_encryption_type(fko_ctx_t ctx);
char* fko_version(fko_ctx_t ctx);
+/* GPG-related functions */
+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);
+
#endif /* FKO_H */
/***EOF***/
View
2  fko/fko_client_timeout.c
@@ -45,7 +45,7 @@ fko_set_spa_client_timeout(fko_ctx_t ctx, int timeout)
ctx->client_timeout = timeout;
- ctx->state |= FKO_CLIENT_TIMEOUT_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
/* If a timeout is set, then we may need to verify/change message
* type accordingly.
View
8 fko/fko_context.h
@@ -26,6 +26,8 @@
#ifndef FKO_CONTEXT_H
#define FKO_CONTEXT_H 1
+#include "fko_common.h"
+
/* The pieces we need to make an FKO SPA data packet.
*/
struct fko_context {
@@ -54,6 +56,12 @@ struct fko_context {
/* State info */
unsigned short state;
unsigned char initval;
+
+#if HAVE_LIBGPGME
+ /* For gpgme support */
+ char *gpg_recipient;
+ char *gpg_signer;
+#endif /* HAVE_LIBGPGME */
};
#endif /* FKO_CONTEXT_H */
View
6 fko/fko_decode.c
@@ -97,15 +97,15 @@ fko_decode_spa_data(fko_ctx_t ctx)
switch(ctx->digest_type)
{
case FKO_DIGEST_MD5:
- md5_base64(tbuf, ctx->encoded_msg, strlen(ctx->encoded_msg));
+ md5_base64(tbuf, (unsigned char*)ctx->encoded_msg, strlen(ctx->encoded_msg));
break;
case FKO_DIGEST_SHA1:
- sha1_base64(tbuf, ctx->encoded_msg, strlen(ctx->encoded_msg));
+ sha1_base64(tbuf, (unsigned char*)ctx->encoded_msg, strlen(ctx->encoded_msg));
break;
case FKO_DIGEST_SHA256:
- sha256_base64(tbuf, ctx->encoded_msg, strlen(ctx->encoded_msg));
+ sha256_base64(tbuf, (unsigned char*)ctx->encoded_msg, strlen(ctx->encoded_msg));
break;
}
View
38 fko/fko_encode.c
@@ -30,8 +30,8 @@
#include "base64.h"
#include "digest.h"
-/* A rough way to make enough space for a base64 encoded version of
- * the given string, encode it, and return it.
+/* Take a given string, base64-encode it and append it to the given
+ * buffer.
*/
int
append_b64(char* tbuf, char *str)
@@ -63,7 +63,7 @@ int
fko_encode_spa_data(fko_ctx_t ctx)
{
int res, offset = 0;
- char tbuf[FKO_ENCODE_TMP_BUF_SIZE] = {0};
+ char *tbuf;
/* Must be initialized
*/
@@ -88,6 +88,12 @@ fko_encode_spa_data(fko_ctx_t ctx)
return(FKO_ERROR_INCOMPLETE_SPA_DATA);
}
+ /* Allocate our initial tmp buffer.
+ */
+ tbuf = calloc(1, FKO_ENCODE_TMP_BUF_SIZE);
+ if(tbuf == NULL)
+ return(FKO_ERROR_MEMORY_ALLOCATION);
+
/* Put it together a piece at a time, starting with the rand val.
*/
strcpy(tbuf, ctx->rand_val);
@@ -96,7 +102,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
*/
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
if((res = append_b64(tbuf, ctx->username)) != FKO_SUCCESS)
+ {
+ free(tbuf);
return(res);
+ }
/* Add the timestamp.
*/
@@ -126,7 +135,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
/* Add the base64-encoded SPA message.
*/
if((res = append_b64(tbuf, ctx->message)) != FKO_SUCCESS)
+ {
+ free(tbuf);
return(res);
+ }
/* If a nat_access message was given, add it to the SPA
* message.
@@ -135,7 +147,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
{
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
if((res = append_b64(tbuf, ctx->nat_access)) != FKO_SUCCESS)
- return(res);
+ {
+ free(tbuf);
+ return(res);
+ }
}
/* If we have a server_auth field set. Add it here.
@@ -145,7 +160,10 @@ fko_encode_spa_data(fko_ctx_t ctx)
{
strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
if((res = append_b64(tbuf, ctx->server_auth)) != FKO_SUCCESS)
- return(res);
+ {
+ free(tbuf);
+ return(res);
+ }
}
/* If a client timeout is specified and we are not dealing with a
@@ -167,17 +185,25 @@ fko_encode_spa_data(fko_ctx_t ctx)
*/
ctx->encoded_msg = strdup(tbuf);
if(ctx->encoded_msg == NULL)
+ {
+ free(tbuf);
return(FKO_ERROR_MEMORY_ALLOCATION);
+ }
/* At this point we can compute the digest for this SPA data.
*/
if((res = fko_set_spa_digest(ctx)) != FKO_SUCCESS)
+ {
+ free(tbuf);
return(res);
+ }
/* Here we can clear the modified flags on the SPA data fields.
*/
FKO_CLEAR_SPA_DATA_MODIFIED(ctx);
+ free(tbuf);
+
return(FKO_SUCCESS);
}
@@ -186,8 +212,6 @@ fko_encode_spa_data(fko_ctx_t ctx)
char*
fko_get_encoded_data(fko_ctx_t ctx)
{
- int res;
-
/* Must be initialized
*/
if(!CTX_INITIALIZED(ctx))
View
359 fko/fko_encryption.c
@@ -30,71 +30,15 @@
#define B64_RIJNDAEL_SALT "U2FsdGVkX1"
-/* Set the SPA encryption type.
-*/
-int
-fko_set_spa_encryption_type(fko_ctx_t ctx, short encrypt_type)
-{
- /* Must be initialized
- */
- if(!CTX_INITIALIZED(ctx))
- return(FKO_ERROR_CTX_NOT_INITIALIZED);
-
- if(encrypt_type < 0 || encrypt_type >= FKO_LAST_ENCRYPTION_TYPE)
- return(FKO_ERROR_INVALID_DATA);
-
- ctx->encryption_type = encrypt_type;
-
- ctx->state |= FKO_ENCRYPT_TYPE_MODIFIED;
-
- return(FKO_SUCCESS);
-}
-
-/* Return the SPA encryption type.
-*/
-short
-fko_get_spa_encryption_type(fko_ctx_t ctx)
-{
- /* Must be initialized
- */
- if(!CTX_INITIALIZED(ctx))
- return(FKO_ERROR_CTX_NOT_INITIALIZED);
-
- return(ctx->encryption_type);
-}
-
-/* Encrypt the encoded SPA data.
+/* Prep and encrypt using Rijndael
*/
int
-fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
+_rijndael_encrypt(fko_ctx_t ctx, const char *enc_key)
{
char *plain;
char *b64cipher;
unsigned char *cipher;
- int cipher_len, res;
-
- /* Must be initialized
- */
- if(!CTX_INITIALIZED(ctx))
- return(FKO_ERROR_CTX_NOT_INITIALIZED);
-
- /* If there is no encoded data or the SPA data has been modified,
- * go ahead and re-encode here.
- */
- if(ctx->encoded_msg == NULL || FKO_SPA_DATA_MODIFIED(ctx))
- {
- res = fko_encode_spa_data(ctx);
-
- if(res != FKO_SUCCESS)
- return(res);
- }
-
- /* Croak on invalid encoded message as well. At present this is a
- * check for a somewhat arbitrary minimum length for the encoded
- * data.
- */
- if(strlen(ctx->encoded_msg) < MIN_SPA_ENCODED_MSG_SIZE)
- return(FKO_ERROR_MISSING_ENCODED_DATA);
+ int cipher_len;
/* Make a bucket big enough to hold the enc msg + digest (plaintext)
* and populate it appropriately.
@@ -111,7 +55,7 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
if(cipher == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
- cipher_len = fko_encrypt(
+ cipher_len = rij_encrypt(
(unsigned char*)plain, strlen(plain), (char*)enc_key, cipher
);
@@ -141,31 +85,11 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
/* Decode, decrypt, and parse SPA data into the context.
*/
int
-fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
+_rijndael_decrypt(fko_ctx_t ctx, const char *dec_key, int b64_len)
{
char *tbuf;
unsigned char *cipher;
- int b64_len, cipher_len, pt_len;
-
- /* First, make sure we have data to work with.
- */
- if(ctx->encrypted_msg == NULL
- || strlen(ctx->encrypted_msg) < MIN_SPA_ENCODED_MSG_SIZE)
- return(FKO_ERROR_INVALID_DATA);
-
- /* Determine type of encryption used. For know, we are using the
- * size of the message. However, we will want to come up with a
- * more reliable method of identification.
- */
- b64_len = strlen(ctx->encrypted_msg);
-
- if(b64_len > MIN_GNUPG_MSG_SIZE)
- {
- /* TODO: add GPG handling */
- /* Since we do not support GPG yet, we will just fall through */
- }
-
- /* Assuming Rijndael */
+ int cipher_len, pt_len;
/* Now see if we need to add the "Salted__" string to the front of the
* encrypted data.
@@ -198,7 +122,7 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
if(ctx->encoded_msg == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
- pt_len = fko_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
+ pt_len = rij_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
/* Done with cipher...
*/
@@ -215,4 +139,273 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
return(fko_decode_spa_data(ctx));
}
+
+#if HAVE_LIBGPGME
+
+/* Prep and encrypt using gpgme
+*/
+int
+_gpg_encrypt(fko_ctx_t ctx, const char *enc_key)
+{
+ int res;
+ char *plain;
+ char *b64cipher;
+ unsigned char *cipher;
+ size_t cipher_len;
+
+ /* First make sure we have signer and recipient keys set.
+ */
+ if(ctx->gpg_signer == NULL || ctx->gpg_recipient == NULL)
+ return(FKO_ERROR_MISSING_GPG_KEY_DATA);
+
+ /* Make a bucket big enough to hold the enc msg + digest (plaintext)
+ * and populate it appropriately.
+ */
+ plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2);
+ if(plain == NULL)
+ return(FKO_ERROR_MEMORY_ALLOCATION);
+
+ sprintf(plain, "%s:%s", ctx->encoded_msg, ctx->digest);
+
+ res = gpgme_encrypt(
+ (unsigned char*)plain, strlen(plain),
+ ctx->gpg_signer, ctx->gpg_recipient,
+ enc_key, &cipher, &cipher_len
+ );
+
+ /* --DSS XXX: Better parsing of what went wrong would be nice :)
+ */
+ if(res != FKO_SUCCESS)
+ return(res);
+
+ /* Now make a bucket for the base64-encoded version and populate it.
+ */
+ b64cipher = malloc(((cipher_len / 3) * 4) + 8);
+ if(b64cipher == NULL)
+ return(FKO_ERROR_MEMORY_ALLOCATION);
+
+ b64_encode(cipher, b64cipher, cipher_len);
+ strip_b64_eq(b64cipher);
+
+ ctx->encrypted_msg = strdup(b64cipher);
+
+ /* Clean-up
+ */
+ free(plain);
+ free(cipher);
+ free(b64cipher);
+
+ if(ctx->encrypted_msg == NULL)
+ return(FKO_ERROR_MEMORY_ALLOCATION);
+
+ return(FKO_SUCCESS);
+}
+
+#endif /* HAVE_LIBGPGME */
+
+/* Set the SPA encryption type.
+*/
+int
+fko_set_spa_encryption_type(fko_ctx_t ctx, short encrypt_type)
+{
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+ if(encrypt_type < 0 || encrypt_type >= FKO_LAST_ENCRYPTION_TYPE)
+ return(FKO_ERROR_INVALID_DATA);
+
+ ctx->encryption_type = encrypt_type;
+
+ ctx->state |= FKO_ENCRYPT_TYPE_MODIFIED;
+
+ return(FKO_SUCCESS);
+}
+
+/* Return the SPA encryption type.
+*/
+short
+fko_get_spa_encryption_type(fko_ctx_t ctx)
+{
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+ return(ctx->encryption_type);
+}
+
+/* Encrypt the encoded SPA data.
+*/
+int
+fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
+{
+ int res;
+
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+ /* If there is no encoded data or the SPA data has been modified,
+ * go ahead and re-encode here.
+ */
+ if(ctx->encoded_msg == NULL || FKO_IS_SPA_DATA_MODIFIED(ctx))
+ {
+ res = fko_encode_spa_data(ctx);
+
+ if(res != FKO_SUCCESS)
+ return(res);
+ }
+
+ /* Croak on invalid encoded message as well. At present this is a
+ * check for a somewhat arbitrary minimum length for the encoded
+ * data.
+ */
+ if(strlen(ctx->encoded_msg) < MIN_SPA_ENCODED_MSG_SIZE)
+ return(FKO_ERROR_MISSING_ENCODED_DATA);
+
+ /* Encrypt according to type and return...
+ */
+ if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL)
+ return(_rijndael_encrypt(ctx, enc_key));
+
+ else if(ctx->encryption_type == FKO_ENCRYPTION_GPG)
+#if HAVE_LIBGPGME
+ return(_gpg_encrypt(ctx, enc_key));
+#else
+ return(FKO_ERROR_UNSUPPORTED_FEATURE);
+#endif
+
+ else
+ return(FKO_ERROR_INVALID_ENCRYPTION_TYPE);
+}
+
+/* Decode, decrypt, and parse SPA data into the context.
+*/
+int
+fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
+{
+ int b64_len;
+
+ /* First, make sure we have data to work with.
+ */
+ if(ctx->encrypted_msg == NULL
+ || strlen(ctx->encrypted_msg) < MIN_SPA_ENCODED_MSG_SIZE)
+ return(FKO_ERROR_INVALID_DATA);
+
+ /* Determine type of encryption used. For know, we are using the
+ * size of the message.
+ *
+ * XXX: We will want to come up with a more reliable method of
+ * identifying the encryption type.
+ */
+ b64_len = strlen(ctx->encrypted_msg);
+
+ if(b64_len > MIN_GNUPG_MSG_SIZE)
+ {
+ ctx->encryption_type = FKO_ENCRYPTION_GPG;
+#if HAVE_LIBGPGME
+ return(FKO_ERROR_UNSUPPORTED_FEATURE);
+ //return(_gpg_decrypt(ctx, dec_key));
+#else
+ return(FKO_ERROR_UNSUPPORTED_FEATURE);
+#endif
+ }
+ else /* We are assuming the default of Rijndael */
+ {
+ ctx->encryption_type = FKO_ENCRYPTION_RIJNDAEL;
+ return(_rijndael_decrypt(ctx, dec_key, b64_len));
+ }
+}
+
+/* Set the GPG recipient key name.
+*/
+int
+fko_set_gpg_recipient(fko_ctx_t ctx, const char *recip)
+{
+#if HAVE_LIBGPGME
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+ if(ctx->encryption_type != FKO_ENCRYPTION_GPG)
+ return(FKO_ERROR_WRONG_ENCRYPTION_TYPE);
+
+ ctx->gpg_recipient = strdup(recip);
+ if(ctx->gpg_recipient == NULL)
+ return(FKO_ERROR_MEMORY_ALLOCATION);
+
+ ctx->state |= FKO_DATA_MODIFIED;
+
+ return(FKO_SUCCESS);
+#else
+ return(FKO_ERROR_UNSUPPORTED_FEATURE);
+#endif /* HAVE_LIBGPGME */
+}
+
+/* Get the GPG recipient key name.
+*/
+char*
+fko_get_gpg_recipient(fko_ctx_t ctx)
+{
+#if HAVE_LIBGPGME
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(NULL);
+
+ return(ctx->gpg_recipient);
+#else
+ //--DSS we should make this an error
+ return(NULL);
+#endif /* HAVE_LIBGPGME */
+}
+
+/* Set the GPG signer key name.
+*/
+int
+fko_set_gpg_signer(fko_ctx_t ctx, const char *signer)
+{
+#if HAVE_LIBGPGME
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+ if(ctx->encryption_type != FKO_ENCRYPTION_GPG)
+ return(FKO_ERROR_WRONG_ENCRYPTION_TYPE);
+
+ ctx->gpg_signer = strdup(signer);
+ if(ctx->gpg_signer == NULL)
+ return(FKO_ERROR_MEMORY_ALLOCATION);
+
+ ctx->state |= FKO_DATA_MODIFIED;
+
+ return(FKO_SUCCESS);
+#else
+ return(FKO_ERROR_UNSUPPORTED_FEATURE);
+#endif /* HAVE_LIBGPGME */
+}
+
+/* Get the GPG signer key name.
+*/
+char*
+fko_get_gpg_signer(fko_ctx_t ctx)
+{
+#if HAVE_LIBGPGME
+ /* Must be initialized
+ */
+ if(!CTX_INITIALIZED(ctx))
+ return(NULL);
+
+ return(ctx->gpg_signer);
+#else
+ //--DSS we should make this an error
+ return(NULL);
+#endif /* HAVE_LIBGPGME */
+}
+
/***EOF***/
View
2  fko/fko_error.c
@@ -44,6 +44,8 @@ static const char *fko_err_msgs[] = {
"Invalid SPA access mesage format",
"Invalid SPA nat_access mesage format",
"Invalid encryption type",
+ "Wrong or inappropriate encryption type for this operation",
+ "Missing GPG key data (signer or recipient not set)",
"Unexpected or invalid size for decrypted data",
"The computed digest did not match the digest in the spa data",
"Unsupported or unimplemented feature or function",
View
12 fko/fko_funcs.c
@@ -209,6 +209,14 @@ fko_destroy(fko_ctx_t ctx)
if(ctx->encrypted_msg != NULL)
free(ctx->encrypted_msg);
+#if HAVE_LIBGPGME
+ if(ctx->gpg_recipient != NULL)
+ free(ctx->gpg_recipient);
+
+ if(ctx->gpg_signer != NULL)
+ free(ctx->gpg_signer);
+
+#endif /* HAVE_LIBGPGME */
bzero(ctx, sizeof(fko_ctx_t));
}
@@ -235,8 +243,6 @@ fko_version(fko_ctx_t ctx)
int
fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
{
- int res;
-
/* Must be initialized
*/
if(!CTX_INITIALIZED(ctx))
@@ -250,8 +256,6 @@ fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
char*
fko_get_spa_data(fko_ctx_t ctx)
{
- int res;
-
/* Must be initialized
*/
if(!CTX_INITIALIZED(ctx))
View
2  fko/fko_message.c
@@ -123,7 +123,7 @@ fko_set_spa_message(fko_ctx_t ctx, const char *msg)
ctx->message = strdup(msg);
- ctx->state |= FKO_SPA_MSG_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
if(ctx->message == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
View
2  fko/fko_nat_access.c
@@ -55,7 +55,7 @@ fko_set_spa_nat_access(fko_ctx_t ctx, const char *msg)
ctx->nat_access = strdup(msg);
- ctx->state |= FKO_NAT_ACCESS_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
if(ctx->nat_access == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
View
4 fko/fko_rand_value.c
@@ -61,7 +61,7 @@ fko_set_rand_value(fko_ctx_t ctx, const char *new_val)
if(ctx->rand_val == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
- ctx->state |= FKO_RAND_VAL_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
return(FKO_SUCCESS);
}
@@ -106,7 +106,7 @@ fko_set_rand_value(fko_ctx_t ctx, const char *new_val)
free(tmp_buf);
- ctx->state |= FKO_RAND_VAL_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
return(FKO_SUCCESS);
}
View
2  fko/fko_server_auth.c
@@ -69,7 +69,7 @@ fko_set_spa_server_auth(fko_ctx_t ctx, const char *msg)
ctx->server_auth = strdup(msg);
- ctx->state |= FKO_SERVER_AUTH_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
if(ctx->server_auth == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
View
32 fko/fko_state.h
@@ -30,19 +30,20 @@
*/
typedef enum {
FKO_CTX_SET = 1, /* Set when ctx is initialized */
- FKO_RAND_VAL_MODIFIED = 1 << 1,
- FKO_USERNAME_MODIFIED = 1 << 2,
- FKO_TIMESTAMP_MODIFIED = 1 << 3,
- FKO_VERSION_MODIFIED = 1 << 4,
+ FKO_DATA_MODIFIED = 1 << 1,
+ FKO_STATE_RESERVED_2 = 1 << 2,
+ STATE_RESERVED_3 = 1 << 3,
+ STATE_RESERVED_4 = 1 << 4,
+ STATE_RESERVED_5 = 1 << 5,
FKO_SPA_MSG_TYPE_MODIFIED = 1 << 6,
FKO_CTX_SET_2 = 1 << 7, /* Set when ctx is initialized */
- FKO_SPA_MSG_MODIFIED = 1 << 8,
- FKO_NAT_ACCESS_MODIFIED = 1 << 9,
- FKO_SERVER_AUTH_MODIFIED = 1 << 10,
- FKO_CLIENT_TIMEOUT_MODIFIED = 1 << 11,
+ STATE_RESERVED_8 = 1 << 8,
+ STATE_RESERVED_9 = 1 << 9,
+ STATE_RESERVED_10 = 1 << 10,
+ STATE_RESERVED_11 = 1 << 11,
FKO_DIGEST_TYPE_MODIFIED = 1 << 12,
FKO_ENCRYPT_TYPE_MODIFIED = 1 << 13,
- FKO_GPG_SUPPORTED = 1 << 14,
+ STATE_RESERVED_14 = 1 << 14,
FKO_BACKWARD_COMPATIBLE = 1 << 15
} fko_state_flags_t;
@@ -62,23 +63,20 @@ typedef enum {
/* Consolidate all SPA data modified flags.
*/
-#define FKO_ANY_SPA_DATA_MODIFIED ( \
- FKO_RAND_VAL_MODIFIED | FKO_USERNAME_MODIFIED | FKO_TIMESTAMP_MODIFIED \
- | FKO_VERSION_MODIFIED | FKO_SPA_MSG_TYPE_MODIFIED | FKO_SPA_MSG_MODIFIED \
- | FKO_NAT_ACCESS_MODIFIED | FKO_SERVER_AUTH_MODIFIED \
- | FKO_CLIENT_TIMEOUT_MODIFIED | FKO_DIGEST_TYPE_MODIFIED \
- | FKO_ENCRYPT_TYPE_MODIFIED )
+#define FKO_SPA_DATA_MODIFIED ( \
+ FKO_DATA_MODIFIED | FKO_SPA_MSG_TYPE_MODIFIED \
+ | FKO_DIGEST_TYPE_MODIFIED | FKO_ENCRYPT_TYPE_MODIFIED )
/* This should return true if any SPA data field has been modifed since the
* last encode/encrypt.
*/
-#define FKO_SPA_DATA_MODIFIED(ctx) (ctx->state & FKO_ANY_SPA_DATA_MODIFIED)
+#define FKO_IS_SPA_DATA_MODIFIED(ctx) (ctx->state & FKO_SPA_DATA_MODIFIED)
/* Clear all SPA data modified flags. This is normally called after a
* succesful encode/digest/encryption cycle.
*/
#define FKO_CLEAR_SPA_DATA_MODIFIED(ctx) \
- (ctx->state &= (0xffff & ~FKO_ANY_SPA_DATA_MODIFIED))
+ (ctx->state &= (0xffff & ~FKO_SPA_DATA_MODIFIED))
/* Macros used for determining ctx initialization state.
*/
View
2  fko/fko_timestamp.c
@@ -52,7 +52,7 @@ fko_set_timestamp(fko_ctx_t ctx, int offset)
ctx->timestamp = ts;
- ctx->state |= FKO_TIMESTAMP_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
return(FKO_SUCCESS);
}
View
2  fko/fko_user.c
@@ -82,7 +82,7 @@ fko_set_username(fko_ctx_t ctx, const char *spoof_user)
ctx->username = strdup(username);
- ctx->state |= FKO_USERNAME_MODIFIED;
+ ctx->state |= FKO_DATA_MODIFIED;
if(ctx->username == NULL)
return(FKO_ERROR_MEMORY_ALLOCATION);
View
287 fko/gpgme_funcs.c
@@ -0,0 +1,287 @@
+/* $Id$
+ *****************************************************************************
+ *
+ * File: gpgme_funcs.c
+ *
+ * Author: Damien S. Stuart
+ *
+ * Purpose: gpgme-related functions for GPG encryptions support in libfko.
+ *
+ * Copyright (C) 2008 Damien Stuart (dstuart@dstuart.org)
+ *
+ * License (GNU Public License):
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ *****************************************************************************
+*/
+
+#include "fko_common.h"
+
+#if HAVE_LIBGPGME
+
+#include <gpgme.h>
+#include "gpgme_funcs.h"
+
+/* Callback function that supplies the password when gpgme needs it.
+*/
+gpgme_error_t
+get_gpg_pw(
+ void *hook, const char *uid_hint, const char *passphrase_info,
+ int prev_was_bad, int fd)
+{
+
+ /* We only need to try once as it is fed by the program
+ * (for now --DSS).
+ */
+ if(prev_was_bad)
+ return(GPG_ERR_CANCELED);
+
+ write(fd, (const char*)hook, strlen((const char*)hook));
+ write(fd, "\n", 1);
+
+ return 0;
+}
+
+/* Get the key for the designated signer and add it to the main gpgme context.
+*/
+int
+set_signer(gpgme_ctx_t ctx, const char *signer)
+{
+ gpgme_error_t err;
+ gpgme_ctx_t list_ctx;
+ gpgme_key_t key, key2;
+
+ /* Create a gpgme context for the list
+ */
+ err = gpgme_new(&list_ctx);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ return(gpg_err_code(err));
+ }
+
+ err = gpgme_op_keylist_start(list_ctx, signer, 1);
+
+ if (!err)
+ err = gpgme_op_keylist_next(list_ctx, &key);
+
+ if (err)
+ {
+ gpgme_release(list_ctx);
+ //secret key not found
+ return(gpg_err_code(err));
+ }
+
+ err = gpgme_op_keylist_next(list_ctx, &key2);
+
+ if (!err)
+ {
+ gpgme_key_release(key);
+ gpgme_key_release(key2);
+ gpgme_release(list_ctx);
+ //ambiguous specfication of secret key
+ return(gpg_err_code(err));
+ }
+
+ gpgme_op_keylist_end(list_ctx);
+ gpgme_release(list_ctx);
+
+ gpgme_signers_clear(ctx);
+
+ err = gpgme_signers_add(ctx, key);
+
+ gpgme_key_release(key);
+
+ if (err)
+ {
+ //error setting secret key
+ return(gpg_err_code(err));
+ }
+
+ return 0;
+}
+
+int
+get_recip_key(gpgme_key_t *mykey, const char *recip)
+{
+ gpgme_error_t err;
+ gpgme_ctx_t list_ctx;
+ gpgme_key_t key, key2;
+
+ /* Create a gpgme context for the list
+ */
+ err = gpgme_new(&list_ctx);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ return(gpg_err_code(err));
+ }
+
+ err = gpgme_op_keylist_start(list_ctx, recip, 1);
+
+ /* Grab the first key in the list (we hope it is the only one).
+ */
+ err = gpgme_op_keylist_next(list_ctx, &key);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ gpgme_release(list_ctx);
+ return(gpg_err_code(err));
+ }
+
+ /* We try to get the next key match. If we do, then the name is
+ * ambiguous, so we return an error.
+ */
+ err = gpgme_op_keylist_next(list_ctx, &key2);
+ if(gpg_err_code(err) == GPG_ERR_NO_ERROR) /* Note: look for NO error */
+ {
+ gpgme_key_release(key);
+ gpgme_key_release(key2);
+ gpgme_release(list_ctx);
+ //ambiguous specfication of secret key
+ return(gpg_err_code(err));
+ }
+
+ gpgme_op_keylist_end(list_ctx);
+
+ //printf("Got Key:\n%s: %s <%s>\n",
+ // key->subkeys->keyid, key->uids->name, key->uids->email);
+
+ /* Make our key the first entry in the array (just more gpgme funkyness).
+ */
+ *mykey = key;
+
+ return(0);
+}
+
+/* The main GPG encryption routine for libfko.
+*/
+int
+gpgme_encrypt(
+ unsigned char *indata, size_t in_len, const char *signer, const char *recip,
+ const char *pw, unsigned char **out, size_t *out_len)
+{
+ char *tmp_buf;
+ int res;
+
+ gpgme_ctx_t gpg_ctx;
+ gpgme_error_t err;
+ gpgme_key_t key[2] = {0};
+ gpgme_data_t data;
+ gpgme_data_t plaintext;
+
+ /* Because the gpgme manual says you should.
+ */
+ gpgme_check_version(NULL);
+
+ /* Check for OpenPGP support
+ */
+ err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ /* GPG engine is not available. */
+ return(gpg_err_code(err));
+ }
+
+ /* Create our gpgme context
+ */
+ err = gpgme_new(&gpg_ctx);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ return(gpg_err_code(err));
+ }
+
+ /* Initialize the plaintext data (place into gpgme_data object)
+ */
+ err = gpgme_data_new_from_mem(&plaintext, (char*)indata, in_len, 1);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ gpgme_release(gpg_ctx);
+ return(gpg_err_code(err));
+ }
+
+ /* Set protocol
+ */
+ err = gpgme_set_protocol(gpg_ctx, GPGME_PROTOCOL_OpenPGP);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ gpgme_release(gpg_ctx);
+ return(gpg_err_code(err));
+ }
+
+ /* Set ascii-armor off (we will be base64-encoding the encrypted data
+ * ourselves.
+ */
+ gpgme_set_armor(gpg_ctx, 0);
+
+ /* Get the signer gpg key
+ */
+ err = set_signer(gpg_ctx, signer);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ gpgme_release(gpg_ctx);
+ return(gpg_err_code(err));
+ }
+
+ /* Get the recipient gpg key
+ */
+ err = get_recip_key((gpgme_key_t*)&key, recip);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ gpgme_release(gpg_ctx);
+ return(gpg_err_code(err));
+ }
+
+ /* Create the buffer for our encrypted data.
+ */
+ err = gpgme_data_new(&data);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ gpgme_release(gpg_ctx);
+
+ return(gpg_err_code(err));
+ }
+
+ /* Set the passphrase callback.
+ */
+ gpgme_set_passphrase_cb(gpg_ctx, get_gpg_pw, pw);
+
+ err = gpgme_op_encrypt_sign(gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, data);
+ if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
+ {
+ //fprintf(stderr, "*Ecrypt&Sign Error: %s\n", gpgme_strerror(err));
+ gpgme_release(gpg_ctx);
+
+ return(gpg_err_code(err));
+ }
+
+ /* Get the encrypted data and its length from the gpgme data object.
+ */
+ tmp_buf = gpgme_data_release_and_get_mem(data, out_len);
+
+ *out = malloc(*out_len); /* Note: this is freed when the context is destroyed */
+ if(*out == NULL)
+ {
+ res = -2;
+ }
+ else
+ {
+ res = 0;
+ memcpy(*out, tmp_buf, *out_len);
+ }
+
+ gpgme_free(tmp_buf);
+ gpgme_release(gpg_ctx);
+
+ return(res);
+}
+
+#endif /* HAVE_LIBGPGME */
+
+/***EOF***/
View
34 fko/gpgme_funcs.h
@@ -0,0 +1,34 @@
+/* $Id$
+ *****************************************************************************
+ *
+ * File: gpgme_funcs.h
+ *
+ * Author: Damien S. Stuart
+ *
+ * Purpose: Header for the fwknop gpgme_funcs.c.
+ *
+ * License (GNU Public License):
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ *****************************************************************************
+*/
+#ifndef GPGME_FUNCS_H
+#define GPGME_FUNCS_H 1
+
+#include "fko_common.h"
+
+int gpgme_encrypt(unsigned char *in, size_t len, const char *signer, const char *recip, const char *pw, unsigned char **out, size_t *out_len);
+int gpgme_decrypt(unsigned char *in, size_t len, const char *pw, unsigned char **out, size_t *out_len);
+
+#endif /* GPGME_FUNCS_H */
+
+/***EOF***/
Please sign in to comment.
Something went wrong with that request. Please try again.