#include "Pkcs7.h"

#include <openssl/pem.h>
#include <stdexcept>

#include "Utils.h"

using namespace std;

Pkcs7::Pkcs7(const string& filename)
    : key_(NULL), p7_(NULL), rsa_(NULL) {
  if (FILE *fp = fopen(filename.c_str(), "rb")) {
    p7_ = d2i_PKCS7_fp(fp, &p7_);
    if (!p7_) {
      throw std::runtime_error("It's not PKCS7 file: " + filename);
    }

    Init();

    fclose(fp);
  } else {
    throw std::runtime_error("Can't open file: " + filename);
  }
}

Pkcs7::Pkcs7(const std::vector<uint8_t>& data)
  : key_(NULL), p7_(NULL), rsa_(NULL) {
  BIO *bufio = BIO_new_mem_buf((void*) &data[0], data.size());
  p7_ = d2i_PKCS7_bio(bufio, &p7_);
  if (!p7_) {
    throw std::runtime_error("It's not PKCS7 buffer");
  }

  Init();

  BIO_free(bufio);
}

Pkcs7::~Pkcs7()  {
  RSA_free(rsa_);
  EVP_PKEY_free(key_);
  PKCS7_free(p7_);
}

EVP_PKEY* Pkcs7::GetKey() {
  return key_;
}

void Pkcs7::Init() {
  STACK_OF(X509) *x509;
  x509 = PKCS7_get0_signers(p7_, NULL, 0);
  if (!x509) {
    throw std::runtime_error("PKCS7 does not have signers");
  }

  if (sk_X509_num(x509) != 1) {
    throw std::runtime_error("PKCS7 have few signer");
  }

  key_ = X509_get_pubkey(sk_X509_value(x509, 0));

  rsa_ = EVP_PKEY_get1_RSA(key_);
  if (!rsa_) {
    throw runtime_error("PKCS7 did not sign by RSA");
  }
}
