Ejemplo n.º 1
0
int
fko_verify_hmac(fko_ctx_t ctx,
    const char * const hmac_key, const int hmac_key_len)
{
    char    *hmac_digest_from_data = NULL;
    char    *tbuf = NULL;
    int      res = FKO_SUCCESS;
    int      hmac_b64_digest_len = 0, zero_free_rv = FKO_SUCCESS;

    /* Must be initialized
    */
    if(!CTX_INITIALIZED(ctx))
        return(FKO_ERROR_CTX_NOT_INITIALIZED);

    if (! is_valid_encoded_msg_len(ctx->encrypted_msg_len))
        return(FKO_ERROR_INVALID_DATA_HMAC_MSGLEN_VALIDFAIL);

    if(hmac_key_len > MAX_DIGEST_BLOCK_LEN)
        return(FKO_ERROR_INVALID_HMAC_KEY_LEN);

    if(ctx->hmac_type == FKO_HMAC_MD5)
        hmac_b64_digest_len = MD5_B64_LEN;
    else if(ctx->hmac_type == FKO_HMAC_SHA1)
        hmac_b64_digest_len = SHA1_B64_LEN;
    else if(ctx->hmac_type == FKO_HMAC_SHA256)
        hmac_b64_digest_len = SHA256_B64_LEN;
    else if(ctx->hmac_type == FKO_HMAC_SHA384)
        hmac_b64_digest_len = SHA384_B64_LEN;
    else if(ctx->hmac_type == FKO_HMAC_SHA512)
        hmac_b64_digest_len = SHA512_B64_LEN;
    else
        return(FKO_ERROR_UNSUPPORTED_HMAC_MODE);

    if((ctx->encrypted_msg_len - hmac_b64_digest_len)
            < MIN_SPA_ENCODED_MSG_SIZE)
        return(FKO_ERROR_INVALID_DATA_HMAC_ENCMSGLEN_VALIDFAIL);

    /* Get digest value
    */
    hmac_digest_from_data = strndup((ctx->encrypted_msg
            + ctx->encrypted_msg_len - hmac_b64_digest_len),
            hmac_b64_digest_len);

    if(hmac_digest_from_data == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    /* Now we chop the HMAC digest off of the encrypted msg
    */
    tbuf = strndup(ctx->encrypted_msg,
            ctx->encrypted_msg_len - hmac_b64_digest_len);

    if(tbuf == NULL)
    {
        if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data,
                MAX_SPA_ENCODED_MSG_SIZE)) == FKO_SUCCESS)
            return(FKO_ERROR_MEMORY_ALLOCATION);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    if(zero_free(ctx->encrypted_msg, ctx->encrypted_msg_len) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    ctx->encrypted_msg      = tbuf;
    ctx->encrypted_msg_len -= hmac_b64_digest_len;

    if(ctx->encryption_mode == FKO_ENC_MODE_ASYMMETRIC)
    {
        /* See if we need to add the "hQ" string to the front of the
         * encrypted data.
         */
        if(! ctx->added_gpg_prefix)
        {
            res = add_gpg_prefix(ctx);
        }
    }
    else
    {
        /* See if we need to add the "Salted__" string to the front of the
         * encrypted data.
         */
        if(! ctx->added_salted_str)
        {
            res = add_salted_str(ctx);
        }
    }

    if (res != FKO_SUCCESS)
    {
        if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data,
                        MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

        if(zero_free_rv == FKO_SUCCESS)
            return(res);
        else
            return(zero_free_rv);
    }

    /* Calculate the HMAC from the encrypted data and then
     * compare
    */
    res = fko_set_spa_hmac_type(ctx, ctx->hmac_type);
    if(res == FKO_SUCCESS)
    {
        res = fko_set_spa_hmac(ctx, hmac_key, hmac_key_len);

        if(res == FKO_SUCCESS)
        {
            if(constant_runtime_cmp(hmac_digest_from_data,
                    ctx->msg_hmac, hmac_b64_digest_len) != 0)
            {
                res = FKO_ERROR_INVALID_DATA_HMAC_COMPAREFAIL;
            }
        }
    }

    if(zero_free(hmac_digest_from_data, strnlen(hmac_digest_from_data,
                    MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(res == FKO_SUCCESS)
        return(zero_free_rv);
    else
        return(res);
}
Ejemplo n.º 2
0
static void find_domain_master_name_query_success(struct subnet_record *subrec,
                        struct userdata_struct *userdata_in,
                        struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
{
  /* 
   * Unfortunately, finding the IP address of the Domain Master Browser,
   * as we have here, is not enough. We need to now do a sync to the
   * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
   * respond to the SMBSERVER name. To get this name from IP
   * address we do a Node status request, and look for the first
   * NAME<0x20> in the response, and take that as the server name.
   * We also keep a cache of the Domain Master Browser name for this
   * workgroup in the Workgroup struct, so that if the same IP addess
   * is returned every time, we don't need to do the node status
   * request.
   */

  struct work_record *work;
  struct nmb_name nmbname;
  struct userdata_struct *userdata;
  int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;

  if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
  {
    if( DEBUGLVL( 0 ) )
      {
      dbgtext( "find_domain_master_name_query_success:\n" );
      dbgtext( "Failed to find workgroup %s\n", q_name->name );
      }
    return;
  }

  /* First check if we already have a dmb for this workgroup. */

  if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip))
  {
    /* Do the local master browser announcement to the domain
       master browser name and IP. */
    announce_local_master_browser_to_domain_master_browser( work );

    /* Now synchronise lists with the domain master browser. */
    sync_with_dmb(work);
    return;
  }
  else
    zero_ip(&work->dmb_addr);

  /* Now initiate the node status request. */
  make_nmb_name(&nmbname,"*",0x0);

  /* Put the workgroup name into the userdata so we know
     what workgroup we're talking to when the reply comes
     back. */

  /* Setup the userdata_struct - this is copied so we can use
     a stack variable for this. */
  if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
  {
    DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
    return;
  }

  userdata->copy_fn = NULL;
  userdata->free_fn = NULL;
  userdata->userdata_len = strlen(work->work_group)+1;
  pstrcpy(userdata->data, work->work_group);

  node_status( subrec, &nmbname, answer_ip, 
               domain_master_node_status_success,
               domain_master_node_status_fail,
               userdata);

  zero_free(userdata, size);
}
Ejemplo n.º 3
0
/* Prep and encrypt using Rijndael
*/
static int
_rijndael_encrypt(fko_ctx_t ctx, const char *enc_key, const int enc_key_len)
{
    char           *plaintext;
    char           *b64ciphertext;
    unsigned char  *ciphertext;
    int             cipher_len;
    int             pt_len;
    int             zero_free_rv = FKO_SUCCESS;

    if(enc_key_len > RIJNDAEL_MAX_KEYSIZE)
        return(FKO_ERROR_INVALID_KEY_LEN);

    if (! is_valid_encoded_msg_len(ctx->encoded_msg_len))
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_MSGLEN_VALIDFAIL);

    switch(ctx->digest_len)
    {
        case MD5_B64_LEN:
            break;
        case SHA1_B64_LEN:
            break;
        case SHA256_B64_LEN:
            break;
        case SHA384_B64_LEN:
            break;
        case SHA512_B64_LEN:
            break;
        default:
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_DIGESTLEN_VALIDFAIL);
    }

    pt_len = ctx->encoded_msg_len + ctx->digest_len + RIJNDAEL_BLOCKSIZE + 2;

    /* Make a bucket big enough to hold the enc msg + digest (plaintext)
     * and populate it appropriately.
    */
    plaintext = calloc(1, pt_len);

    if(plaintext == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    pt_len = snprintf(plaintext, pt_len, "%s:%s", ctx->encoded_msg, ctx->digest);

    if(! is_valid_pt_msg_len(pt_len))
    {
        if(zero_free(plaintext, pt_len) == FKO_SUCCESS)
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_PTLEN_VALIDFAIL);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    /* Make a bucket for the encrypted version and populate it.
    */
    ciphertext = calloc(1, pt_len + 32); /* Plus padding for salt and Block */
    if(ciphertext == NULL)
    {
        if(zero_free(plaintext, pt_len) == FKO_SUCCESS)
            return(FKO_ERROR_MEMORY_ALLOCATION);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    cipher_len = rij_encrypt(
        (unsigned char*)plaintext, pt_len,
        (char*)enc_key, enc_key_len,
        ciphertext, ctx->encryption_mode
    );

    /* Now make a bucket for the base64-encoded version and populate it.
    */
    b64ciphertext = malloc(((cipher_len / 3) * 4) + 8);
    if(b64ciphertext == NULL)
    {
        if(zero_free((char *) ciphertext, pt_len+32) == FKO_SUCCESS
                && zero_free(plaintext, pt_len) == FKO_SUCCESS)
            return(FKO_ERROR_MEMORY_ALLOCATION);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    b64_encode(ciphertext, b64ciphertext, cipher_len);
    strip_b64_eq(b64ciphertext);

    if(ctx->encrypted_msg != NULL)
        zero_free_rv = zero_free(ctx->encrypted_msg,
                strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE));

    ctx->encrypted_msg     = strdup(b64ciphertext);
    ctx->encrypted_msg_len = strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE);

    /* Clean-up
    */
    if(zero_free(plaintext, pt_len) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(zero_free((char *) ciphertext, pt_len+32) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(zero_free(b64ciphertext, strnlen(b64ciphertext,
                    MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(ctx->encrypted_msg == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    if(! is_valid_encoded_msg_len(ctx->encrypted_msg_len))
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_RESULT_MSGLEN_VALIDFAIL);

    return(zero_free_rv);
}
Ejemplo n.º 4
0
/* Prep and decrypt using gpgme
*/
static int
gpg_decrypt(fko_ctx_t ctx, const char *dec_key)
{
    unsigned char  *cipher;
    size_t          cipher_len;
    int             res, pt_len, b64_decode_len;

    /* Now see if we need to add the "hQ" string to the front of the
     * base64-encoded-GPG-encrypted data.
    */
    if(! ctx->added_gpg_prefix)
        add_gpg_prefix(ctx);

    /* Create a bucket for the (base64) decoded encrypted data and get the
     * raw cipher data.
    */
    cipher = malloc(ctx->encrypted_msg_len);
    if(cipher == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    if((b64_decode_len = b64_decode(ctx->encrypted_msg, cipher)) < 0)
    {
        if(zero_free((char *) cipher, ctx->encrypted_msg_len) == FKO_SUCCESS)
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_CIPHER_DECODEFAIL);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);

    }

    cipher_len = b64_decode_len;

    /* Create a bucket for the plaintext data and decrypt the message
     * data into it.
    */
    /* --DSS Actually, the needed memory will be malloced in the gpgme_decrypt
    //       function. Just leaving this here for reference (for now).
    //ctx->encoded_msg = malloc(cipher_len);
    //if(ctx->encoded_msg == NULL)
    //    return(FKO_ERROR_MEMORY_ALLOCATION);
    */

    res = gpgme_decrypt(ctx, cipher, cipher_len,
        dec_key, (unsigned char**)&ctx->encoded_msg, &cipher_len
    );

    /* Done with cipher...
    */
    if(res != FKO_SUCCESS)
    {
        if(zero_free((char *) cipher, ctx->encrypted_msg_len) != FKO_SUCCESS)
            return(FKO_ERROR_ZERO_OUT_DATA);
        else
            return(res);
    }

    pt_len = strnlen(ctx->encoded_msg, MAX_SPA_ENCODED_MSG_SIZE);

    if(ctx->encoded_msg == NULL)
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_DECRYPTED_MESSAGE_MISSING);

    if(! is_valid_encoded_msg_len(pt_len))
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_DECRYPTED_MSGLEN_VALIDFAIL);

    ctx->encoded_msg_len = pt_len;

    /* Call fko_decode and return the results.
    */
    return(fko_decode_spa_data(ctx));
}
Ejemplo n.º 5
0
/* Prep and encrypt using gpgme
*/
static int
gpg_encrypt(fko_ctx_t ctx, const char *enc_key)
{
    int             res;
    char           *plain;
    int             pt_len, zero_free_rv = FKO_SUCCESS;
    char           *b64cipher;
    unsigned char  *cipher = NULL;
    size_t          cipher_len;
    char           *empty_key = "";

    if (! is_valid_encoded_msg_len(ctx->encoded_msg_len))
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_MESSAGE_VALIDFAIL);

    switch(ctx->digest_len)
    {
        case MD5_B64_LEN:
            break;
        case SHA1_B64_LEN:
            break;
        case SHA256_B64_LEN:
            break;
        case SHA384_B64_LEN:
            break;
        case SHA512_B64_LEN:
            break;
        default:
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_DIGEST_VALIDFAIL);
    }

    /* First make sure we have a recipient key set.
    */
    if(ctx->gpg_recipient == NULL)
        return(FKO_ERROR_MISSING_GPG_KEY_DATA);

    pt_len = ctx->encoded_msg_len + ctx->digest_len + 2;

    /* Make a bucket big enough to hold the enc msg + digest (plaintext)
     * and populate it appropriately.
    */
    plain = malloc(ctx->encoded_msg_len + ctx->digest_len + 2);
    if(plain == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    pt_len = snprintf(plain, pt_len+1, "%s:%s", ctx->encoded_msg, ctx->digest);

    if(! is_valid_pt_msg_len(pt_len))
    {
        if(zero_free(plain, pt_len) == FKO_SUCCESS)
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_MSGLEN_VALIDFAIL);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    if (enc_key != NULL)
    {
        res = gpgme_encrypt(ctx, (unsigned char*)plain, pt_len,
            enc_key, &cipher, &cipher_len
        );
    }
    else
    {
        res = gpgme_encrypt(ctx, (unsigned char*)plain, pt_len,
            empty_key, &cipher, &cipher_len
        );
    }

    /* --DSS XXX: Better parsing of what went wrong would be nice :)
    */
    if(res != FKO_SUCCESS)
    {
        zero_free_rv = zero_free(plain, pt_len);

        if(cipher != NULL)
            if(zero_free((char *) cipher, cipher_len) != FKO_SUCCESS)
                zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

        if(zero_free_rv == FKO_SUCCESS)
            return(res);
        else
            return(zero_free_rv);
    }

    /* Now make a bucket for the base64-encoded version and populate it.
    */
    b64cipher = malloc(((cipher_len / 3) * 4) + 8);
    if(b64cipher == NULL)
    {
        if(zero_free(plain, pt_len) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

        if(cipher != NULL)
            if(zero_free((char *) cipher, cipher_len) != FKO_SUCCESS)
                zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

        if(zero_free_rv == FKO_SUCCESS)
            return(FKO_ERROR_MEMORY_ALLOCATION);
        else
            return(zero_free_rv);
    }

    b64_encode(cipher, b64cipher, cipher_len);
    strip_b64_eq(b64cipher);

    if(ctx->encrypted_msg != NULL)
        zero_free_rv = zero_free(ctx->encrypted_msg,
                strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE));

    ctx->encrypted_msg     = strdup(b64cipher);
    ctx->encrypted_msg_len = strnlen(ctx->encrypted_msg, MAX_SPA_ENCODED_MSG_SIZE);

    /* Clean-up
    */
    if(zero_free(plain, pt_len) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(zero_free((char *) cipher, cipher_len) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(zero_free(b64cipher, strnlen(b64cipher,
                    MAX_SPA_ENCODED_MSG_SIZE)) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(ctx->encrypted_msg == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    if(! is_valid_encoded_msg_len(ctx->encrypted_msg_len))
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_RESULT_MSGLEN_VALIDFAIL);

    return(zero_free_rv);
}
Ejemplo n.º 6
0
/* Decode, decrypt, and parse SPA data into the context.
*/
static int
_rijndael_decrypt(fko_ctx_t ctx,
    const char *dec_key, const int key_len, int encryption_mode)
{
    unsigned char  *ndx;
    unsigned char  *cipher;
    int             cipher_len, pt_len, i, err = 0, res = FKO_SUCCESS;
    int             zero_free_rv = FKO_SUCCESS;

    if(key_len > RIJNDAEL_MAX_KEYSIZE)
        return(FKO_ERROR_INVALID_KEY_LEN);

    /* Now see if we need to add the "Salted__" string to the front of the
     * encrypted data.
    */
    if(! ctx->added_salted_str)
    {
        res = add_salted_str(ctx);
        if(res != FKO_SUCCESS)
            return res;
    }

    /* Create a bucket for the (base64) decoded encrypted data and get the
     * raw cipher data.
    */
    cipher = malloc(ctx->encrypted_msg_len);
    if(cipher == NULL)
        return(FKO_ERROR_MEMORY_ALLOCATION);

    if((cipher_len = b64_decode(ctx->encrypted_msg, cipher)) < 0)
    {
        if(zero_free((char *)cipher, ctx->encrypted_msg_len) == FKO_SUCCESS)
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_CIPHERLEN_DECODEFAIL);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    /* Since we're using AES, make sure the incoming data is a multiple of
     * the blocksize
    */
    if((cipher_len % RIJNDAEL_BLOCKSIZE) != 0)
    {
        if(zero_free((char *)cipher, ctx->encrypted_msg_len) == FKO_SUCCESS)
            return(FKO_ERROR_INVALID_DATA_ENCRYPT_CIPHERLEN_VALIDFAIL);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    if(ctx->encoded_msg != NULL)
        zero_free_rv = zero_free(ctx->encoded_msg,
                strnlen(ctx->encoded_msg, MAX_SPA_ENCODED_MSG_SIZE));

    /* 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(zero_free((char *)cipher, ctx->encrypted_msg_len) == FKO_SUCCESS)
            return(FKO_ERROR_MEMORY_ALLOCATION);
        else
            return(FKO_ERROR_ZERO_OUT_DATA);
    }

    pt_len = rij_decrypt(cipher, cipher_len, dec_key, key_len,
                (unsigned char*)ctx->encoded_msg, encryption_mode);

    /* Done with cipher...
    */
    if(zero_free((char *)cipher, ctx->encrypted_msg_len) != FKO_SUCCESS)
        zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    /* The length of the decrypted data should be within 32 bytes of the
     * length of the encrypted version.
    */
    if(pt_len < (cipher_len - 32) || pt_len <= 0)
        return(FKO_ERROR_DECRYPTION_SIZE);

    if(ctx->encoded_msg == NULL)
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_ENCODEDMSG_NULL);

    if(! is_valid_encoded_msg_len(pt_len))
        return(FKO_ERROR_INVALID_DATA_ENCRYPT_GPG_ENCODEDMSGLEN_VALIDFAIL);

    if(zero_free_rv != FKO_SUCCESS)
        return(zero_free_rv);

    ctx->encoded_msg_len = pt_len;

    /* At this point we can check the data to see if we have a good
     * decryption by ensuring the first field (16-digit random decimal
     * value) is valid and is followed by a colon.  Additional checks
     * are made in fko_decode_spa_data().
    */
    ndx = (unsigned char *)ctx->encoded_msg;
    for(i=0; i<FKO_RAND_VAL_SIZE; i++)
        if(!isdigit(*(ndx++)))
            err++;

    if(err > 0 || *ndx != ':')
        return(FKO_ERROR_DECRYPTION_FAILURE);

    /* Call fko_decode and return the results.
    */
    return(fko_decode_spa_data(ctx));
}
Ejemplo n.º 7
0
/* Destroy a context and free its resources
*/
int
fko_destroy(fko_ctx_t ctx)
{
    int zero_free_rv = FKO_SUCCESS;

#if HAVE_LIBGPGME
    fko_gpg_sig_t   gsig, tgsig;
#endif

    if(!CTX_INITIALIZED(ctx))
        return(zero_free_rv);

    if(ctx->rand_val != NULL)
        free(ctx->rand_val);

    if(ctx->username != NULL)
        free(ctx->username);

    if(ctx->version != NULL)
        free(ctx->version);

    if(ctx->message != NULL)
        free(ctx->message);

    if(ctx->nat_access != NULL)
        free(ctx->nat_access);

    if(ctx->server_auth != NULL)
        free(ctx->server_auth);

    if(ctx->digest != NULL)
        if(zero_free(ctx->digest, ctx->digest_len) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(ctx->raw_digest != NULL)
        if(zero_free(ctx->raw_digest, ctx->raw_digest_len) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(ctx->encoded_msg != NULL)
        if(zero_free(ctx->encoded_msg, ctx->encoded_msg_len) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(ctx->encrypted_msg != NULL)
        if(zero_free(ctx->encrypted_msg, ctx->encrypted_msg_len) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

    if(ctx->msg_hmac != NULL)
        if(zero_free(ctx->msg_hmac, ctx->msg_hmac_len) != FKO_SUCCESS)
            zero_free_rv = FKO_ERROR_ZERO_OUT_DATA;

#if HAVE_LIBGPGME
    if(ctx->gpg_exe != NULL)
        free(ctx->gpg_exe);

    if(ctx->gpg_home_dir != NULL)
        free(ctx->gpg_home_dir);

    if(ctx->gpg_recipient != NULL)
        free(ctx->gpg_recipient);

    if(ctx->gpg_signer != NULL)
        free(ctx->gpg_signer);

    if(ctx->recipient_key != NULL)
        gpgme_key_unref(ctx->recipient_key);

    if(ctx->signer_key != NULL)
        gpgme_key_unref(ctx->signer_key);

    if(ctx->gpg_ctx != NULL)
        gpgme_release(ctx->gpg_ctx);

    gsig = ctx->gpg_sigs;
    while(gsig != NULL)
    {
        if(gsig->fpr != NULL)
            free(gsig->fpr);

        tgsig = gsig;
        gsig = gsig->next;

        free(tgsig);
    }

#endif /* HAVE_LIBGPGME */

    memset(ctx, 0x0, sizeof(*ctx));

    free(ctx);

    return(zero_free_rv);
}