/**
* \file da_cert_parcer.c
* \brief Certificate verification high level functions.
* \author Dmytro Podgornyi (d.podgornyi@samsung.com)
* \version 0.1
* \date Created May 28, 2013
* \par In Samsung Ukraine R&D Center (SURC) under a contract between
* \par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
* \par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
* \par Copyright: (c) Samsung Electronics Co, Ltd 2012. All rights reserved.
**/

#include <stdint.h>

#include "CommLayerData.h"
#include "CryptoPlatform.h"
#include "x509v3.h"
#include "asn1rsa.h"
#include "log.h"

#include "da_cert_gencer.h"
#include "da_cert_parcer.h"
#include "bn/bn_wrapper.h"

static uint8_t ca_pbk_mod_buf [] = {
	0xe0, 0xc2, 0x81, 0x87, 0x55, 0xaf, 0xd2, 0xd1, 0xe0, 0x8d, 0xa3, 0x72, 0x80, 0x23,
	0xb9, 0xf6, 0x31, 0x80, 0xdf, 0x09, 0x31, 0x06, 0xdb, 0x52, 0xb0, 0x98, 0x5a, 0x98, 0x6b,
	0x1e, 0x5c, 0xf3, 0x50, 0x6d, 0x66, 0xbf, 0x82, 0xa3, 0xab, 0x26, 0x42, 0x7b, 0x5a, 0x0d,
	0xba, 0x06, 0x3f, 0xe4, 0xe4, 0x0e, 0x86, 0x55, 0xa7, 0x7a, 0x59, 0xa4, 0xc3, 0xd5, 0x6d,
	0xc2, 0x9b, 0xc3, 0x7e, 0xc0, 0x38, 0x33, 0x43, 0xc3, 0xbc, 0x85, 0x08, 0xad, 0x65, 0xea,
	0xef, 0x5f, 0x68, 0x99, 0x4c, 0xc4, 0xe7, 0x5d, 0x55, 0x95, 0xe4, 0x83, 0x0e, 0x28, 0x12,
	0x16, 0x9f, 0xd4, 0xc4, 0xc6, 0x6c, 0x0c, 0xef, 0x1c, 0x09, 0x80, 0xc1, 0xb5, 0xf9, 0x35,
	0x42, 0xe7, 0xc7, 0xee, 0xcf, 0x86, 0x3a, 0x05, 0xdd, 0x94, 0x1b, 0xac, 0xc2, 0x7c, 0xdb,
	0x20, 0x21, 0x6e, 0x6c, 0x6a, 0xa4, 0x3b, 0x8b, 0xf4, 0x15, 0x25, 0xc9, 0x32, 0xa2, 0x87,
	0x00, 0xaa, 0xee, 0x75, 0xd2, 0xa9, 0xfb, 0x86, 0x0e, 0xda, 0xd6, 0xc5, 0x7a, 0xbe, 0x76,
	0xa8, 0x3b, 0xbd, 0x6e, 0x51, 0x19, 0xa3, 0xd4, 0x20, 0x8b, 0x67, 0x30, 0xde, 0x23, 0xc2,
	0x29, 0x9e, 0x6b, 0xd3, 0xe4, 0xf4, 0x3e, 0x75, 0xfb, 0x85, 0xe0, 0x6e, 0x51, 0x47, 0x14,
	0xb2, 0x44, 0x1d, 0xf0, 0xec, 0xe9, 0xe4, 0xc4, 0xe1, 0x45, 0xfe, 0x50, 0x6c, 0x4e, 0x8a,
	0x11, 0xbf, 0x5a, 0xb3, 0x0a, 0x47, 0x0d, 0x20, 0x44, 0x20, 0xcf, 0x8b, 0xe5, 0xcd, 0xf1,
	0xe0, 0x1b, 0x77, 0x6e, 0xad, 0x24, 0xb4, 0x91, 0xd6, 0x9f, 0x4d, 0x0d, 0x4d, 0xe5, 0x32,
	0x92, 0x58, 0x4a, 0x74, 0x90, 0x06, 0x6d, 0xd5, 0x5f, 0x51, 0x3a, 0xb1, 0x32, 0xdd, 0x57,	
	0xfe, 0x5b, 0x02, 0x1e, 0xaf, 0x16, 0x0c, 0x21, 0xc2, 0x5d, 0xd7, 0x5d, 0xb4, 0xa3, 0x24,
	0x11, 0xdd };

unsigned char ca_pbk_exp_buf[] = { 0x01, 0x00, 0x01 };

/* Samsung public key */
RSA* ca_rsa_ctx = NULL;

RSA* getCAPublicKey(void)
{
	if (ca_rsa_ctx == NULL) {
		ca_rsa_ctx = mldap_RSA_new();
		if (ca_rsa_ctx) {
			ca_rsa_ctx->n = BN_new();
			ca_rsa_ctx->e = BN_new();
			if ( ca_rsa_ctx->n == NULL || ca_rsa_ctx->e == NULL || BN_bin2bn(ca_pbk_mod_buf, sizeof(ca_pbk_mod_buf), ca_rsa_ctx->n) == NULL ||
				BN_bin2bn(ca_pbk_exp_buf, sizeof(ca_pbk_exp_buf), ca_rsa_ctx->e) == NULL ) {
				mldap_RSA_free(ca_rsa_ctx);
				ca_rsa_ctx = NULL;
			}
		}
	}
	return ca_rsa_ctx;
}

int32_t verify_cert_signature_rsa(const struct x509_certificate* cert, RSA* ca)
{
	int32_t res = PLATFORM_INTERNAL_ERROR;
	unsigned char digest[SHA512_DIGEST_LEN] = {0};
	uint32_t digestLen = 0;
	hashCallback_t hash = NULL;
	int algo = 0;

	algo = getCertSignHash(cert);
	if (algo < 0) {
		LOGE("verify_cert_signature_rsa: incorrect signature algorithm");
		return WRONG_DATA;
	}

	switch (algo)
	{
		case RSA_SHA512:
			hash = getSHA512Digest;
			digestLen = SHA512_DIGEST_LEN;
			break;
		case RSA_SHA256:
			hash = getSHA256Digest;
			digestLen = SHA256_DIGEST_LEN;
			break;
		case RSA_SHA1:
			hash = getSHA1Digest;
			digestLen = SHA1_DIGEST_LEN;
			break;
		default:
			LOGE("verify_cert_signature_rsa: unknown signature algorithm");
			return PLATFORM_INTERNAL_ERROR;
	}

	res = hash((uint8_t*)cert->tbs_cert_start, cert->tbs_cert_len, digest);
	if (NO_ERROR != res) {
		LOGE("Hash digest calculating error");
		return PLATFORM_INTERNAL_ERROR;
	}

	res = mldap_rsa_pkcs1_verify(ca, algo, digestLen, digest, (unsigned char *)cert->sign_value);
	if (res != NO_ERROR) {
		LOGE("Error mldap_rsa_pkcs1_verify : %d", res);
	}

	return res;
}

int32_t checkRSACertificate(const uint8_t *buf, uint32_t len, RSA* ca)
{
	struct x509_certificate cert = {0};
	x509_parser_error_t res = X509_PARSE_ERROR_UNDEFINED;

	res = x509_certificate_parse(buf, len, &cert);
	if (res != X509_PARSE_OK) {
		LOGE("Cannot parse certificate. Error code: %d", res);
		return PLATFORM_INTERNAL_ERROR;
	}

	if (verify_cert_signature_rsa(&cert, ca) != NO_ERROR) {
		LOGE("Certificate signature verification error");
		return WRONG_RSA_CERT;
	}

	return NO_ERROR;
}

int32_t getCertUid(const struct x509_certificate *cert, uint8_t *uid, uint32_t uidLen)
{
	int index = 0;
	int attributNum = -1;
	size_t len = 0;

	/* get UID of subject certificate field */
	for (index = 0; index < cert->subject.num_attr; index++) {
		if(cert->subject.attr[index].type == X509_NAME_ATTR_UID) {
			attributNum = index;
			break;
		}
	}

	if (attributNum < 0) {
		LOGE("There is not UID field within certificate");
		return WRONG_DATA;
	}

	len = cert->subject.attr[attributNum].value_size;
	if (uidLen <= len) {
		LOGE("Not enough space in uid buffer");
		return WRONG_DATA;
	}

	memcpy(uid, cert->subject.attr[attributNum].value, len);
	uid[len] = '\0';

	return NO_ERROR;
}