/*
Module : CryptoWrappersChain.h
Purpose: Defines the interface for a C++ wrapper class for a CryptoAPI PCCERT_CHAIN_CONTEXT
History: PJN / 01-08-2014 1. Initial public release
         PJN / 12-06-2018 1. Updated copyright details.
                          2. Fixed a number of C++ core guidelines compiler warnings. These changes mean
                          that the code will now only compile on VC 2017 or later.
         PJN / 22-08-2018 1. Fixed a number of compiler warnings when using VS 2017 15.8.1

Copyright (c) 2014 - 2018 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
when your product is released in binary form. You are allowed to modify the source code in any way you want 
except you cannot modify the copyright details at the top of each module. If you want to distribute source 
code with your application, then you are only allowed to distribute versions released by the author. This is 
to maintain a single distribution point for the source code.

*/


////////////////////////// Macros / Defines ///////////////////////////////////

#pragma once

#ifndef __CRYPTOWRAPPERSCHAIN_H__
#define __CRYPTOWRAPPERSCHAIN_H__

#pragma comment(lib, "Crypt32.lib")  //Automatically link in the Crypto dll


////////////////////////// Includes ///////////////////////////////////////////

#ifndef __WINCRYPT_H__
#pragma message("To avoid this message, please put wincrypt.h in your pre compiled header (normally stdafx.h)")
#include <wincrypt.h>
#endif //#ifndef __WINCRYPT_H__


////////////////////////// Classes ////////////////////////////////////////////

namespace CryptoWrappers
{


//Encapsulates a CryptoAPI PCERT_CHAIN_CONTEXT
class CChain
{
public:
//Constructors / Destructors
  CChain() noexcept : m_pChain(nullptr)
  {
  }

  CChain(_In_ const CChain& chain) noexcept : m_pChain(nullptr)
  {
    if (!chain.Duplicate(*this))
      m_pChain = nullptr;
  }

  CChain(_In_ CChain&& chain) noexcept : m_pChain(nullptr)
  {
    Attach(chain.Detach());
  }

  explicit CChain(_In_opt_ PCCERT_CHAIN_CONTEXT pChain) noexcept : m_pChain(pChain)
  {
  }

  ~CChain() noexcept
  {
    if (m_pChain != nullptr)
      Free();
  }

//Methods
  CChain& operator=(_In_ const CChain& chain) noexcept
  {
    if (this != &chain)
    {
      if (m_pChain != nullptr)
        Free();
      if (!chain.Duplicate(*this))
        m_pChain = nullptr;
    }
    return *this;
  }

  CChain& operator=(_In_ CChain&& chain) noexcept
  {
    if (m_pChain != nullptr)
      Free();
    Attach(chain.Detach());
    return *this;
  }

  PCCERT_CHAIN_CONTEXT Handle() const noexcept
  {
    return m_pChain;
  }

  void Attach(_In_opt_ PCCERT_CHAIN_CONTEXT pChain) noexcept
  {
    //Validate our parameters
#pragma warning(suppress: 26477)
    ATLASSERT(m_pChain == nullptr);

    m_pChain = pChain;
  }

  PCCERT_CHAIN_CONTEXT Detach() noexcept
  {
    PCCERT_CHAIN_CONTEXT pChain = m_pChain;
    m_pChain = nullptr;
    return pChain;
  }

  void Free() noexcept
  {
    //Validate our parameters
#pragma warning(suppress: 26477)
    ATLASSERT(m_pChain != nullptr);

    CertFreeCertificateChain(m_pChain);
    m_pChain = nullptr;
  }

  _Success_(return != FALSE)
  BOOL Duplicate(_Inout_ CChain& chain) const noexcept
  {
    //Validate our parameters
#pragma warning(suppress: 26477)
    ATLASSERT(m_pChain != nullptr);
#pragma warning(suppress: 26477)
    ATLASSERT(chain.m_pChain == nullptr);

    chain.m_pChain = CertDuplicateCertificateChain(m_pChain);
    return (chain.m_pChain != nullptr);
  }

  _Success_(return != FALSE)
  BOOL VerifyPolicy(_In_ LPCSTR pszPolicyOID, _In_ PCERT_CHAIN_POLICY_PARA pPolicyPara, _Inout_ PCERT_CHAIN_POLICY_STATUS pPolicyStatus) noexcept
  {
    //Validate our parameters
#pragma warning(suppress: 26477)
    ATLASSERT(m_pChain != nullptr);

    return CertVerifyCertificateChainPolicy(pszPolicyOID, m_pChain, pPolicyPara, pPolicyStatus);
  }

//Member variables
  PCCERT_CHAIN_CONTEXT m_pChain;

  friend class CStore;
  friend class CChainEngine;
};


}; //namespace CryptoWrappers

#endif //#ifndef __CRYPTOWRAPPERSCHAIN_H__
