diff --git a/rpifwcrypto/README.md b/rpifwcrypto/README.md index a6e6d52..3b31a8c 100644 --- a/rpifwcrypto/README.md +++ b/rpifwcrypto/README.md @@ -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) diff --git a/rpifwcrypto/main.c b/rpifwcrypto/main.c index b0888b6..942e36c 100644 --- a/rpifwcrypto/main.c +++ b/rpifwcrypto/main.c @@ -26,6 +26,10 @@ static void usage(const char *progname) "\n" " set-key-status [LOCKED] Sets the status attributes for the specified key.\n" "\n" + " get-key-usage Gets the usage of a specified key\n" + "\n" + " set-key-usage Sets the usage of a specified key\n" + "\n" " sign --in --key-id --alg [--out ] [--outform hex]\n" "\n" " Supported algorithms: ec\n" @@ -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) { + 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) diff --git a/rpifwcrypto/rpifwcrypto.c b/rpifwcrypto/rpifwcrypto.c index 9aac1b3..e78b53e 100644 --- a/rpifwcrypto/rpifwcrypto.c +++ b/rpifwcrypto/rpifwcrypto.c @@ -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 */ @@ -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) @@ -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; diff --git a/rpifwcrypto/rpifwcrypto.h b/rpifwcrypto/rpifwcrypto.h index 861ff35..f61aa9a 100644 --- a/rpifwcrypto/rpifwcrypto.h +++ b/rpifwcrypto/rpifwcrypto.h @@ -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 * @@ -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. *