First cut at GPG encrytion support (decryption and doc update are pending).
git-svn-id: file:///home/mbr/svn/fwknop/trunk@39 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
parent
04674071ef
commit
e846cdd44d
14
configure.ac
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
|
||||
"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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***/
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -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***/
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -30,6 +30,179 @@
|
||||
|
||||
#define B64_RIJNDAEL_SALT "U2FsdGVkX1"
|
||||
|
||||
/* Prep and encrypt using Rijndael
|
||||
*/
|
||||
int
|
||||
_rijndael_encrypt(fko_ctx_t ctx, const char *enc_key)
|
||||
{
|
||||
char *plain;
|
||||
char *b64cipher;
|
||||
unsigned char *cipher;
|
||||
int cipher_len;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Make a bucket for the encrypted version and populate it.
|
||||
*/
|
||||
cipher = malloc(strlen(plain) + 32); /* Plus padding for salt and Block */
|
||||
if(cipher == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
cipher_len = rij_encrypt(
|
||||
(unsigned char*)plain, strlen(plain), (char*)enc_key, cipher
|
||||
);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Decode, decrypt, and parse SPA data into the context.
|
||||
*/
|
||||
int
|
||||
_rijndael_decrypt(fko_ctx_t ctx, const char *dec_key, int b64_len)
|
||||
{
|
||||
char *tbuf;
|
||||
unsigned char *cipher;
|
||||
int cipher_len, pt_len;
|
||||
|
||||
/* Now see if we need to add the "Salted__" string to the front of the
|
||||
* encrypted data.
|
||||
*/
|
||||
if(strncmp(ctx->encrypted_msg, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT)))
|
||||
{
|
||||
/* We need to realloc space for the salt.
|
||||
*/
|
||||
tbuf = realloc(ctx->encrypted_msg, b64_len + 12);
|
||||
if(tbuf == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
memmove(tbuf+10, tbuf, b64_len);
|
||||
ctx->encrypted_msg = memcpy(tbuf, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT));
|
||||
}
|
||||
|
||||
/* Create a bucket for the (base64) decoded encrypted data and get the
|
||||
* raw cipher data.
|
||||
*/
|
||||
cipher = malloc(strlen(ctx->encrypted_msg));
|
||||
if(cipher == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
cipher_len = b64_decode(ctx->encrypted_msg, cipher, b64_len);
|
||||
|
||||
/* Create a bucket for the plaintext data and decrypt the message
|
||||
* data into it.
|
||||
*/
|
||||
ctx->encoded_msg = malloc(cipher_len);
|
||||
if(ctx->encoded_msg == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
pt_len = rij_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
|
||||
|
||||
/* Done with cipher...
|
||||
*/
|
||||
free(cipher);
|
||||
|
||||
/* The length of the decrypted data should be within 16 of the
|
||||
* length of the encrypted version.
|
||||
*/
|
||||
if(pt_len < (cipher_len - 32))
|
||||
return(FKO_ERROR_DECRYPTION_SIZE_ERROR);
|
||||
|
||||
/* Call fko_decode and return the results.
|
||||
*/
|
||||
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
|
||||
@ -68,10 +241,7 @@ fko_get_spa_encryption_type(fko_ctx_t ctx)
|
||||
int
|
||||
fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
||||
{
|
||||
char *plain;
|
||||
char *b64cipher;
|
||||
unsigned char *cipher;
|
||||
int cipher_len, res;
|
||||
int res;
|
||||
|
||||
/* Must be initialized
|
||||
*/
|
||||
@ -81,7 +251,7 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
||||
/* 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))
|
||||
if(ctx->encoded_msg == NULL || FKO_IS_SPA_DATA_MODIFIED(ctx))
|
||||
{
|
||||
res = fko_encode_spa_data(ctx);
|
||||
|
||||
@ -96,46 +266,20 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
||||
if(strlen(ctx->encoded_msg) < MIN_SPA_ENCODED_MSG_SIZE)
|
||||
return(FKO_ERROR_MISSING_ENCODED_DATA);
|
||||
|
||||
/* Make a bucket big enough to hold the enc msg + digest (plaintext)
|
||||
* and populate it appropriately.
|
||||
/* Encrypt according to type and return...
|
||||
*/
|
||||
plain = malloc(strlen(ctx->encoded_msg) + strlen(ctx->digest) + 2);
|
||||
if(plain == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL)
|
||||
return(_rijndael_encrypt(ctx, enc_key));
|
||||
|
||||
sprintf(plain, "%s:%s", ctx->encoded_msg, ctx->digest);
|
||||
else if(ctx->encryption_type == FKO_ENCRYPTION_GPG)
|
||||
#if HAVE_LIBGPGME
|
||||
return(_gpg_encrypt(ctx, enc_key));
|
||||
#else
|
||||
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||
#endif
|
||||
|
||||
/* Make a bucket for the encrypted version and populate it.
|
||||
*/
|
||||
cipher = malloc(strlen(plain) + 32); /* Plus padding for salt and Block */
|
||||
if(cipher == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
cipher_len = fko_encrypt(
|
||||
(unsigned char*)plain, strlen(plain), (char*)enc_key, cipher
|
||||
);
|
||||
|
||||
/* 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);
|
||||
else
|
||||
return(FKO_ERROR_INVALID_ENCRYPTION_TYPE);
|
||||
}
|
||||
|
||||
/* Decode, decrypt, and parse SPA data into the context.
|
||||
@ -143,9 +287,7 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key)
|
||||
int
|
||||
fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
|
||||
{
|
||||
char *tbuf;
|
||||
unsigned char *cipher;
|
||||
int b64_len, cipher_len, pt_len;
|
||||
int b64_len;
|
||||
|
||||
/* First, make sure we have data to work with.
|
||||
*/
|
||||
@ -154,65 +296,116 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
|
||||
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.
|
||||
* 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)
|
||||
{
|
||||
/* TODO: add GPG handling */
|
||||
/* Since we do not support GPG yet, we will just fall through */
|
||||
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
|
||||
}
|
||||
|
||||
/* Assuming Rijndael */
|
||||
|
||||
/* Now see if we need to add the "Salted__" string to the front of the
|
||||
* encrypted data.
|
||||
*/
|
||||
if(strncmp(ctx->encrypted_msg, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT)))
|
||||
else /* We are assuming the default of Rijndael */
|
||||
{
|
||||
/* We need to realloc space for the salt.
|
||||
*/
|
||||
tbuf = realloc(ctx->encrypted_msg, b64_len + 12);
|
||||
if(tbuf == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
memmove(tbuf+10, tbuf, b64_len);
|
||||
ctx->encrypted_msg = memcpy(tbuf, B64_RIJNDAEL_SALT, strlen(B64_RIJNDAEL_SALT));
|
||||
ctx->encryption_type = FKO_ENCRYPTION_RIJNDAEL;
|
||||
return(_rijndael_decrypt(ctx, dec_key, b64_len));
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a bucket for the (base64) decoded encrypted data and get the
|
||||
* raw cipher data.
|
||||
/* Set the GPG recipient key name.
|
||||
*/
|
||||
int
|
||||
fko_set_gpg_recipient(fko_ctx_t ctx, const char *recip)
|
||||
{
|
||||
#if HAVE_LIBGPGME
|
||||
/* Must be initialized
|
||||
*/
|
||||
cipher = malloc(strlen(ctx->encrypted_msg));
|
||||
if(cipher == NULL)
|
||||
return(FKO_ERROR_MEMORY_ALLOCATION);
|
||||
|
||||
cipher_len = b64_decode(ctx->encrypted_msg, cipher, b64_len);
|
||||
if(!CTX_INITIALIZED(ctx))
|
||||
return(FKO_ERROR_CTX_NOT_INITIALIZED);
|
||||
|
||||
/* Create a bucket for the plaintext data and decrypt the message
|
||||
* data into it.
|
||||
*/
|
||||
ctx->encoded_msg = malloc(cipher_len);
|
||||
if(ctx->encoded_msg == NULL)
|
||||
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);
|
||||
|
||||
pt_len = fko_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
|
||||
|
||||
/* Done with cipher...
|
||||
*/
|
||||
free(cipher);
|
||||
ctx->state |= FKO_DATA_MODIFIED;
|
||||
|
||||
/* The length of the decrypted data should be within 16 of the
|
||||
* length of the encrypted version.
|
||||
*/
|
||||
if(pt_len < (cipher_len - 32))
|
||||
return(FKO_ERROR_DECRYPTION_SIZE_ERROR);
|
||||
return(FKO_SUCCESS);
|
||||
#else
|
||||
return(FKO_ERROR_UNSUPPORTED_FEATURE);
|
||||
#endif /* HAVE_LIBGPGME */
|
||||
}
|
||||
|
||||
/* Call fko_decode and return the results.
|
||||
/* Get the GPG recipient key name.
|
||||
*/
|
||||
char*
|
||||
fko_get_gpg_recipient(fko_ctx_t ctx)
|
||||
{
|
||||
#if HAVE_LIBGPGME
|
||||
/* Must be initialized
|
||||
*/
|
||||
return(fko_decode_spa_data(ctx));
|
||||
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***/
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
287
fko/gpgme_funcs.c
Normal file
287
fko/gpgme_funcs.c
Normal file
@ -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***/
|
||||
34
fko/gpgme_funcs.h
Normal file
34
fko/gpgme_funcs.h
Normal file
@ -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***/
|
||||
Loading…
x
Reference in New Issue
Block a user