/**
 * @file       der.c
 * @brief      Simple DER iterator to parse x.509 certificate.
 * @author     Oleksandr Fadieiev (o.fadieiev@samsung.com)
 * @version    1.0
 * @date       Created April 12, 2017
 * @copyright  In Samsung Ukraine R&D Center (SURC) under a contract between
 * @par        LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * @par        "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 * @par        Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
 */
#include "der.h"
#include <stdlib.h>

static uint8_t DerLengthCount(const DerHeader *der) {
  // Length part is 1 byte at least.
  uint8_t count = 1;

  // Composite length has additional bytes.
  if ((der->length[0] & 0x80) && (der->length[0] & 0x7f)) {
    // Ignore reserved values "127" and "0", just use them as length part size.
    count += der->length[0] & 0x7f;
  }

  return count;
}

uint8_t DerTag(const DerHeader *der) {
  return der->tag;
}

uint16_t DerLength(const DerHeader *der) {
  uint8_t count = DerLengthCount(der);

  if (count == 1) {
    // Length consists of 1 byte and has binary format [0|xxxxxxx] => [0|len].
    return der->length[0] & 0x7f;
  } else if (count == 2) {
    // Length consists of 2 bytes and has binary format [1|0000001][len].
    return (uint16_t)der->length[1];
  } else if (count == 3) {
    // Length consists of 3 bytes and has binary format [1|0000010][len][len].
    return (uint16_t)(der->length[1] << 8 | der->length[2]);
  }

  // Don't support other length types.
  return 0;
}

void *DerValue(const DerHeader *der) {
  return (void *)(der + sizeof(DerHeader) + DerLengthCount(der));
}

DerHeader *DerNext(const DerHeader *current, const void *end) {
  size_t der_size = sizeof(DerHeader) + DerLengthCount(current) +
                    DerLength(current);

  if ((size_t)(end - (void *)current) < der_size) {
    return NULL;
  }

  return (DerHeader *)((uint8_t *)current + der_size);
}
