Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rpifwcrypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Install prerequisites with "sudo apt install cmake libgnutls28-dev"" - you need
* rpi-fw-crypto sign --in message.bin --key-id 1 --alg ec --out sig.bin (Signs message.bin with the device unique OTP key (id 1))
* rpi-fw-crypto get-key-status 1 (Gets the status of key-id 1)
* rpi-fw-crypto set-key-status 1 LOCKED (Blocks the raw OTP read API on this key until the device is rebooted)
* rpi-fw-crypto get-key-usage 1 (Gets the usage of key-id 1)
* rpi-fw-crypto set-key-usage 1 0x1 (Sets the usage of key-id 1 to RPI_CONNECT in OTP)
* rpi-fw-crypto hmac --in message.bin --key-id 1 --out hmac.bin (Generates the SHA256 HMAC of message.bin and OTP key id 1)
* rpi-fw-crypto pubkey --key-id 1 --out device-pub.der (Derives and retrieves the corresponding public key for the specified device private ECDSA P256 key)
* rpi-fw-crypto privkey --key-id 1 --out device-priv.der (Retrieves the device private key - in DER form - will error if key status is locked)
Expand Down
36 changes: 36 additions & 0 deletions rpifwcrypto/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ static void usage(const char *progname)
"\n"
" set-key-status <key-id> [LOCKED] Sets the status attributes for the specified key.\n"
"\n"
" get-key-usage <key-id> Gets the usage of a specified key\n"
"\n"
" set-key-usage <key-id> <usage> Sets the usage of a specified key\n"
"\n"
" sign --in <infile> --key-id <id> --alg <alg> [--out <outfile>] [--outform hex]\n"
"\n"
" Supported algorithms: ec\n"
Expand Down Expand Up @@ -474,6 +478,38 @@ int main(int argc, char *argv[])
return 0;
}

if (strcmp(argv[1], "get-key-usage") == 0) {
if (argc != 3)
usage(argv[0]);
key_id = atoi(argv[2]);
RPI_FW_CRYPTO_KEY_USAGE key_usage;
rc = rpi_fw_crypto_get_key_usage(key_id, &key_usage);
if (rc < 0)
goto error;
printf("Key %u usage: 0x%02x (%s)\n", key_id, (unsigned)key_usage, rpi_fw_crypto_key_usage_str(key_usage));
return 0;
}

if (strcmp(argv[1], "set-key-usage") == 0) {
if (argc != 4)
usage(argv[0]);
key_id = atoi(argv[2]);
unsigned long key_usage_raw = strtoul(argv[3], NULL, 0);
if (key_usage_raw > RPI_FW_CRYPTO_KEY_USAGE_INVALID) {
Comment thread
pelwell marked this conversation as resolved.
fprintf(stderr, "Invalid key usage 0x%lx: must be in range 0x0..0x%x\n",
key_usage_raw, RPI_FW_CRYPTO_KEY_USAGE_INVALID);
return -1;
}
RPI_FW_CRYPTO_KEY_USAGE key_usage = (RPI_FW_CRYPTO_KEY_USAGE)key_usage_raw;
rc = rpi_fw_crypto_set_key_usage(key_id, key_usage);
if (rc < 0) {
fprintf(stderr, "Failed to set key usage: %s\n", rpi_fw_crypto_strerror(rc));
goto error;
}
printf("Set key %u usage to 0x%02x (%s)\n", key_id, (unsigned)key_usage, rpi_fw_crypto_key_usage_str(key_usage));
return 0;
}

if (strcmp(argv[1], "sign") == 0) {
rc = cmd_sign(argc, argv);
if (rc < 0)
Expand Down
85 changes: 85 additions & 0 deletions rpifwcrypto/rpifwcrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ typedef enum {
TAG_GET_CRYPTO_PUBLIC_KEY = 0x00030093, // Get public key
TAG_GET_CRYPTO_PRIVATE_KEY = 0x00030094, // Get private key
TAG_GET_CRYPTO_GEN_ECDSA_KEY = 0x00030095, // Generate ECDSA key
TAG_GET_CRYPTO_KEY_USAGE = 0x0003009c, // Get key usage
TAG_SET_CRYPTO_KEY_USAGE = 0x0003809c, // Set key usage
} RPI_FW_CRYPTO_TAG;

/* Common header structure for firmware mailbox messages */
Expand Down Expand Up @@ -309,6 +311,35 @@ const char *rpi_fw_crypto_key_status_str(uint32_t key_status)
return buf;
}

const char *rpi_fw_crypto_key_usage_str(RPI_FW_CRYPTO_KEY_USAGE key_usage)
{
switch (key_usage) {
case RPI_FW_CRYPTO_KEY_USAGE_UNDEFINED:
return "UNDEFINED";
case RPI_FW_CRYPTO_KEY_USAGE_RPI_CONNECT:
return "RPI_CONNECT";
case RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_0:
case RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_1:
case RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_2:
case RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_3:
case RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_4:
case RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_5:
return "RPI_RESERVED";
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_0:
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_1:
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_2:
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_3:
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_4:
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_5:
case RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_6:
return "USER_DEFINED";
case RPI_FW_CRYPTO_KEY_USAGE_INVALID:
return "INVALID";
default:
return "UNKNOWN";
}
}

// Implementation of ECDSA sign via firmware mailbox
int rpi_fw_crypto_ecdsa_sign(uint32_t flags, uint32_t key_id, const uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_max_len, size_t *sig_len)
Expand Down Expand Up @@ -406,6 +437,60 @@ int rpi_fw_crypto_set_key_status(uint32_t key_id, uint32_t status)
return (rc < 0) ? rc : RPI_FW_CRYPTO_SUCCESS;
}

int rpi_fw_crypto_get_key_usage(uint32_t key_id, RPI_FW_CRYPTO_KEY_USAGE *usage)
{
int mb;
int rc;
struct firmware_msg msg = {0};

if (!usage)
return -RPI_FW_CRYPTO_EINVAL;

mb = mbox_open();
if (mb < 0)
return -RPI_FW_CRYPTO_ERROR_UNKNOWN;

msg.hdr.buf_size = sizeof(msg);
msg.hdr.tag = TAG_GET_CRYPTO_KEY_USAGE;
msg.hdr.tag_buf_size = 4;
msg.value[0] = key_id;

rc = mbox_property(mb, &msg);
mbox_close(mb);

if (rc < 0)
return rc;

if (msg.value[0] & VC_MAILBOX_ERROR)
return -RPI_FW_CRYPTO_KEY_NOT_FOUND;

*usage = (RPI_FW_CRYPTO_KEY_USAGE)msg.value[0];
return RPI_FW_CRYPTO_SUCCESS;
}

int rpi_fw_crypto_set_key_usage(uint32_t key_id, RPI_FW_CRYPTO_KEY_USAGE usage)
{
int mb;
int rc;
struct firmware_msg msg = {0};

mb = mbox_open();
if (mb < 0)
return -RPI_FW_CRYPTO_ERROR_UNKNOWN;

msg.hdr.buf_size = sizeof(msg);
msg.hdr.tag = TAG_SET_CRYPTO_KEY_USAGE;
msg.hdr.tag_buf_size = 8;
msg.value[0] = key_id;
msg.value[1] = (uint32_t)usage;
msg.end_tag = 0;

rc = mbox_property(mb, &msg);
mbox_close(mb);

return (rc < 0) ? rc : RPI_FW_CRYPTO_SUCCESS;
}

int rpi_fw_crypto_get_pubkey(uint32_t flags, uint32_t key_id, uint8_t *pubkey, size_t pubkey_max_len, size_t *pubkey_len)
{
int mb;
Expand Down
45 changes: 45 additions & 0 deletions rpifwcrypto/rpifwcrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ typedef enum {
RPI_FW_CRYPTO_KEY_NOT_BLANK = 10, // Key slot is not blank
} RPI_FW_CRYPTO_STATUS;

typedef enum {
RPI_FW_CRYPTO_KEY_USAGE_UNDEFINED = 0x0,
RPI_FW_CRYPTO_KEY_USAGE_RPI_CONNECT = 0x1,
RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_0 = 0x2,
RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_1 = 0x3,
RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_2 = 0x4,
RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_3 = 0x5,
RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_4 = 0x6,
RPI_FW_CRYPTO_KEY_USAGE_RPI_RESERVED_5 = 0x7,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_0 = 0x8,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_1 = 0x9,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_2 = 0xA,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_3 = 0xB,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_4 = 0xC,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_5 = 0xD,
RPI_FW_CRYPTO_KEY_USAGE_USER_DEFINED_6 = 0xE,
RPI_FW_CRYPTO_KEY_USAGE_INVALID = 0xF,
} RPI_FW_CRYPTO_KEY_USAGE;

/**
* Get the number of OTP keys available in firmware
*
Expand Down Expand Up @@ -128,6 +147,32 @@ int rpi_fw_crypto_get_private_key(uint32_t flags, uint32_t key_id, uint8_t *priv
*/
const char *rpi_fw_crypto_key_status_str(uint32_t key_status);

/**
* Get the usage of a specific OTP key
*
* @param key_id The ID of the key to query
* @param usage Pointer to store the key usage (RPI_FW_CRYPTO_KEY_USAGE value)
* @return 0 on success, negative error code on failure
*/
int rpi_fw_crypto_get_key_usage(uint32_t key_id, RPI_FW_CRYPTO_KEY_USAGE *usage);

/**
* Set the usage of a specific OTP key
*
* @param key_id The ID of the key to set
* @param usage The new key usage value (RPI_FW_CRYPTO_KEY_USAGE value)
* @return 0 on success, negative error code on failure
*/
int rpi_fw_crypto_set_key_usage(uint32_t key_id, RPI_FW_CRYPTO_KEY_USAGE usage);

/**
* Convert a key usage value to a human-readable string
*
* @param key_usage The key usage value (RPI_FW_CRYPTO_KEY_USAGE value)
* @return A constant string describing the key usage
*/
const char *rpi_fw_crypto_key_usage_str(RPI_FW_CRYPTO_KEY_USAGE key_usage);

/**
* Generates an ECDSA in the specified key slot.
*
Expand Down