/* This file is in the public domain */
#include <botan/x509self.h>
#include <botan/x509stor.h>
#include <botan/x509_ca.h>
#include <botan/pkcs10.h>
#include <botan/rsa.h>
#include <botan/dsa.h>
using namespace Botan;

#include <iostream>

X509_Cert_Options ca_opts();
X509_Cert_Options req_opts1();
X509_Cert_Options req_opts2();

void do_x509_tests()
   {
   std::cout << "Testing X.509 CA/CRL/cert/cert request: " << std::flush;

   /* Create the CA's key and self-signed cert */
   std::cout << '.' << std::flush;
   RSA_PrivateKey ca_key(1024);
   std::cout << '.' << std::flush;
   X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(), ca_key);
   std::cout << '.' << std::flush;

   /* Create user #1's key and cert request */
   std::cout << '.' << std::flush;
   DSA_PrivateKey user1_key(get_dl_group("DSA-1024"));
   std::cout << '.' << std::flush;
   PKCS10_Request user1_req = X509::create_cert_req(req_opts1(), user1_key);

   /* Create user #2's key and cert request */
   std::cout << '.' << std::flush;
   RSA_PrivateKey user2_key(768);
   std::cout << '.' << std::flush;
   PKCS10_Request user2_req = X509::create_cert_req(req_opts2(), user2_key);

   /* Create the CA object */
   std::cout << '.' << std::flush;
   X509_CA ca(ca_cert, ca_key);
   std::cout << '.' << std::flush;

   /* Sign the requests to create the certs */
   std::cout << '.' << std::flush;
   X509_Certificate user1_cert = ca.sign_request(user1_req);
   std::cout << '.' << std::flush;
   X509_Certificate user2_cert = ca.sign_request(user2_req);
   std::cout << '.' << std::flush;

   X509_CRL crl1 = ca.new_crl();

   /* Verify the certs */
   X509_Store store;

   store.add_cert(ca_cert, true); // second arg == true: trusted CA cert

   std::cout << '.' << std::flush;
   if(store.validate_cert(user1_cert) != VERIFIED)
      std::cout << "\nFAILED: User cert #1 did not validate" << std::endl;

   if(store.validate_cert(user2_cert) != VERIFIED)
      std::cout << "\nFAILED: User cert #2 did not validate" << std::endl;

   if(store.add_crl(crl1) != VERIFIED)
      std::cout << "\nFAILED: CRL #1 did not validate" << std::endl;

   std::vector<CRL_Entry> revoked;
   revoked.push_back(user2_cert);

   X509_CRL crl2 = ca.update_crl(crl1, revoked);

   if(store.add_crl(crl2) != VERIFIED)
      std::cout << "\nFAILED: CRL #2 did not validate" << std::endl;

   if(store.validate_cert(user2_cert) != CERT_IS_REVOKED)
      std::cout << "\nFAILED: User cert #2 was not revoked" << std::endl;

   std::cout << std::endl;
   }

/* Return some option sets */
X509_Cert_Options ca_opts()
   {
   X509_Cert_Options opts("Test CA/US/Botan Project/Testing");

   opts.uri = "http://botan.randombit.net";
   opts.dns = "botan.randombit.net";
   opts.email = "testing@randombit.net";

   opts.CA_key(1);

   return opts;
   }

X509_Cert_Options req_opts1()
   {
   X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");

   opts.uri = "http://botan.randombit.net";
   opts.dns = "botan.randombit.net";
   opts.email = "testing@randombit.net";

   return opts;
   }

X509_Cert_Options req_opts2()
   {
   X509_Cert_Options opts("Test User 2/US/Botan Project/Testing");

   opts.uri = "http://botan.randombit.net";
   opts.dns = "botan.randombit.net";
   opts.email = "testing@randombit.net";

   return opts;
   }
