summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.c5
-rw-r--r--src/rcm.c145
-rw-r--r--src/rcm.h23
3 files changed, 159 insertions, 14 deletions
diff --git a/src/main.c b/src/main.c
index 89f04c9..ebc766e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -182,6 +182,11 @@ int main(int argc, char **argv)
printf("uid: 0x%" PRIx64 "\n", uid);
+ // initialize RCM
+ ret = rcm_init(RCM_VERSION_1);
+ if (ret)
+ error(1, errno, "RCM initialize failed");
+
// create query version message
rcm_create_msg(RCM_CMD_QUERY_RCM_VERSION, NULL, 0, NULL, 0, &msg_buff);
diff --git a/src/rcm.c b/src/rcm.c
index 2fed49f..c5b3aac 100644
--- a/src/rcm.c
+++ b/src/rcm.c
@@ -34,6 +34,8 @@
#include "aes-cmac.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 void rcm_init_msg(
uint8_t *buf,
uint32_t msg_len,
@@ -41,14 +43,53 @@ static void rcm_init_msg(
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 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;
+
+int rcm_init(uint32_t version)
+{
+ 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;
+ }
+ return ret;
+}
+
uint32_t rcm_get_msg_len(uint8_t *msg)
{
- return ((rcm_msg_t*)msg)->len_insecure;
+ 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
+ return 0;
}
int rcm_create_msg(
@@ -96,10 +137,20 @@ done:
static int rcm_sign_msg(uint8_t *buf)
{
- rcm_msg_t *msg;
+ if (rcm_version == RCM_VERSION_35)
+ return rcm35_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 = (rcm_msg_t*)buf;
+ msg = (rcm1_msg_t*)buf;
// signing does not include the len_insecure and
// cmac_hash fields at the beginning of the message.
@@ -113,15 +164,35 @@ static int rcm_sign_msg(uint8_t *buf)
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);
+ return 0;
+}
+
static uint32_t rcm_get_msg_buf_len(uint32_t payload_len)
{
- return sizeof(rcm_msg_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 + sizeof(rcm_msg_t);
+ return buf + message_size;
}
static void rcm_msg_pad(uint8_t *data, uint32_t len)
@@ -141,14 +212,64 @@ static void rcm_init_msg(
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_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 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;
- rcm_msg_t *msg;
+ rcm1_msg_t *msg;
- msg = (rcm_msg_t *)buf;
+ msg = (rcm1_msg_t *)buf;
padding_len = rcm_get_pad_len(payload_len);
- msg->len_insecure = sizeof(rcm_msg_t) + payload_len +
+ msg->len_insecure = sizeof(rcm1_msg_t) + payload_len +
padding_len;
memset(&msg->cmac_hash, 0x0, sizeof(msg->cmac_hash));
@@ -157,20 +278,20 @@ static void rcm_init_msg(
msg->opcode = opcode;
msg->len_secure = msg->len_insecure;
msg->payload_len = payload_len;
- msg->rcm_version = RCM_VERSION;
+ 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(rcm_msg_t) + payload_len, padding_len);
+ 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 = sizeof(rcm_msg_t) + payload_len;
+ 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) {
@@ -184,7 +305,7 @@ static uint32_t rcm_get_pad_len(uint32_t payload_len)
* rcm_msg_t size handles the initial data that is not part of
* the hashing and encryption.
*/
- pad_len += 16 - ((msg_len - sizeof(rcm_msg_t)) & 0xf);
+ pad_len += 16 - ((msg_len - message_size) & 0xf);
return pad_len;
}
diff --git a/src/rcm.h b/src/rcm.h
index 868893e..1aeca9f 100644
--- a/src/rcm.h
+++ b/src/rcm.h
@@ -34,7 +34,8 @@
#define RCM_MIN_MSG_LENGTH 1024 // In bytes
#define NVBOOT_VERSION(a,b) ((((a)&0xffff) << 16) | ((b)&0xffff))
-#define RCM_VERSION (NVBOOT_VERSION(1, 0))
+#define RCM_VERSION_1 (NVBOOT_VERSION(1, 0))
+#define RCM_VERSION_35 (NVBOOT_VERSION(0x35, 1))
#define RCM_VERSION_MAJOR(ver) ((ver) >> 16)
#define RCM_VERSION_MINOR(ver) ((ver) & 0xffff)
@@ -66,13 +67,31 @@ typedef struct {
uint32_t rcm_version;
uint8_t args[48];
uint8_t padding[16];
-} rcm_msg_t;
+} rcm1_msg_t;
+
+typedef struct {
+ uint32_t len_insecure;
+ uint8_t modulus[2048 / 8];
+ union {
+ uint8_t cmac_hash[RCM_AES_BLOCK_SIZE];
+ uint8_t rsa_pss_sig[2048 / 8];
+ } object_sig;
+ uint8_t reserved[16];
+ uint32_t ecid[4];
+ uint32_t opcode;
+ uint32_t len_secure;
+ uint32_t payload_len;
+ uint32_t rcm_version;
+ uint8_t args[48];
+ uint8_t padding[16];
+} rcm35_msg_t;
// security operating modes
#define RCM_OP_MODE_PRE_PRODUCTION 0x1
#define RCM_OP_MODE_DEVEL 0x3
#define RCM_OP_MODE_ODM_OPEN 0x5
+int rcm_init(uint32_t version);
uint32_t rcm_get_msg_len(uint8_t *msg);
int rcm_create_msg(
uint32_t opcode,