/**
 * @file pem_import.c
 * @brief PEM file import functions
 *
 * @section License
 *
 * Copyright (C) 2021-2026 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneCRYPTO Eval
 * 
 * This software is provided in source form for a short-term evaluation only. The
 * evaluation license expires 90 days after the date you first download the software.
 *
 * If you plan to use this software in a commercial product, you are required to
 * purchase a commercial license from Oryx Embedded SARL.
 *
 * After the 90-day evaluation period, you agree to either purchase a commercial
 * license or delete all copies of this software. If you wish to extend the
 * evaluation period, you must contact sales@oryx-embedded.com.
 *
 * This evaluation software is provided "as is" without warranty of any kind.
 * Technical support is available as an option during the evaluation period.

 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 2.6.0
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL

//Dependencies
#include "core/crypto.h"
#include "pkix/pem_import.h"
#include "encoding/asn1.h"
#include "debug.h"

//Check crypto library configuration
#if (PEM_SUPPORT == ENABLED)


/**
 * @brief Decode a PEM file containing a certificate
 * @param[in] input Pointer to the PEM string
 * @param[in] inputLen Length of the PEM string
 * @param[out] output Pointer to the DER-encoded certificate
 * @param[out] outputLen Length of the DER-encoded certificate, in bytes
 * @param[out] consumed Total number of characters that have been consumed
 *   (optional parameter)
 * @return Error code
 **/

error_t pemImportCertificate(const char_t *input, size_t inputLen,
   uint8_t *output, size_t *outputLen, size_t *consumed)
{
   error_t error;

   //Check parameters
   if(input == NULL || outputLen == NULL)
      return ERROR_INVALID_PARAMETER;

   //X.509 certificates are encoded using the "CERTIFICATE" label
   error = pemDecodeFile(input, inputLen, "CERTIFICATE", output, outputLen,
      NULL, consumed);

   //Return status code
   return error;
}


/**
 * @brief Decode a PEM file containing a certificate revocation list
 * @param[in] input Pointer to the PEM string
 * @param[in] inputLen Length of the PEM string
 * @param[out] output Pointer to the DER-encoded CRL
 * @param[out] outputLen Length of the DER-encoded CRL, in bytes
 * @param[out] consumed Total number of characters that have been consumed
 *   (optional parameter)
 * @return Error code
 **/

error_t pemImportCrl(const char_t *input, size_t inputLen,
   uint8_t *output, size_t *outputLen, size_t *consumed)
{
   error_t error;

   //Check parameters
   if(input == NULL || outputLen == NULL)
      return ERROR_INVALID_PARAMETER;

   //CRLs are encoded using the "X509 CRL" label
   error = pemDecodeFile(input, inputLen, "X509 CRL", output, outputLen,
      NULL, consumed);

   //Return status code
   return error;
}


/**
 * @brief Decode a PEM file containing a certification signing request
 * @param[in] input Pointer to the PEM string
 * @param[in] inputLen Length of the PEM string
 * @param[out] output Pointer to the DER-encoded CSR
 * @param[out] outputLen Length of the DER-encoded CSR, in bytes
 * @return Error code
 **/

error_t pemImportCsr(const char_t *input, size_t inputLen,
   uint8_t *output, size_t *outputLen)
{
   error_t error;

   //Check parameters
   if(input == NULL || outputLen == NULL)
      return ERROR_INVALID_PARAMETER;

   //CSRs are encoded using the "CERTIFICATE REQUEST" label
   error = pemDecodeFile(input, inputLen, "CERTIFICATE REQUEST", output,
      outputLen, NULL, NULL);

   //Return status code
   return error;
}


/**
 * @brief Decode a PEM file containing Diffie-Hellman parameters
 * @param[out] params Diffie-Hellman parameters resulting from the parsing process
 * @param[in] input Pointer to the PEM string
 * @param[in] length Length of the PEM string
 * @return Error code
 **/

error_t pemImportDhParameters(DhParameters *params, const char_t *input,
   size_t length)
{
#if (DH_SUPPORT == ENABLED)
   error_t error;
   size_t n;
   uint8_t *buffer;
   const uint8_t *p;
   Asn1Tag tag;

   //Check parameters
   if(params == NULL || input == NULL)
      return ERROR_INVALID_PARAMETER;

   //Initialize variables
   p = NULL;
   n = 0;

   //Diffie-Hellman parameters are encoded using the "DH PARAMETERS" label
   error = pemDecodeFile(input, length, "DH PARAMETERS", NULL, &n, NULL, NULL);

   //Check status code
   if(!error)
   {
      //Allocate a memory buffer to hold the ASN.1 data
      buffer = cryptoAllocMem(n);

      //Successful memory allocation?
      if(buffer != NULL)
      {
         //Decode the content of the PEM container
         error = pemDecodeFile(input, length, "DH PARAMETERS", buffer, &n,
            NULL, NULL);

         //Check status code
         if(!error)
         {
            //The Diffie-Hellman parameters are encapsulated within a sequence
            error = asn1ReadSequence(buffer, n, &tag);
         }

         //Check status code
         if(!error)
         {
            //Point to the first field of the sequence
            p = tag.value;
            n = tag.length;

            //Read the prime modulus
            error = asn1ReadMpi(p, n, &tag, &params->p);
         }

         //Check status code
         if(!error)
         {
            //Point to the next field
            p += tag.totalLength;
            n -= tag.totalLength;

            //Read the generator
            error = asn1ReadMpi(p, n, &tag, &params->g);
         }

         //Check status code
         if(!error)
         {
            //Debug message
            TRACE_DEBUG("Diffie-Hellman parameters:\r\n");
            TRACE_DEBUG("  Prime modulus:\r\n");
            TRACE_DEBUG_MPI("    ", &params->p);
            TRACE_DEBUG("  Generator:\r\n");
            TRACE_DEBUG_MPI("    ", &params->g);
         }

         //Release previously allocated memory
         cryptoFreeMem(buffer);
      }
      else
      {
         //Failed to allocate memory
         error = ERROR_OUT_OF_MEMORY;
      }
   }

   //Any error to report?
   if(error)
   {
      //Clean up side effects
      mpiFree(&params->p);
      mpiFree(&params->g);
   }

   //Return status code
   return error;
#else
   //Not implemented
   return ERROR_NOT_IMPLEMENTED;
#endif
}

#endif
