
/*
 * =====================================================================================
 *
 *       Filename:  pebble_x509.c
 *
 *    Description:  PEBBLE x509 certificates manipulation
 *
 *        Version:  1.0
 *        Created:  06/03/2020
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2020 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "pebble_x509.h"

/**
 * Trust anchor x509 certificate - SamsungServiceServerCA.crt
 */
uint8_t *trust_anchor_cert = (uint8_t*) "-----BEGIN CERTIFICATE-----\n"\
                           "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\n"\
                           "-----END CERTIFICATE-----";

uint8_t *aks_anchor_cert1 = (uint8_t *) "-----BEGIN CERTIFICATE-----\n"\
"MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYyODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdSSxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggjnar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGqC4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQoVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+OJtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/EgsTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRiigHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+MRPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9EaDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5UmAGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYDVR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lkLmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQADggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfBPb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00mqC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rYDBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPmQUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4uJU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyDCdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79IyZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxDqwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23UaicMDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk\n"\
"-----END CERTIFICATE-----";

const char * drk_root_n = "e0c2818755afd2d1e08da3728023b9f63180df093106db52b0985a986b1e5cf3506d66bf82a3ab26427b5a0dba063fe4e40e8655a77a59a4c3d56dc29bc37ec0383343c3bc8508ad65eaef5f68994cc4e75d5595e4830e2812169fd4c4c66c0cef1c0980c1b5f93542e7c7eecf863a05dd941bacc27cdb20216e6c6aa43b8bf41525c932a28700aaee75d2a9fb860edad6c57abe76a83bbd6e5119a3d4208b6730de23c2299e6bd3e4f43e75fb85e06e514714b2441df0ece9e4c4e145fe506c4e8a11bf5ab30a470d204420cf8be5cdf1e01b776ead24b491d69f4d0d4de53292584a7490066dd55f513ab132dd57fe5b021eaf160c21c25dd75db4a32411dd";

const char * drk_root_e = "10001";

/**
 * Static functions prototypes
 */
static EVP_PKEY *get_public_key(uint8_t *pem_cert);
static pebble_return_code_t verify_cert(uint8_t *pem_cert, uint8_t *pem_trust_anchor);

/**
 * @brief
 * get_public_key
 * Parses public key from x509 PEM certificate
 * @param[in] *pem_cert - PEM certificate
 *
 * @return EVP_PKEY
 */
static EVP_PKEY* get_public_key(uint8_t *pem_cert) {
        PEBBLE_LOG_DEBUG("get_public_key()");

        BIO  *reqbio = NULL;
        X509 *certreq = NULL;

        reqbio = BIO_new_mem_buf(pem_cert, -1);
        if(reqbio == NULL)
        {
                PEBBLE_LOG("Error to alloc memory");
                return NULL;
        }

        if (!(certreq = PEM_read_bio_X509(reqbio, NULL, NULL, NULL))) {
                PEBBLE_LOG("ERROR read bio");
                BIO_free(reqbio);  // SI-16842
                return NULL;
        }

        EVP_PKEY *pkey_trust_anchor = X509_get_pubkey(certreq);
        X509_free(certreq);
        BIO_free(reqbio);

        return pkey_trust_anchor;
}

/**
 * @brief
 * get subjectName from Certificate
 * return subjectName
 * @param[in] *pem_cert - PEM certificate
 * @param[out] *subjectName - subject name from pem_cert
 *
 * @return PEBBLE status code
 */
static pebble_return_code_t get_subject_from_certificate(uint8_t *pem_cert, uint8_t** subjectName) {
        PEBBLE_LOG_DEBUG("get_subject_from_certificate()");

        pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
        BIO  *reqbio = NULL;
        X509 *certreq = NULL;

        reqbio = BIO_new_mem_buf(pem_cert, -1);
        if(reqbio == NULL)
        {
                PEBBLE_LOG("Error to alloc memory");
                return PEBBLE_CONVERT_DER_CERT_FAIL;
        }
        certreq = PEM_read_bio_X509(reqbio, NULL, NULL, NULL);

        if (certreq == NULL) {
                PEBBLE_LOG("parse_pem_cert Failed!");
                unsigned long errCode = ERR_peek_last_error();
                char errBuffer[16384];
                ERR_error_string_n(errCode, errBuffer, 16384);

                PEBBLE_LOG_DEBUG("err = %s",errBuffer);
                BIO_free(reqbio); // SI-16842
                return PEBBLE_CONVERT_DER_CERT_FAIL;
        } else {
                PEBBLE_LOG_DEBUG("parse_pem_cert Success!");
        }

        X509_NAME *subj = X509_get_subject_name(certreq);

        int index = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
        X509_NAME_ENTRY *e = X509_NAME_get_entry(subj, index);
        ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
        unsigned char *str = ASN1_STRING_data(d);
        if (str == NULL) {
            PEBBLE_LOG("Wrong subjectName!");
            X509_free(certreq);
            BIO_free(reqbio);
            return PEBBLE_CONVERT_DER_CERT_FAIL;
        }
        int str_len = ASN1_STRING_length(d); // SI-16920

        *subjectName = TEE_Malloc((str_len + 1), 0);
        if (*subjectName != NULL) { // SI-16876
            strncpy((char *)*subjectName, (char *)str, str_len);\
            PEBBLE_LOG_DEBUG("CN = %s",*subjectName);
        }
        else {
            PEBBLE_LOG("TEE_Malloc failed");
        }

	X509_free(certreq);
        BIO_free(reqbio);

        return ret;
}

/**
 * @brief
 * get AKS attestation challenge from Certificate
 * return nonce
 * @param[in] *pem_cert - PEM certificate
 * @param[out] *nonce - attestation challenge from pem_cert
 *
 * @return PEBBLE status code
 */
static pebble_return_code_t get_nonce_from_certificate(uint8_t *pem_cert, uint8_t** nonce) {
        PEBBLE_LOG_DEBUG("get_nonce_from_certificate()");

        pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
        BIO  *reqbio = NULL;
        X509 *certreq = NULL;

        reqbio = BIO_new_mem_buf(pem_cert, -1);
        if(reqbio == NULL)
        {
                PEBBLE_LOG("Error to alloc memory");
                return PEBBLE_CONVERT_DER_CERT_FAIL;
        }
        certreq = PEM_read_bio_X509(reqbio, NULL, NULL, NULL);

        if (certreq == NULL) {
                PEBBLE_LOG("parse_pem_cert Failed!");
                unsigned long errCode = ERR_peek_last_error();
                char errBuffer[16384];
                ERR_error_string_n(errCode, errBuffer, 16384);

                PEBBLE_LOG_DEBUG("err = %s",errBuffer);
                BIO_free(reqbio); // SI-16842
                return PEBBLE_CONVERT_DER_CERT_FAIL;
        } else {
                PEBBLE_LOG_DEBUG("parse_pem_cert Success!");
        }

        int nid = OBJ_create("1.3.6.1.4.1.11129.2.1.17", "AKS", "Attestation extension");
        int loc = X509_get_ext_by_NID(certreq, nid, -1);
        if (loc == -1) {
                PEBBLE_LOG("cannot find extension/attestation!");
                BIO_free(reqbio); // SI-16842
                return PEBBLE_CONVERT_DER_CERT_FAIL;
        }
        X509_EXTENSION *ext = X509_get_ext(certreq, loc);
        ASN1_OCTET_STRING *extdata = X509_EXTENSION_get_data(ext);

        const unsigned char* octet_str_data = extdata->data;
        long xlen;
        long max_len;
        int tag, xclass;
        ASN1_get_object(&octet_str_data, &xlen, &tag, &xclass, extdata->length);
        PEBBLE_LOG("nonce: %ld", xlen);
        max_len = xlen;
        ASN1_get_object(&octet_str_data, &xlen, &tag, &xclass, max_len);
        PEBBLE_LOG("attestationVersion(INTEGER): %ld", xlen);
        octet_str_data += xlen;
        max_len -= xlen;
        ASN1_get_object(&octet_str_data, &xlen, &tag, &xclass, max_len);
        PEBBLE_LOG("attestationSecurity(SecurityLevel): %ld", xlen);
        octet_str_data += xlen;
        max_len -= xlen;
        ASN1_get_object(&octet_str_data, &xlen, &tag, &xclass, max_len);
        PEBBLE_LOG("keymasterVersion(INTEGER): %ld", xlen);
        octet_str_data += xlen;
        max_len -= xlen;
        ASN1_get_object(&octet_str_data, &xlen, &tag, &xclass, max_len);
        PEBBLE_LOG("keymasterSecurity(SecurityLevel): %ld", xlen);
        octet_str_data += xlen;
        max_len -= xlen;
        ASN1_get_object(&octet_str_data, &xlen, &tag, &xclass, max_len);
        PEBBLE_LOG("attestationChallenge(OCTET_STRING): %ld", xlen);
        printRange((uint8_t *)octet_str_data, xlen, "nonce");
        
        *nonce = TEE_Malloc((xlen + 1), 0);
        if (*nonce != NULL) { // SI-16876
            strncpy((char *)*nonce, (char *)octet_str_data, xlen);\
            PEBBLE_LOG_DEBUG("nonce = %s", *nonce);
        }
        else {
            PEBBLE_LOG("TEE_Malloc failed");
        }
	X509_free(certreq);
        BIO_free(reqbio);

        return ret;
}

/**
 * @brief
 * Compare string subjectName with subjectName from certificate
 * return subjectName
 * @param[out] *subjectName - subject name from pem_cert
 * * @param[in] *pem_cert - PEM certificate
 *
 * @return PEBBLE status code
 */
static pebble_return_code_t compare_subject_name(uint8_t *subjectName, uint8_t *pem_cert) 
{
        PEBBLE_LOG_DEBUG("compare_subject_name()");

        pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
        uint8_t* subjectName_from_cert = NULL;

        ret = get_subject_from_certificate(pem_cert, &subjectName_from_cert);
        if(ret != PEBBLE_STATUS_SUCCESS){
                PEBBLE_LOG_DEBUG("get_subject_from_certificate error: %d", ret);
                goto exit;
        }
        
        if(strlen((char *) subjectName_from_cert) != strlen((char *)subjectName)){
                PEBBLE_LOG_DEBUG("len not match %d %d", strlen((char *)subjectName_from_cert), strlen((char *) subjectName));
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }
        ret = strncmp((char *) subjectName,(char *) subjectName_from_cert, strlen((char *) subjectName));
        if(ret != 0){
                PEBBLE_LOG("subjectName is wrong");
                PEBBLE_LOG_DEBUG("subjectName is wrong - subjectName1=%s subjectName=%s", subjectName, subjectName_from_cert);
                ret = PEBBLE_INVALID_CN_CHECK;
        }
        else
        {
                PEBBLE_LOG_DEBUG("subjectName match");
        }
        
exit:
        if(subjectName_from_cert != NULL){
                TEE_Free(subjectName_from_cert);
        }
                
        return ret;
}

/**
 * @brief
 * verify_cert
 * Verify x509 certificate with its trust anchor
 *
 * @param[in] *pem_cert         - PEM certificate
 * @param[in] *pem_trust_anchor - x509 trust anchor certificate
 *
 * @return PEBBLE status code
 */
static pebble_return_code_t verify_cert(uint8_t *pem_cert, uint8_t *pem_trust_anchor) {
        PEBBLE_LOG_DEBUG("verify_cert()");

        pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
        BIO  *reqbio = NULL;
        X509 *certreq = NULL;

        OpenSSL_add_all_algorithms();
        ERR_load_BIO_strings();

        reqbio = BIO_new_mem_buf(pem_cert, -1);
        if(reqbio == NULL)
        {
                ret = PEBBLE_ALLOC_ERROR;
                PEBBLE_LOG("Error to alloc memory");
                goto exit;
        }

        if (!(certreq = PEM_read_bio_X509(reqbio, NULL, NULL, NULL))) {
                PEBBLE_LOG("ERROR read bio");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }

        EVP_PKEY *pkey_trust_anchor = get_public_key(pem_trust_anchor);
        if(pkey_trust_anchor == NULL) {
                PEBBLE_LOG("FAIL to get trust anchor");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }

        ret = X509_verify(certreq, pkey_trust_anchor);
        if(!ret) {
                PEBBLE_LOG("Chain Cert verify FAIL");
                PEBBLE_LOG_DEBUG("X509_verify fail ret = %d",ret);
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }

        PEBBLE_LOG("Certificate signature OK");
        ret = PEBBLE_STATUS_SUCCESS;
exit:
        if (pkey_trust_anchor != NULL) EVP_PKEY_free(pkey_trust_anchor);
        if (certreq != NULL) X509_free(certreq);
        if (reqbio != NULL) BIO_free(reqbio);

        return ret;
}

/**
 * @brief
 * verify_cert_drk_root
 * Verify x509 certificate with hard coded DRK root public key
 *
 * @param[in] *pem_cert         - PEM certificate
 *
 * @return PEBBLE status code
 */
static pebble_return_code_t verify_cert_drk_root(uint8_t *pem_cert) {
        PEBBLE_LOG_DEBUG("verify_cert_drk_root()");

        pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;
        BIO  *reqbio = NULL;
        X509 *certreq = NULL;
        RSA *r = NULL;
        BIGNUM *bnn = NULL, *bne = NULL;
        EVP_PKEY *pkey_trust_anchor = NULL;

        OpenSSL_add_all_algorithms();
        ERR_load_BIO_strings();

        reqbio = BIO_new_mem_buf(pem_cert, -1);
        if(reqbio == NULL)
        {
                ret = PEBBLE_ALLOC_ERROR;
                PEBBLE_LOG("Error to alloc memory");
                goto exit;
        }

        if (!(certreq = PEM_read_bio_X509(reqbio, NULL, NULL, NULL))) {
                PEBBLE_LOG("ERROR read bio");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }

        r = RSA_new();
        pkey_trust_anchor = EVP_PKEY_new();
        if (r == NULL || pkey_trust_anchor == NULL) {
                ret = PEBBLE_ALLOC_ERROR;
                PEBBLE_LOG("Error to alloc memory to construct pkey_trust_anchor");
                goto exit;
        }
        ret = BN_hex2bn(&bnn, drk_root_n);
        if (ret == 0) {
                PEBBLE_LOG("ERROR BN_hex2bn for drk_root_n");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }
        ret = BN_hex2bn(&bne, drk_root_e);
        if (ret == 0) {
                PEBBLE_LOG("ERROR BN_hex2bn for drk_root_e");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }
        ret = RSA_set0_key(r, bnn, bne, NULL);
        if (ret != 1) {
                PEBBLE_LOG("ERROR RSA_set0_key");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }
        ret = EVP_PKEY_set1_RSA(pkey_trust_anchor, r);
        if(ret != 1) {
                PEBBLE_LOG("ERROR EVP_PKEY_set1_RSA");
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }

        ret = X509_verify(certreq, pkey_trust_anchor);
        if(!ret) {
                PEBBLE_LOG("Chain Cert verify FAIL");
                PEBBLE_LOG_DEBUG("X509_verify fail ret = %d",ret);
                ret = PEBBLE_INVALID_CERTCHAIN;
                goto exit;
        }

        PEBBLE_LOG("Certificate signature OK");
        ret = PEBBLE_STATUS_SUCCESS;
exit:
        if (bne != NULL) BN_free(bne);
        if (bnn != NULL) BN_free(bnn);
        if (r != NULL) RSA_free(r);
        if (pkey_trust_anchor != NULL) EVP_PKEY_free(pkey_trust_anchor);
        if (certreq != NULL) X509_free(certreq);
        if (reqbio != NULL) BIO_free(reqbio);

        return ret;
}

/**
 * @brief
 * verify_cert_chain
 * Validates x509 certificates chain
 *
 * @param[in] certificates[]     - certificates chain
 * @param[in] certificates_count - number of certificates
 * @param[in] key                - envelopped key
 *
 * @return PEBBLE status code
 */
pebble_return_code_t verify_cert_chain(cert_chain_t cert_chain, bool leaf_first, EVP_PKEY **pkey) {
        PEBBLE_LOG_DEBUG("verify_cert_chain()");
        pebble_return_code_t ret = PEBBLE_INVALID_CERTCHAIN;
        uint32_t em_status = -1;

        if(cert_chain.num_certs < 2){
                PEBBLE_LOG("Certificate chain is not completed");
                PEBBLE_LOG_DEBUG("Invalid number of certificates: %d", cert_chain.num_certs);
                return ret;
        }
        
        ret = pebble_ICCC_check_em_status((uint32_t*) &em_status);
        if (ret != PEBBLE_STATUS_SUCCESS) {
                PEBBLE_LOG_DEBUG("ICCC Fail");
                PEBBLE_LOG_DEBUG("Fail to pebble_ICCC_check_em_status: %d", ret);
                return ret;
        }
#if 0
        switch (em_status) {
            case 0: // PROD Device
                    PEBBLE_LOG_DEBUG("Verifing CN PROD");
                    ret = compare_subject_name((uint8_t *) "PEBBLE Intermediate CA", certificates[1].certificate);
                    if(ret != PEBBLE_STATUS_SUCCESS) /* PROD CERT */
                    {
                                PEBBLE_LOG_DEBUG("Invalid subjectName");
                                return ret;
                    }
                    break;

            case 1: // DEV Device
            case 2: // Eng Token on PROD Device
                    PEBBLE_LOG("Verifing CN DEV");
                    ret = compare_subject_name((uint8_t *) "PEBBLE TEST", certificates[1].certificate);
                    if(ret != PEBBLE_STATUS_SUCCESS) /* DEV CERT */
                    {
                                PEBBLE_LOG_DEBUG("Invalid subjectName");
                                return ret;
                    }
                    break;

            default:
                    PEBBLE_LOG_DEBUG("Invalid em_status: %d", em_status);
                    return PEBBLE_READ_EM_STATUS_FAIL;
                    break;
        }

        PEBBLE_LOG("SubjectName checked");
#endif
        for (size_t i = 0; i < cert_chain.num_certs - 1; i++)
        {
                if (leaf_first) {
                        PEBBLE_LOG_DEBUG("Check signature cert[%d] with cert[%d]", i, i+1);
                        ret = verify_cert(cert_chain.cert[i].blob, cert_chain.cert[i+1].blob);
                } else {
                        PEBBLE_LOG_DEBUG("Check signature cert[%d] with cert[%d]", cert_chain.num_certs - 1 - i, cert_chain.num_certs - i - 2);
                        ret = verify_cert(cert_chain.cert[cert_chain.num_certs - 1 - i].blob, cert_chain.cert[cert_chain.num_certs - i - 2].blob);

                }
                if( ret != PEBBLE_STATUS_SUCCESS)
                {
                        PEBBLE_LOG("Invalid signature on certificate chain");
                        return ret;
                }
        }

        if (leaf_first) {
                PEBBLE_LOG_DEBUG("Check signature cert[%d] with trusted anchor", cert_chain.num_certs - 1);
                ret = verify_cert_drk_root(cert_chain.cert[cert_chain.num_certs - 1].blob);
        } else {
                PEBBLE_LOG_DEBUG("Check signature cert[0] with trusted anchor");
                ret = verify_cert_drk_root(cert_chain.cert[0].blob);

        }
        if( ret != PEBBLE_STATUS_SUCCESS)
        {
                PEBBLE_LOG("Invalid signature on certificate chain");
                return ret;
        }

        if (leaf_first)
                *pkey = get_public_key(cert_chain.cert[0].blob);
        else
                *pkey = get_public_key(cert_chain.cert[cert_chain.num_certs - 1].blob);

        //SRR-14532
        if(*pkey == NULL){
                PEBBLE_LOG_DEBUG("Invalid pkey");
                return PEBBLE_KEY_ERROR;
        }
        ret = PEBBLE_STATUS_SUCCESS;
        return ret;        
}

/**
 * @brief
 * verify_aks_cert_chain
 * Validates x509 certificates chain from Android KeyStore
 *
 * @param[in] certificates[]     - certificates chain
 * @param[in] certificates_count - number of certificates
 * @param[in] key                - envelopped key
 *
 * @return PEBBLE status code
 */
pebble_return_code_t verify_aks_cert_chain(cert_chain_t cert_chain, EVP_PKEY **pkey, uint8_t *nonce, uint32_t nonce_len) {
        PEBBLE_LOG_DEBUG("verify_aks_cert_chain()");
        pebble_return_code_t ret = PEBBLE_INVALID_CERTCHAIN;
        uint32_t em_status = -1;

        if(cert_chain.num_certs < 2){
                PEBBLE_LOG("Certificate chain is not completed");
                PEBBLE_LOG_DEBUG("Invalid number of certificates: %d", cert_chain.num_certs);
                return ret;
        }
        
        ret = pebble_ICCC_check_em_status((uint32_t*) &em_status);
        if (ret != PEBBLE_STATUS_SUCCESS) {
                PEBBLE_LOG_DEBUG("ICCC Fail");
                PEBBLE_LOG_DEBUG("Fail to pebble_ICCC_check_em_status: %d", ret);
                return ret;
        }
#if 0
        switch (em_status) {
            case 0: // PROD Device
                    PEBBLE_LOG_DEBUG("Verifing CN PROD");
                    ret = compare_subject_name((uint8_t *) "PEBBLE Intermediate CA", certificates[1].certificate);
                    if(ret != PEBBLE_STATUS_SUCCESS) /* PROD CERT */
                    {
                                PEBBLE_LOG_DEBUG("Invalid subjectName");
                                return ret;
                    }
                    break;

            case 1: // DEV Device
            case 2: // Eng Token on PROD Device
                    PEBBLE_LOG("Verifing CN DEV");
                    ret = compare_subject_name((uint8_t *) "PEBBLE TEST", certificates[1].certificate);
                    if(ret != PEBBLE_STATUS_SUCCESS) /* DEV CERT */
                    {
                                PEBBLE_LOG_DEBUG("Invalid subjectName");
                                return ret;
                    }
                    break;

            default:
                    PEBBLE_LOG_DEBUG("Invalid em_status: %d", em_status);
                    return PEBBLE_READ_EM_STATUS_FAIL;
                    break;
        }

        PEBBLE_LOG("SubjectName checked");
#endif

        /* check the nonce for cert 0 */
        uint8_t * nonce_from_cert;
        ret = get_nonce_from_certificate(cert_chain.cert[0].blob, &nonce_from_cert);
        if (ret != PEBBLE_STATUS_SUCCESS) {
                PEBBLE_LOG("fail to get challenge from attestation cert");
                return ret;
        }
        ret = TEE_MemCompare(nonce_from_cert, nonce, nonce_len);
        if (ret != 0) {
                PEBBLE_LOG("attestation challenge mismatch");
                return PEBBLE_ATN_NONCE_MISMATCH;
        }
        for (size_t i = 0; i < cert_chain.num_certs - 1; i++)
        {
                PEBBLE_LOG_DEBUG("Check signature cert[%d] with cert[%d]", i, i+1);
                ret = verify_cert(cert_chain.cert[i].blob, cert_chain.cert[i+1].blob);
                if( ret != PEBBLE_STATUS_SUCCESS)
                {
                        PEBBLE_LOG("Invalid signature on certificate chain");
                        return ret;
                }
        }

        PEBBLE_LOG_DEBUG("Check signature cert[%d] with trusted anchor", cert_chain.num_certs - 1);
        ret = verify_cert(cert_chain.cert[cert_chain.num_certs - 1].blob, aks_anchor_cert1);
        if( ret != PEBBLE_STATUS_SUCCESS)
        {
                PEBBLE_LOG("failed to check with aks trusted anchor");
                return ret;
        }

        *pkey = get_public_key(cert_chain.cert[0].blob);
        //SRR-14532
        if(*pkey == NULL){
                PEBBLE_LOG_DEBUG("Invalid pkey");
                return PEBBLE_KEY_ERROR;
        }
        ret = PEBBLE_STATUS_SUCCESS;
        return ret;        
}
/**
 * @brief
 * convert_der_to_b64
 * Convert der certificates to PEM.
 * 
 * @param[in]     cert_chain  - array of certificates to be converted
 * @param[in]     num_certs   - the number of certificates in the array
 *
 * @return Status Code
*/
pebble_return_code_t convert_der_to_b64(cert_t *cert_chain, uint32_t num_certs) {
        uint32_t i;
        pebble_return_code_t ret = PEBBLE_STATUS_SUCCESS;

        for (i = 0; i < num_certs; i++) {
                if (base64_encode_in_place(cert_chain[i].blob, &cert_chain[i].len, CERT_MAX_LEN) != BASE64_OK)
                        return PEBBLE_CONVERT_DER_CERT_FAIL;
        }

        return ret;
}
