/*
 * smime-decode.c
 * + decode S/MIME message
 * + print out the plaintext
 * + verify signature (for now ignore the certificate chain)
 * - can't write opuput to a file (only stdout)
 * - doesn't verify the certificate chain
 * - can't decrypt encrypted messages
 *
 * Michal Ludvig <michal@logix.cz> (c) 2003
 * Homepage: http://www.logix.cz/michal/devel/smime
 *
 * This code is public domain. Use it as you want to, 
 * but don't blame me if something doesn't work as you 
 * expect.
 * NOTE: This code works with cryptography - you should double
 * chack and fully understand it before relying on it's output!
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/pkcs7.h>
#include <openssl/err.h>

int
main (int argc, char *argv[])
{
  BIO *bin, *bout, *content = NULL;
  PKCS7 *p7;
  X509_STORE *store = NULL;
  X509_LOOKUP *lookup;
  int res, flags = 0;

  /* Initialize the OpenSSL engine.  */
  CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
  OpenSSL_add_all_algorithms();
  ERR_load_crypto_strings();

  /* Open output BIO.  */
  bout = BIO_new_fp (stdout, BIO_NOCLOSE);
  if (! bout)
  {
    printf ("Can not attach stdout: %s\n", strerror (errno));
    return 1;
  }

  /* Open input BIO.  */
  if (argc < 2)
  {
    bin = BIO_new_fp (stdin, BIO_NOCLOSE);
    if (! bin)
    {
      BIO_printf (bout, "Can not attach stdin: %s\n", strerror (errno));
      return 1;
    }
  }
  else
  {
    bin = BIO_new_file (argv[1], "r");
    if (! bin)
    {
      BIO_printf (bout, "%s: %s\n", argv[1], strerror (errno));
      return 1;
    }
  }

  /* Prepare for using CA certificates. Useless for now.  */
  store = X509_STORE_new ();
  lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ());
  X509_LOOKUP_load_file (lookup, NULL, X509_FILETYPE_DEFAULT);
  lookup = X509_STORE_add_lookup (store, X509_LOOKUP_hash_dir ());
  X509_LOOKUP_add_dir (lookup, NULL, X509_FILETYPE_DEFAULT);

  /* Read and decode S/MIME message.  */
  p7 = SMIME_read_PKCS7(bin, &content);
  if (! p7)
  {
    BIO_printf (bout, "Read: %s\n", ERR_error_string(ERR_get_error (), NULL));
    return 1;
  }

  /* Exit if it isn't a signed-only message.  */
  if (PKCS7_type_is_enveloped (p7))
  {
    printf ("[Message is encrypted - can't handle it]\n");
    return 11;
  }

  if (PKCS7_type_is_signedAndEnveloped (p7))
  {
    printf ("[Message is signed & encrypted - can't handle it]\n");
    return 12;
  }

  /* IMPORTANT: Verify only the signature, not the certificate!
   * This is probably not what you want, because the signature could
   * be easily forged! */
  flags = PKCS7_NOVERIFY;

  /* Verification itself.  Plaintext is written to 'bout' BIO.  */
  res = PKCS7_verify (p7, NULL, store, content, bout, flags);

  /* Print a result.  */
  BIO_printf (bout, "********************\n");
  BIO_printf (bout, "[%s signature %s]\n",
              PKCS7_get_detached (p7) ? "Detached" : "Embedded",
              res == 1 ? "verified" : "broken");

  return 0;
}