#include "service_key.h"

#include "ssp_util.h"
#include "crypto_module.h"
#include "tz_utils.h"

uint8_t sDrkCert[2048] = {0,};
uint16_t sDrkCertLen = 0;

uint8_t sServiceCert[2048] = {0,};
uint16_t sServiceCertLen = 0;

uint8_t sWrappedEccKey[300] = {0,};
uint32_t sWrappedEccKeyLen = sizeof(sWrappedEccKey);

uint8_t sWrappedRsaKey[2000] = {0,};
uint32_t sWrappedRsaKeyLen = sizeof(sWrappedRsaKey);

uint8_t sServiceCert_skms[2048] = {0,};
uint16_t sServiceCert_skmsLen = 0;

int32_t parseSEMServiceKey(uint8_t* unwrapData, uint16_t unwrapDataLen) {
    uint8_t drkCert[2048] = {0x00,};
    uint16_t drkCertSize = 0;

    uint8_t semServiceKeyCert[2048] = {0x00,};
    uint16_t semServiceKeyCertSize = 0;

    uint8_t eccPrivateKey[124] = {0x00,};
    uint16_t eccPrivateKeySize = 0;

    uint32_t offset = 0;
    uint16_t realDrkLen = 0;

    (void)unwrapDataLen;

    // Device Root Key Cert
    if (unwrapData[offset] == 0x01) {
        memcpy(&drkCertSize, unwrapData + offset + 1, 2);
        offset = offset + 1 + 2;
        if (drkCertSize > sizeof(drkCert)) {
            LOGD("buffer is not enough");
            return -1;
        }
        memcpy(drkCert, unwrapData+offset, drkCertSize);
        hex_print_tag_debug("DRK Cert", drkCert, drkCertSize);

        offset = offset + drkCertSize;
        // SEM Service Key Cert
        if (unwrapData[offset] == 0x01) {
            memcpy(&semServiceKeyCertSize, unwrapData + offset + 1, 2);
            offset = offset + 1 + 2;
            if (semServiceKeyCertSize > sizeof(semServiceKeyCert)) {
                LOGD("buffer is not enough");
                return -1;
            }
            memcpy(semServiceKeyCert, unwrapData+offset, semServiceKeyCertSize);
            hex_print_tag_debug("Service Key Cert", semServiceKeyCert, semServiceKeyCertSize);
            offset = offset + semServiceKeyCertSize;
            // ECC Private Key
            if (unwrapData[offset] == 0x03) {
                memcpy(&eccPrivateKeySize, unwrapData + offset + 1, 2);
                offset = offset + 1 + 2;
                if (eccPrivateKeySize > sizeof(eccPrivateKey)) {
                    LOGD("buffer is not enough");
                    return -1;
                }
                memcpy(eccPrivateKey, unwrapData+offset, eccPrivateKeySize);
                hex_print_tag_debug("ECC Private Key Structure", eccPrivateKey, eccPrivateKeySize);
                offset = offset + eccPrivateKeySize;
            } else {
                LOGD("ERROR : ECC PrivateKey tag not found");
                return -1;
            }
        } else {
            LOGD("ERROR : SEM ServiceKey CERT tag not found");
            return -1;
        }
    } else {
        LOGD("ERROR : DRK CERT tag not found");
        return -1;
    }

    // unwrap data parsing done.  TODO HERE...
    // store in static memory
    hex_print_tag_debug("eccPrivateKey", eccPrivateKey, eccPrivateKeySize);

    realDrkLen = drkCert[2];
    realDrkLen = realDrkLen << 8;
    realDrkLen |= drkCert[3];
    realDrkLen += 4;
    if (realDrkLen > sizeof(sDrkCert)) {
        LOGD("buffer is not enough");
        return -1;
    }

    memcpy(sDrkCert, drkCert, realDrkLen);
    sDrkCertLen = realDrkLen;
    if (semServiceKeyCertSize > sizeof(sServiceCert)) {
        LOGD("buffer is not enough");
        return -1;
    }
    memcpy(sServiceCert, semServiceKeyCert, semServiceKeyCertSize);
    sServiceCertLen = semServiceKeyCertSize;

#ifdef USE_TRUSTY_UNISOC
    if (wrapInternalData("service_key", eccPrivateKey, eccPrivateKeySize) != SSPSTATUS_SUCCESS) {
#else
    if (wrapInternalData(eccPrivateKey, eccPrivateKeySize, sWrappedEccKey, &sWrappedEccKeyLen) != SSPSTATUS_SUCCESS) {
#endif
        LOGE("Wrap eccPrivateKey is failed");
        secure_memclear( eccPrivateKey, sizeof( eccPrivateKey ) );
        return -1;
    }

    hex_print_tag_debug("sWrappedEccKey", sWrappedEccKey, sWrappedEccKeyLen);
    secure_memclear( eccPrivateKey, sizeof( eccPrivateKey ) );

    return RET_SUCCESS;
}

void unwrapSEMServiceKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;
    uint32_t current_pos;
    uint8_t input[WRAPPED_CERT_SIZE] = {0, };
    uint32_t inputSize = sizeof(input);
    uint8_t output[WRAPPED_CERT_SIZE] = {0, };
    uint32_t outputSize = WRAPPED_CERT_SIZE;

#ifdef USE_QSEE
    const uint8_t DRK_TID[QSEE_MESSAGE_APP_NAME_MAX_LEN] = "skm";
#endif
#if defined(USE_BLOWFISH) || defined(USE_TRUSTY_UNISOC)
    const uint8_t DRK_TID[SSP_TID_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x4b, 0x4d};
#endif

    LOGD("unwrapSEMServiceKey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_CERT_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }
    memcpy(input, cmd->data, inputSize);
    hex_print_tag_debug("Wrapped service key data", input, inputSize);

#if defined(USE_BLOWFISH) || defined(USE_QSEE) || defined(USE_TRUSTY_UNISOC)
    ret = ssp_unwrap_secure_object(DRK_TID, input, inputSize, output, &outputSize);
#else
    ret = ssp_unwrap_secure_object(input, inputSize, output, &outputSize);
#endif

    if ( WRAPPED_CERT_SIZE < inputSize ) {
        LOGE("Output data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }

    if (ret == RET_SUCCESS) {
        hex_print_tag_debug("Unwrapped", output, outputSize);
        ret = parseSEMServiceKey(output, outputSize);
        if (ret != RET_SUCCESS) {
            LOGE("parseSEMServiceKey Failed.");
        } else {
            current_pos = 0;
            memcpy(rsp->data + current_pos, &sDrkCertLen, 2);
            current_pos += 2;
            memcpy(rsp->data + current_pos, sDrkCert, sDrkCertLen);
            current_pos += sDrkCertLen;

            memcpy(rsp->data + current_pos, &sServiceCertLen, 2);
            current_pos += 2;
            memcpy(rsp->data + current_pos, sServiceCert, sServiceCertLen);
            current_pos += sServiceCertLen;

            rsp->dataLen = current_pos;
        }
    } else {
        LOGD("unwrapSEMServiceKey failed !!, ret : %x", ret);
    }
    rsp->ret = ret;
}

void rewrapSEMServiceKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t wrappedKey[WRAPPED_CERT_SIZE] = {0, };
    uint32_t wrappedKeySize = sizeof(wrappedKey);
    uint8_t unwrappedKey[WRAPPED_CERT_SIZE] = {0, };
    uint32_t unwrappedKeySize = sizeof(unwrappedKey);

#ifdef USE_QSEE
    const uint8_t DRK_TID[QSEE_MESSAGE_APP_NAME_MAX_LEN] = "skm";
#endif

#if defined(USE_BLOWFISH) || defined(USE_TRUSTY_UNISOC)
    const uint8_t DRK_TID[SSP_TID_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x4b, 0x4d};
#endif

    LOGD("rewrapSEMServiceKey started");
    wrappedKeySize = cmd->dataLen;
    if (wrappedKeySize > WRAPPED_CERT_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }

    memcpy(wrappedKey, cmd->data, wrappedKeySize);

#if defined(USE_BLOWFISH) || defined(USE_QSEE) || defined(USE_TRUSTY_UNISOC)
    ret = ssp_unwrap_secure_object(DRK_TID, wrappedKey, wrappedKeySize, unwrappedKey, &unwrappedKeySize);
#else
    ret = ssp_unwrap_secure_object(wrappedKey, wrappedKeySize, unwrappedKey, &unwrappedKeySize);
#endif

    if (ret == RET_SUCCESS) {

        wrappedKeySize = sizeof(wrappedKey);
#ifdef USE_TRUSTY_UNISOC
        ret = wrapInternalData("service_key", unwrappedKey, unwrappedKeySize);
#else
        ret = wrapInternalData(unwrappedKey, unwrappedKeySize, wrappedKey, &wrappedKeySize);
#endif
        if (ret != RET_SUCCESS) {
            LOGE("wrapInternalData Failed.");
        } else {
            if ( MAX_DATA_SIZE < wrappedKeySize || sizeof(wrappedKey) < wrappedKeySize ) {
                LOGE("Input data is over the buffer.");
                rsp->ret = RET_ERR_BUFFER_OVERFLOW;
                return ;
            }

            memcpy(rsp->data, wrappedKey, wrappedKeySize);
            rsp->dataLen = wrappedKeySize;
        }
    } else {
        LOGD("rewrapSEMServiceKey failed !!, ret : %x", ret);
    }
    rsp->ret = ret;
}

void unwrapRewrappedSEMServiceKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t input[WRAPPED_CERT_SIZE] = {0, };
    uint32_t inputSize;
    uint8_t output[WRAPPED_CERT_SIZE] = {0, };
    uint32_t outputSize = WRAPPED_CERT_SIZE;

    uint32_t current_pos;

    LOGD("unwrapRewrappedSEMServiceKey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_CERT_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }
    memcpy(input, cmd->data, inputSize);

#ifdef USE_TRUSTY_UNISOC
    ret = unwrapInternalData("service_key", output, &outputSize);
#else
    ret = unwrapInternalData(input, inputSize, output, &outputSize);
#endif
    if ( WRAPPED_CERT_SIZE < outputSize )
    {
        LOGE("Output data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }

    if (ret == RET_SUCCESS) {
        ret = parseSEMServiceKey(output, outputSize);
        if (ret != RET_SUCCESS) {
            LOGE("parseSEMServiceKey Failed.");
        } else {
            current_pos = 0;
            memcpy(rsp->data + current_pos, &sDrkCertLen, 2);
            current_pos += 2;
            memcpy(rsp->data + current_pos, sDrkCert, sDrkCertLen);
            current_pos += sDrkCertLen;

            memcpy(rsp->data + current_pos, &sServiceCertLen, 2);
            current_pos += 2;
            memcpy(rsp->data + current_pos, sServiceCert, sServiceCertLen);
            current_pos += sServiceCertLen;

            rsp->dataLen = current_pos;
        }
    } else {
        LOGD("unwrapRewrappedSEMServiceKey failed !!, ret : %x", ret);
    }
    rsp->ret = ret;
}

static int32_t parseTlvData(uint8_t *tlvData, uint32_t leftBuffSize, uint8_t *data, uint32_t dataBuffSize, uint32_t *dataSize) {
    uint32_t total_len = 0;

    if (total_len + 1 > leftBuffSize) {
        LOGE("Over the Buffer size");
        return RET_ERR_WRONG_INPUT_FORMAT;
    }

    if (tlvData[total_len] == 0x82) {
        total_len++;
        if (total_len + 2 > leftBuffSize) {
            LOGE("Over the Buffer size");
            return RET_ERR_WRONG_INPUT_FORMAT;
        }
        *dataSize = tlvData[total_len++];
        *dataSize = *dataSize << 8;
        *dataSize |= tlvData[total_len++];
        if (dataBuffSize < *dataSize) {
            LOGE("Buffer is not enough");
            return RET_ERR_BUFFER_NOT_ENOUGH;
        }
        if (total_len + *dataSize > leftBuffSize) {
            LOGE("Over the Buffer size");
            return RET_ERR_WRONG_INPUT_FORMAT;
        }
        memcpy(data, tlvData + total_len, *dataSize);
        total_len += *dataSize;
    } else if (tlvData[total_len] == 0x81) {
        total_len++;
        if (total_len + 1 > leftBuffSize) {
            LOGE("Over the Buffer size");
            return RET_ERR_WRONG_INPUT_FORMAT;
        }
        *dataSize = tlvData[total_len++];
        if (dataBuffSize < *dataSize) {
            LOGE("Buffer is not enough");
            return RET_ERR_BUFFER_NOT_ENOUGH;
        }
        if (total_len + *dataSize > leftBuffSize) {
            LOGE("Over the Buffer size");
            return RET_ERR_WRONG_INPUT_FORMAT;
        }
        memcpy(data, tlvData + total_len, *dataSize);
        total_len += *dataSize;
    } else {
        *dataSize = tlvData[total_len++];
        if (dataBuffSize < *dataSize) {
            LOGE("Buffer is not enough");
            return RET_ERR_BUFFER_NOT_ENOUGH;
        }
        if (total_len + *dataSize > leftBuffSize) {
            LOGE("Over the Buffer size");
            return RET_ERR_WRONG_INPUT_FORMAT;
        }
        memcpy(data, tlvData + total_len, *dataSize);
        total_len += *dataSize;
    }

    return total_len;
}

int32_t parseSKMSServiceKey(uint8_t* unwrapData, uint16_t unwrapDataLen) {
    uint8_t drkCert[4096] = {0x00,};
    uint16_t drkCertSize = 0;

    uint8_t skmsServiceKeyCert[4096] = {0x00,};
    uint16_t skmsServiceKeyCertSize = 0;

    uint8_t rsaPrivateKey[2048] = {0x00,};
    uint16_t rsaPrivateKeySize = 0;

    uint32_t offset = 0;

    (void)unwrapDataLen;

    // Device Root Key Cert
    if (unwrapDataLen < 1) {
        LOGE("input buffer is not enough");
        return RET_ERR_BUFFER_NOT_ENOUGH;
    }
    if (unwrapData[offset] == 0x01) {
        memcpy(&drkCertSize, unwrapData + offset + 1, 2);
        offset = offset + 1 + 2;
        if (drkCertSize > sizeof(drkCert)) {
            LOGE("buffer is not enough");
            return RET_ERR_BUFFER_NOT_ENOUGH;
        }
        memcpy(drkCert, unwrapData+offset, drkCertSize);
        hex_print_tag_debug("DRK Cert", drkCert, drkCertSize);
        offset = offset + drkCertSize;

        if (offset >= unwrapDataLen) {
            LOGE("offset is exceeded unwrapData buffer size");
            return RET_ERR_BUFFER_NOT_ENOUGH;
        }

        // SKMS Service Key Cert
        if (unwrapData[offset] == 0x01) {
            memcpy(&skmsServiceKeyCertSize, unwrapData + offset + 1, 2);
            offset = offset + 1 + 2;
            if (skmsServiceKeyCertSize > sizeof(skmsServiceKeyCert)) {
                LOGE("buffer is not enough");
                return RET_ERR_BUFFER_NOT_ENOUGH;
            }
            if (offset >= unwrapDataLen) {
                LOGE("offset is exceeded unwrapData buffer size");
                return RET_ERR_BUFFER_NOT_ENOUGH;
            }

            memcpy(skmsServiceKeyCert, unwrapData+offset, skmsServiceKeyCertSize);
            hex_print_tag_debug("SKMS Service Key Cert", skmsServiceKeyCert, skmsServiceKeyCertSize);
            offset = offset + skmsServiceKeyCertSize;
            LOGD("parsing skms SVC key done");

            if (offset >= unwrapDataLen) {
                LOGE("offset is exceeded unwrapData buffer size");
                return RET_ERR_BUFFER_NOT_ENOUGH;
            }

            // RSA Private Key
            if (unwrapData[offset] == 0x03) {
                memcpy(&rsaPrivateKeySize, unwrapData + offset + 1, 2);
                offset = offset + 1 + 2;

                if (offset >= unwrapDataLen) {
                    LOGE("offset is exceeded unwrapData buffer size");
                    return RET_ERR_BUFFER_NOT_ENOUGH;
                }
                if (rsaPrivateKeySize > sizeof(rsaPrivateKey)) {
                    LOGE("buffer is not enough");
                    return RET_ERR_BUFFER_NOT_ENOUGH;
                }
                memcpy(rsaPrivateKey, unwrapData+offset, rsaPrivateKeySize);
                hex_print_tag_debug("RSA Private Key Structure", rsaPrivateKey, rsaPrivateKeySize);
            } else {
                LOGE("ERROR : RSA PrivateKey tag not found");
                return RET_ERR_WRONG_INPUT_FORMAT;
            }
        } else {
            LOGE("ERROR : SKMS ServiceKey CERT tag not found");
            return RET_ERR_WRONG_INPUT_FORMAT;
        }
    } else {
        LOGE("ERROR : DRK CERT tag not found");
        return RET_ERR_WRONG_INPUT_FORMAT;
    }

    // unwrap data parsing done.
    // store in static memory

    if (drkCertSize > sizeof(sDrkCert)) {
        LOGE("buffer is not enough");
        return RET_ERR_BUFFER_NOT_ENOUGH;
    }
    memcpy(sDrkCert, drkCert, drkCertSize);
    sDrkCertLen = drkCertSize;

    if (skmsServiceKeyCertSize > sizeof(sServiceCert_skms)) {
        LOGE("buffer is not enough");
        return RET_ERR_BUFFER_NOT_ENOUGH;
    }
    memcpy(sServiceCert_skms, skmsServiceKeyCert, skmsServiceKeyCertSize);
    sServiceCert_skmsLen = skmsServiceKeyCertSize;

#ifdef USE_TRUSTY_UNISOC
    if (wrapInternalData("skms_service_key", rsaPrivateKey, rsaPrivateKeySize) != SSPSTATUS_SUCCESS) {
#else
    if (wrapInternalData(rsaPrivateKey, rsaPrivateKeySize, sWrappedRsaKey, &sWrappedRsaKeyLen) != SSPSTATUS_SUCCESS) {
#endif
        LOGE("Wrap rsaPrivateKey is failed");
        secure_memclear( rsaPrivateKey, sizeof( rsaPrivateKey ) );
        return RET_ERR_DATA_WRAPPING_FAIL;
    }

    secure_memclear( rsaPrivateKey, sizeof( rsaPrivateKey ) );
    hex_print_tag_debug("sWrappedRsaKey", sWrappedRsaKey, sWrappedRsaKeyLen);

    return RET_SUCCESS;
}

void rewrapSKMSServiceKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t input[WRAPPED_RSA_CERT_SIZE] = {0, };
    uint32_t inputSize = sizeof(input);
    uint8_t output[WRAPPED_RSA_CERT_SIZE] = {0, };
    uint32_t outputSize = sizeof(output);

#ifdef USE_QSEE
    const uint8_t DRK_TID[QSEE_MESSAGE_APP_NAME_MAX_LEN] = "skm";
#endif

#if defined(USE_BLOWFISH) || defined(USE_TRUSTY_UNISOC)
    const uint8_t DRK_TID[SSP_TID_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x4b, 0x4d};
#endif

    LOGD("rewrapSKMSServiceKey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_RSA_CERT_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }

    memcpy(input, cmd->data, inputSize);

#if defined(USE_BLOWFISH) || defined(USE_QSEE) || defined(USE_TRUSTY_UNISOC)
    ret = ssp_unwrap_secure_object(DRK_TID, input, inputSize, output, &outputSize);
#else
    ret = ssp_unwrap_secure_object(input, inputSize, output, &outputSize);
#endif

    if (ret == RET_SUCCESS) {
        inputSize = sizeof(input);

#ifdef USE_TRUSTY_UNISOC
        ret = wrapInternalData("skms_service_key", output, outputSize);
#else
        ret = wrapInternalData(output, outputSize, input, &inputSize);
#endif
        if (ret != RET_SUCCESS) {
            LOGE("wrapInternalData Failed.");
        } else {
            memcpy(rsp->data, input, inputSize);
            rsp->dataLen = inputSize;
        }
    } else {
        LOGE("rewrapSKMSServiceKey failed !!, ret : %x", ret);
    }
    rsp->ret = ret;
}

void unwrapRewrappedSKMSServiceKey(p_cmd_t cmd, p_rsp_t rsp, uint8_t type) {
    int32_t ret = RET_SUCCESS;
    uint8_t input[WRAPPED_RSA_CERT_SIZE] = {0, };
    uint32_t inputSize;
    uint8_t output[WRAPPED_RSA_CERT_SIZE] = {0, };
    uint32_t outputSize = WRAPPED_RSA_CERT_SIZE;
    uint32_t current_pos;

    LOGD("unwrapRewrappedSKMSServiceKey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_RSA_CERT_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        return ;
    }
    memcpy(input, cmd->data, inputSize);

#ifdef USE_TRUSTY_UNISOC
    ret = unwrapInternalData("skms_service_key", output, &outputSize);
#else
    ret = unwrapInternalData(input, inputSize, output, &outputSize);
#endif
    if (ret == RET_SUCCESS) {
        ret = parseSKMSServiceKey(output, outputSize);
        if (ret != RET_SUCCESS) {
            LOGE("parseSKMSServiceKey Failed.");
        } else {
            current_pos = 0;
            if(type == 1 || cmd->cmd_id == CMD_SKMS_REWRAPPED_SERVICEKEY_UNWRAP) {
                memcpy(rsp->data + current_pos, &sDrkCertLen, 2);
                current_pos += 2;
                memcpy(rsp->data + current_pos, sDrkCert, sDrkCertLen);
                current_pos += sDrkCertLen;
            }
            if(type == 2 || cmd->cmd_id == CMD_SKMS_REWRAPPED_SERVICEKEY_UNWRAP) {
                memcpy(rsp->data + current_pos, &sServiceCert_skmsLen, 2);
                current_pos += 2;
                memcpy(rsp->data + current_pos, sServiceCert_skms, sServiceCert_skmsLen);
                current_pos += sServiceCert_skmsLen;
            }
            rsp->dataLen = current_pos;
        }
    } else {
        LOGE("unwrapRewrappedSKMSServiceKey failed !!, ret : %x", ret);
    }
    rsp->ret = ret;
}

void signMsgUnwrappedSKMSServiceKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;
    uint32_t offset =0;
    uint8_t input[WRAPPED_RSA_CERT_SIZE] = {0, };
    uint16_t inputSize;
    rsa_key_t rsa_key;
    RSA  *rsaKey = NULL;
    uint8_t sig[RSA_SIG_SIZE];
    uint32_t sig_size = RSA_SIG_SIZE;

    uint8_t unwrappedRsaKey[1920] = {0, };
    uint32_t unwrappedRsaKeyLen = sizeof(unwrappedRsaKey);

    LOGD("signMsgUnwrappedSKMSServiceKey started");
    //====================== copying rsa priv key
    hex_print_tag_debug("sWrappedRsaKey", sWrappedRsaKey, sWrappedRsaKeyLen);

#ifdef USE_TRUSTY_UNISOC
    if (unwrapInternalData("skms_service_key", unwrappedRsaKey, &unwrappedRsaKeyLen) != SSPSTATUS_SUCCESS) {
#else
    if (unwrapInternalData(sWrappedRsaKey, sWrappedRsaKeyLen, unwrappedRsaKey, &unwrappedRsaKeyLen) != SSPSTATUS_SUCCESS) {
#endif    
        LOGE("Unwrap sWrappedRsaKey failed");
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }

    hex_print_tag_debug("unwrappedRsaKey", unwrappedRsaKey, unwrappedRsaKeyLen);


    //====================== parsing input msg to be signed
    memcpy(&inputSize, cmd->data + offset, 2);
    offset += 2;

    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize > sizeof(input)) {
        LOGE("buffer is not enough");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("inputSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(input, cmd->data + offset, inputSize);

    //=======================================
    // RSA 2048
    offset = 0;
    memset((uint8_t *)&rsa_key, 0, sizeof(rsa_key_t));

    if (unwrappedRsaKey[offset] == 0x30) {
        offset += 4;
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 3;
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.modulus, sizeof(rsa_key.modulus), &(rsa_key.modulus_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.modulus", rsa_key.modulus, rsa_key.modulus_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.publicExponent, sizeof(rsa_key.publicExponent), &(rsa_key.publicExponent_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.publicExponent", rsa_key.publicExponent, rsa_key.publicExponent_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.privateExponent, sizeof(rsa_key.privateExponent), &(rsa_key.privateExponent_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.privateExponent", rsa_key.privateExponent, rsa_key.privateExponent_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.prime1, sizeof(rsa_key.prime1), &(rsa_key.prime1_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.prime1", rsa_key.prime1, rsa_key.prime1_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.prime2, sizeof(rsa_key.prime2), &(rsa_key.prime2_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.prime2", rsa_key.prime2, rsa_key.prime2_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.exponent1, sizeof(rsa_key.exponent1), &(rsa_key.exponent1_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.exponent1", rsa_key.exponent1, rsa_key.exponent1_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen - offset, rsa_key.exponent2, sizeof(rsa_key.exponent2), &(rsa_key.exponent2_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.exponent2", rsa_key.exponent2, rsa_key.exponent2_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if (offset >= sizeof(unwrappedRsaKey)) {
        LOGE("offset is exceeded sizeof(key_block) buffer size");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (unwrappedRsaKey[offset] == 0x02) {
        offset += 1;
        if (offset >= sizeof(unwrappedRsaKey)) {
            LOGE("offset is exceeded sizeof(key_block) buffer size");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if ((ret = parseTlvData(unwrappedRsaKey + offset, unwrappedRsaKeyLen- offset, rsa_key.coefficient, sizeof(rsa_key.coefficient), &(rsa_key.coefficient_size))) < 0) {
            goto error;
        }
        offset += ret;
        //hex_print_tag_debug("rsa_key.coefficient", rsa_key.coefficient, rsa_key.coefficient_size);
    } else {
        LOGE("ERROR : PrivateKey tag not found");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Verifying
    if (crypto_regen_rsa_privkey(&rsaKey, &rsa_key) != CRYPTO_STATUS_SUCCESS) {
        LOGE("crypto_regen_rsa_privkey is failed");
        ret = RET_ERR_REGEN_RSA_KEY_FAIL;
        goto error;
    }
    hex_print_tag_debug("plain txt", input, inputSize);
    if (crypto_rsa_sign_pss(MD_TYPE_SHA256, 0, rsaKey, input, inputSize, sig, &sig_size) != CRYPTO_STATUS_SUCCESS) {
        LOGE("crypto_rsa_sign_pkcs is failed");
        ret = RET_ERR_SIGN_FAIL;
        goto error;
    }
    hex_print_tag_debug("sig", sig, sig_size);

    rsp->dataLen = sig_size;
    memcpy(rsp->data,sig,sig_size);

    if (crypto_rsa_verify_pss(MD_TYPE_SHA256, 0, rsaKey, input, inputSize, sig, sig_size) != CRYPTO_STATUS_SUCCESS) {
        LOGE("crypto_rsa_verify_pkcs is failed");
        ret = RET_ERR_VERIFY_FAIL;
        goto error;
    }

    ret = RET_SUCCESS;
    rsp->ret = ret;

error:
    if (rsaKey != NULL) {
        crypto_clear_rsa_key(&rsaKey);
    }

    secure_memclear(&rsa_key, sizeof(rsa_key_t));
    secure_memclear(unwrappedRsaKey, sizeof(unwrappedRsaKey));

    LOGD("signMsgUnwrappedSKMSServiceKey end : ret = %d", ret);
    rsp->ret = ret;
}

