1
0
Fork 0
mirror of https://github.com/eliboa/TegraRcmGUI.git synced 2024-11-25 03:32:05 +00:00
TegraRcmGUI/kourou/libs/tegrarcm/rcm.c
2020-06-24 20:30:39 +02:00

400 lines
9.8 KiB
C

/*
* Copyright (c) 2011-2016, NVIDIA CORPORATION
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "rcm.h"
#include "aes-cmac.h"
#include "rsa-pss.h"
static int rcm_sign_msg(uint8_t *buf);
static int rcm1_sign_msg(uint8_t *buf);
static int rcm35_sign_msg(uint8_t *buf);
static int rcm40_sign_msg(uint8_t *buf);
static void rcm_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len);
static void rcm1_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len);
static void rcm35_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len);
static void rcm40_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len);
static uint8_t *rcm_get_msg_payload(uint8_t *buf);
static void rcm_msg_pad(uint8_t *data, uint32_t len);
static uint32_t rcm_get_pad_len(uint32_t payload_len);
static uint32_t rcm_get_msg_buf_len(uint32_t payload_len);
static uint32_t rcm_version = 0;
static uint32_t message_size = 0;
static const char *rcm_keyfile = NULL;
int rcm_init(uint32_t version, const char *keyfile)
{
int ret = -EINVAL;
if (version == RCM_VERSION_1) {
rcm_version = version;
message_size = sizeof(rcm1_msg_t);
ret = 0;
}
else if (version == RCM_VERSION_35) {
rcm_version = version;
message_size = sizeof(rcm35_msg_t);
ret = 0;
}
else if (version == RCM_VERSION_40) {
rcm_version = version;
message_size = sizeof(rcm40_msg_t);
ret = 0;
}
rcm_keyfile = keyfile;
return ret;
}
uint32_t rcm_get_msg_len(uint8_t *msg)
{
if (rcm_version == RCM_VERSION_1)
return ((rcm1_msg_t*)msg)->len_insecure;
else if (rcm_version == RCM_VERSION_35)
return ((rcm35_msg_t*)msg)->len_insecure;
else if (rcm_version == RCM_VERSION_40)
return ((rcm40_msg_t*)msg)->len_insecure;
else
return 0;
}
int rcm_create_msg(
uint32_t opcode,
uint8_t *args,
uint32_t args_len,
uint8_t *payload,
uint32_t payload_len,
uint8_t **buf)
{
int ret = 0;
uint32_t msg_len;
uint8_t *msg = NULL;
uint8_t *msg_payload;
// create message buffer
msg_len = rcm_get_msg_buf_len(payload_len);
msg = malloc(msg_len);
if (!msg) {
ret = -ENOMEM;
goto done;
}
// initialize message
rcm_init_msg(msg, msg_len, opcode, args, args_len, payload_len);
// fill message payload
msg_payload = rcm_get_msg_payload(msg);
if (payload_len)
memcpy(msg_payload, payload, payload_len);
// sign message
rcm_sign_msg(msg);
done:
if (ret) {
free(msg);
msg = NULL;
}
*buf = msg;
return ret;
}
static int rcm_sign_msg(uint8_t *buf)
{
if (rcm_version == RCM_VERSION_35)
return rcm35_sign_msg(buf);
else if (rcm_version == RCM_VERSION_40)
return rcm40_sign_msg(buf);
else if (rcm_version == RCM_VERSION_1)
return rcm1_sign_msg(buf);
else
return -EINVAL;
}
static int rcm1_sign_msg(uint8_t *buf)
{
rcm1_msg_t *msg;
uint32_t crypto_len;
msg = (rcm1_msg_t*)buf;
// signing does not include the len_insecure and
// cmac_hash fields at the beginning of the message.
crypto_len = msg->len_insecure - sizeof(msg->len_insecure) -
sizeof(msg->cmac_hash);
if (crypto_len % RCM_AES_BLOCK_SIZE) {
return -EMSGSIZE;
}
cmac_hash(msg->reserved, crypto_len, msg->cmac_hash);
return 0;
}
static int rcm35_sign_msg(uint8_t *buf)
{
rcm35_msg_t *msg;
uint32_t crypto_len;
msg = (rcm35_msg_t*)buf;
// signing does not include the len_insecure, modulus
// and object signature at the beginning of the message
crypto_len = msg->len_insecure - sizeof(msg->len_insecure) -
sizeof(msg->modulus) -
sizeof(msg->object_sig);
if (crypto_len % RCM_AES_BLOCK_SIZE) {
return -EMSGSIZE;
}
cmac_hash(msg->reserved, crypto_len, msg->object_sig.cmac_hash);
if (rcm_keyfile)
rsa_pss_sign(rcm_keyfile, msg->reserved, crypto_len,
msg->object_sig.rsa_pss_sig, msg->modulus);
return 0;
}
static int rcm40_sign_msg(uint8_t *buf)
{
rcm40_msg_t *msg;
uint32_t crypto_len;
msg = (rcm40_msg_t*)buf;
// signing does not include the len_insecure, modulus
// and object signature at the beginning of the message
crypto_len = msg->len_insecure - sizeof(msg->len_insecure) -
sizeof(msg->modulus) -
sizeof(msg->object_sig);
if (crypto_len % RCM_AES_BLOCK_SIZE) {
return -EMSGSIZE;
}
cmac_hash(msg->reserved, crypto_len, msg->object_sig.cmac_hash);
if (rcm_keyfile)
rsa_pss_sign(rcm_keyfile, msg->reserved, crypto_len,
msg->object_sig.rsa_pss_sig, msg->modulus);
return 0;
}
static uint32_t rcm_get_msg_buf_len(uint32_t payload_len)
{
return message_size + payload_len +
rcm_get_pad_len(payload_len);
}
static uint8_t *rcm_get_msg_payload(uint8_t *buf)
{
return buf + message_size;
}
static void rcm_msg_pad(uint8_t *data, uint32_t len)
{
if (!len)
return;
*data = 0x80;
memset(data+1, 0, len-1);
}
static void rcm_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len)
{
if (rcm_version == RCM_VERSION_35)
rcm35_init_msg(buf, msg_len, opcode, args,
args_len, payload_len);
else if (rcm_version == RCM_VERSION_40)
rcm40_init_msg(buf, msg_len, opcode, args,
args_len, payload_len);
else if (rcm_version == RCM_VERSION_1)
rcm1_init_msg(buf, msg_len, opcode, args,
args_len, payload_len);
}
static void rcm35_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len)
{
uint32_t padding_len;
rcm35_msg_t *msg;
msg = (rcm35_msg_t *)buf;
padding_len = rcm_get_pad_len(payload_len);
msg->len_insecure = sizeof(rcm35_msg_t) + payload_len +
padding_len;
memset(&msg->object_sig.cmac_hash, 0x0, sizeof(msg->object_sig.cmac_hash));
memset(&msg->reserved, 0x0, sizeof(msg->reserved));
msg->opcode = opcode;
msg->len_secure = msg->len_insecure;
msg->payload_len = payload_len;
msg->rcm_version = RCM_VERSION_35;
if (args_len)
memcpy(msg->args, args, args_len);
memset(msg->args + args_len, 0x0, sizeof(msg->args) - args_len);
rcm_msg_pad(msg->padding, sizeof(msg->padding));
rcm_msg_pad(buf + sizeof(rcm35_msg_t) + payload_len, padding_len);
}
static void rcm40_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len)
{
uint32_t padding_len;
rcm40_msg_t *msg;
msg = (rcm40_msg_t *)buf;
padding_len = rcm_get_pad_len(payload_len);
msg->len_insecure = sizeof(rcm40_msg_t) + payload_len +
padding_len;
memset(&msg->object_sig.cmac_hash, 0x0, sizeof(msg->object_sig.cmac_hash));
memset(&msg->reserved, 0x0, sizeof(msg->reserved));
msg->opcode = opcode;
msg->len_secure = msg->len_insecure;
msg->payload_len = payload_len;
msg->rcm_version = RCM_VERSION_40;
if (args_len)
memcpy(msg->args, args, args_len);
memset(msg->args + args_len, 0x0, sizeof(msg->args) - args_len);
rcm_msg_pad(msg->padding, sizeof(msg->padding));
rcm_msg_pad(buf + sizeof(rcm40_msg_t) + payload_len, padding_len);
}
static void rcm1_init_msg(
uint8_t *buf,
uint32_t msg_len,
uint32_t opcode,
void *args,
uint32_t args_len,
uint32_t payload_len)
{
uint32_t padding_len;
rcm1_msg_t *msg;
msg = (rcm1_msg_t *)buf;
padding_len = rcm_get_pad_len(payload_len);
msg->len_insecure = sizeof(rcm1_msg_t) + payload_len +
padding_len;
memset(&msg->cmac_hash, 0x0, sizeof(msg->cmac_hash));
memset(&msg->reserved, 0x0, sizeof(msg->reserved));
msg->opcode = opcode;
msg->len_secure = msg->len_insecure;
msg->payload_len = payload_len;
msg->rcm_version = RCM_VERSION_1;
if (args_len)
memcpy(msg->args, args, args_len);
memset(msg->args + args_len, 0x0, sizeof(msg->args) - args_len);
rcm_msg_pad(msg->padding, sizeof(msg->padding));
rcm_msg_pad(buf + sizeof(rcm1_msg_t) + payload_len, padding_len);
}
static uint32_t rcm_get_pad_len(uint32_t payload_len)
{
uint32_t pad_len = 0;
uint32_t msg_len = message_size + payload_len;
// First, use padding to bump the message size up to the minimum.
if (msg_len < RCM_MIN_MSG_LENGTH) {
pad_len = RCM_MIN_MSG_LENGTH - msg_len;
msg_len += pad_len;
}
/*
* Next, add any extra padding needed to bump the relevant subset
* of the data up to a multiple of 16 bytes. Subtracting off the
* rcm_msg_t size handles the initial data that is not part of
* the hashing and encryption.
*/
pad_len += 16 - ((msg_len - message_size) & 0xf);
return pad_len;
}