/*
  sign: This program should be run on the DSS to sign the student's blinded hashed ID as either pass or fail.
  source: http://www.ter.se/dss
*/

#include <stdio.h>
#include <gnunet/platform.h>
#include <gnunet/gnunet_util_lib.h>
#include "common.c"

/**
 * Declaration of functions
 */
int  checkParams (int nrParams, char* params[]);
void showHelp ();

/**
 * Main
 */
int main (int nrParams, char* params[])
{
  // Check parameters to the program.
  if (checkParams (nrParams, params))
  {
    return (1);
  }

  char* passOrFail = params[nrParams - 1]; // The last argument to the program should be "pass" or "fail"

  if (strcmp (params[nrParams - 1], "pass") == 0)
  {
    // Read the blinded hashed pass ID from file.
    char*  blindedHashedPassID;
    size_t sizeBlindedPassID;
    if (readDataFromFile (STUDENT_BLINDED_HASHED_PASS_ID, &blindedHashedPassID, &sizeBlindedPassID))
    {
      return (1);
    }

    // Read the DSS RSA private pass key from file.
    struct GNUNET_CRYPTO_rsa_PrivateKey *privatePassKeyDSS;
    if (readPrivateKeyFromFile (DSS_PRIVATE_PASS_KEY, &privatePassKeyDSS))
    {
      return (1);
    }

    // Extract the DSS RSA public pass key out of the DSS RSA private pass key.
    struct GNUNET_CRYPTO_rsa_PublicKey *publicPassKeyDSS;
    printf ("Extract the DSS RSA public pass key out of the DSS RSA private pass key.\n");
    publicPassKeyDSS = GNUNET_CRYPTO_rsa_private_key_get_public (privatePassKeyDSS);

    // Sign the blinded hashed pass ID with the DSS RSA private pass key
    struct GNUNET_CRYPTO_rsa_Signature *signedBlindedHashedPassID;
    signedBlindedHashedPassID = GNUNET_CRYPTO_rsa_sign (privatePassKeyDSS, blindedHashedPassID, sizeBlindedPassID);
    GNUNET_free (blindedHashedPassID); // Free the blinded hashed pass ID

    // Write the DSS RSA-signature of blinded hashed pass ID to file.
    if (writeSignatureToFile (DSS_SIGNED_BLINDED_HASHED_ID, &signedBlindedHashedPassID))
    {
      return (1);
    }

    // Free the DSS RSA-signature of blinded hashed pass ID
    GNUNET_CRYPTO_rsa_signature_free (signedBlindedHashedPassID);

    // Free the DSS RSA private pass key
    GNUNET_CRYPTO_rsa_private_key_free (privatePassKeyDSS);

    // Free the DSS RSA public pass key
    GNUNET_CRYPTO_rsa_public_key_free (publicPassKeyDSS);
  }
  else
  if (strcmp (params[nrParams - 1], "fail") == 0)
  {
    // Read the blinded hashed fail ID from file.
    char*  blindedHashedFailID;
    size_t sizeBlindedHashedFailID;
    if (readDataFromFile (STUDENT_BLINDED_HASHED_FAIL_ID, &blindedHashedFailID, &sizeBlindedHashedFailID))
    {
      return (1);
    }

    // Read the DSS RSA private fail key from file.
    struct GNUNET_CRYPTO_rsa_PrivateKey *privateFailKeyDSS;
    if (readPrivateKeyFromFile (DSS_PRIVATE_FAIL_KEY, &privateFailKeyDSS))
    {
      return (1);
    }

    // Extract the DSS RSA public fail key out of the DSS RSA private fail key.
    struct GNUNET_CRYPTO_rsa_PublicKey *publicFailKeyDSS;
    printf ("Extract the DSS RSA public fail key out of the DSS RSA private fail key.\n");
    publicFailKeyDSS = GNUNET_CRYPTO_rsa_private_key_get_public (privateFailKeyDSS);

    // Sign the blinded hashed fail ID with the DSS RSA private fail key
    struct GNUNET_CRYPTO_rsa_Signature *signedBlindedHashedFailID;
    signedBlindedHashedFailID = GNUNET_CRYPTO_rsa_sign (privateFailKeyDSS, blindedHashedFailID, sizeBlindedHashedFailID);
    GNUNET_free (blindedHashedFailID); // Free the blinded hashed fail ID

    // Write the DSS RSA-signature of blinded hashed fail ID to file.
    if (writeSignatureToFile (DSS_SIGNED_BLINDED_HASHED_ID, &signedBlindedHashedFailID))
    {
      return (1);
    }

    // Free the DSS RSA-signature of blinded hashed fail ID
    GNUNET_CRYPTO_rsa_signature_free (signedBlindedHashedFailID);

    // Free the DSS RSA private fail key
    GNUNET_CRYPTO_rsa_private_key_free (privateFailKeyDSS);

    // Free the DSS RSA public fail key
    GNUNET_CRYPTO_rsa_public_key_free (publicFailKeyDSS);
  }
  else
  {
    printf ("Last argument should be either pass or fail.\n");
    return (1);
  }

  return (0);
}

/**
 * Check parameters to the program.
 */
int checkParams (int nrParams, char* params[])
{
  int i;

  if (nrParams == 1)
  {
    showHelp ();
    return (1);
  }

  for (i = 1 ; i < nrParams; i++)
  {
    if (strcmp (params[i], "-h") == 0 || strcmp (params[i], "--help") == 0)
    {
      showHelp ();
      return (1);
    }

    if (strcmp (params[i], "-v") == 0 || strcmp (params[i], "--version") == 0)
    {
      printf (VERSION"\n");
      return (1);
    }

    if (i < (nrParams - 1))
    {
      printf ("Invalid option: %s\n", params[i]);
      printf ("Use \"-h\" for help.\n");
      return (1);
    }
  }

  return (0);
}

/**
 * Show help
 */
void showHelp ()
{
  printf ("Description:\n");
  printf ("  sign: This program should be run on the DSS to sign the student's blinded hashed ID as either pass or fail.\n");
  printf ("Usage:\n");
  printf ("  sign <pass/fail>\n");
  printf ("Output:\n");
  printf ("  The DSS-signature for either pass or fail of the student's blinded hashed ID.\n");
  printf ("Dependencies:\n");
  printf ("  This program relies on GNUnet and Libgcrypt.\n");
  printf ("License:\n");
  printf ("  GNU General Public License, version 3+.\n");
}

