Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

She extension update #27

Merged
merged 20 commits into from
May 21, 2024
Merged

She extension update #27

merged 20 commits into from
May 21, 2024

Conversation

jpbland1
Copy link
Contributor

@jpbland1 jpbland1 commented May 2, 2024

added she functions, tested working with test vectors and the custom uid. decided to use the normal nvm functions to set she keys as it is simple. I think this should be the default way of programming the master ecu key, secret key etc. currently doesn't use the crypto struct for aes and cmac because those PRs are not merged yet. missing the load plain key command and test for export ram key, the load plain key command from my first draft needs to be re written due to how the new keyId system works.

jpbland1 added 2 commits May 2, 2024 03:38
load key and rnd functions with test vectors.
@jpbland1 jpbland1 requested review from billphipps and bigbrett and removed request for billphipps May 2, 2024 07:50
@jpbland1 jpbland1 self-assigned this May 2, 2024
@jpbland1 jpbland1 requested a review from billphipps May 2, 2024 07:50
@jpbland1
Copy link
Contributor Author

jpbland1 commented May 2, 2024

the asan test is failing due to a stack-buffer-overflow in the nvm code. I changed the metadata len to 36 after I added the count parameter which is a uint32_t, 4 bytes. does something else need to be updated when that const changes that I'm not aware of?

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it looks great, though I haven't dug into the SHE spec to verify adherence. A few nits, including adding a few more negative tests to ensure things fail when they should fail. But yeah, first pass LGTM

src/wh_server_she.c Outdated Show resolved Hide resolved
test/wh_test_she.c Outdated Show resolved Hide resolved
test/wh_test_she.c Outdated Show resolved Hide resolved
goto exit;
}
/* verify bootloader */
if ((ret = wh_Client_SheSecureBoot(client, bootloader, bootloaderSz)) != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a negative test to know that the validation works and wont validate everything?

test/wh_test_she.c Outdated Show resolved Hide resolved
jpbland1 added 2 commits May 3, 2024 06:10
setting the manufacturers keys, test export ram key, fix commited key check
@jpbland1 jpbland1 requested a review from bigbrett May 3, 2024 10:29
src/wh_client_she.c Show resolved Hide resolved
int ret;
uint8_t* packIn;
whPacket* packet;
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to check that it is a multiple of the block/key size here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think there are cases here where we need to validate the size. The size the user passes is directly passed to memcpy without any upper bound checking, so while it might be considered abuse of the function, it is still a potential buffer overflow. Yes it is on the client side and so not any real security implications, but still, I don't think we should allow the client to overflow a buffer in one of our public APIs if we can avoid it. We should look at all the size arguments passed to these APIs and ensure they aren't used directly without validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not how it's done in any of our crypto for aes, the ecb encrypt and decrypt functions don't even check minimum length:

        for (i = 0; i < sz; i += AES_BLOCK_SIZE) {
            ret = wc_AesEncryptDirect(aes, out, in);
            if (ret != 0)
                break;
            in += AES_BLOCK_SIZE;
            out += AES_BLOCK_SIZE;
        }

when the data is longer than the packet buffer, assuming we're not using shared memory, we'll need a different scheme that lets the client send multiple packets for a single command, and that's not in the scope of this change

Comment on lines +516 to +525
int wh_Client_SheEncEcbResponse(whClientContext* c, uint8_t* out, uint32_t sz)
{
int ret;
uint16_t group;
uint16_t action;
uint16_t dataSz;
uint8_t* packOut;
whPacket* packet;
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
return WH_ERROR_BADARGS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above re: size checking against WOLFHSM_SHE_KEY_SZ

if (ret == 0) {
if (packet->rc != WOLFHSM_SHE_ERC_NO_ERROR)
ret = packet->rc;
else if (sz < packet->sheEncEcbRes.sz)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

equality check? If we are copying out fewer bytes than expected to the user (e.g. if sz > packet->sheEncEcbRes.sz) then we need to indicate that via output argument. But this is probably an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just based it on how we do aes in wolfCrypt, see https://www.wolfssl.com/doxygen/group__AES.html#gaed1e38cd30d917165183fc68dd4b218b, usually the same buffer is used and overwritten for the output anyways.

int ret;
uint8_t* packIn;
whPacket* packet;
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || iv == NULL ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above re: size checking against WOLFHSM_SHE_KEY_SZ

uint16_t dataSz;
uint8_t* packOut;
whPacket* packet;
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above re: size checking against WOLFHSM_SHE_KEY_SZ

src/wh_server_she.c Outdated Show resolved Hide resolved
@jpbland1 jpbland1 requested a review from bigbrett May 13, 2024 16:42
Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As always, would like to see some more expanded testing for these features. At least once negative test case would be good to ensure things fail when we need them to fail. Would go a long way towards being more confident that further code modifications don't introduce regerssions

src/wh_she_common.c Show resolved Hide resolved
@@ -108,6 +108,7 @@ ifeq ($(SHE),1)
SRC_C += \
$(WOLFHSM_DIR)/src/wh_client_she.c \
$(WOLFHSM_DIR)/src/wh_server_she.c \
$(WOLFHSM_DIR)/src/wh_she_common.c \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trailing slash, while okay now, might lead to a cryptic Make error later on

src/wh_she_common.c Show resolved Hide resolved
Comment on lines 84 to 85
uint8_t bootloader[512];
uint8_t keyAndDigest[32] = {0};
uint8_t bootMacDigest[16] = {0};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have macros for these array sizes?

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, prior approval was premature - only blocker is removing arpa/inet.h. Can't merge that in

@jpbland1 jpbland1 requested a review from bigbrett May 15, 2024 20:38
bigbrett
bigbrett previously approved these changes May 17, 2024
Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good on my end. @billphipps please review

Copy link
Contributor

@billphipps billphipps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. A few things we need to get correct, but I'll merge it now if you want to.

  1. AES CBC and CMAC sizes larger than a single block must be supported. recommend to use DMA for these and simply pass a pointer when available. Otherwise, add a client-side loop to perform the iterative process.
  2. Collect SHE state into a single struct and associate that with a server context. The same state can be used by multiple contexts, or not. It's not necessarily global.
  3. Separate SHE stuff into different files/headers to minimize logic spread into common functions. SHE should appear to be an add-on or helper to use the base HSM library. I expect to code up the PKCS11 as a layer on top, hopefully with no internal logic aside from ID segregation.

A few nits and questions throughout. I still don't see a consistent whKeyId vs whNvmId use yet, but we'll get there. Excellent job on the test code! We may want to have a fixed known answer test in there before you generate everything randomly.

Comment on lines +157 to +161
#define WOLFHSM_SHE_M1_SZ 16
#define WOLFHSM_SHE_M2_SZ 32
#define WOLFHSM_SHE_M3_SZ WOLFHSM_SHE_M1_SZ
#define WOLFHSM_SHE_M4_SZ WOLFHSM_SHE_M2_SZ
#define WOLFHSM_SHE_M5_SZ WOLFHSM_SHE_M1_SZ
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated above.

wolfhsm/wh_common.h Outdated Show resolved Hide resolved
Comment on lines +161 to +164
int wh_SheGenerateLoadableKey(uint8_t keyId,
uint8_t authKeyId, uint32_t count, uint32_t flags, uint8_t* uid,
uint8_t* key, uint8_t* authKey, uint8_t* messageOne, uint8_t* messageTwo,
uint8_t* messageThree, uint8_t* messageFour, uint8_t* messageFive);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary in common? Recommend to move all of the SHE defines to wh_she.h so that we can keep the common files clean. Not urgent.

Comment on lines +57 to +76
/* SHE actions */
enum {
WH_SHE_SET_UID,
WH_SHE_SECURE_BOOT_INIT,
WH_SHE_SECURE_BOOT_UPDATE,
WH_SHE_SECURE_BOOT_FINISH,
WH_SHE_GET_STATUS,
WH_SHE_LOAD_KEY,
WH_SHE_LOAD_PLAIN_KEY,
WH_SHE_EXPORT_RAM_KEY,
WH_SHE_INIT_RND,
WH_SHE_RND,
WH_SHE_EXTEND_SEED,
WH_SHE_ENC_ECB,
WH_SHE_ENC_CBC,
WH_SHE_DEC_ECB,
WH_SHE_DEC_CBC,
WH_SHE_GEN_MAC,
WH_SHE_VERIFY_MAC,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these to wh_message_she.h so they can be shared with the server. Recommend to update naming to WH_MESSAGE_SHE_ACTION_xxx so it's clear these are message actions. Consider replacing the WOLFHSM_SHE_SUBTYPE with these as they appear to be a one-to-one match.

Comment on lines 23 to 33
enum WOLFHSM_SHE_SUBTYPE {
WOLFHSM_SHE_SECURE_BOOT_INIT,
WOLFHSM_SHE_SECURE_BOOT_UPDATE,
WOLFHSM_SHE_SECURE_BOOT_FINISH,
WOLFHSM_SHE_GET_STATUS,
WOLFHSM_SHE_LOAD_KEY,
WOLFHSM_SHE_EXPORT_RAM_KEY,
WOLFHSM_SHE_INIT_RNG,
WOLFHSM_SHE_RND,
WOLFHSM_SHE_EXTEND_SEED,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be replaced by the ACTION enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes these are redundant/wrong

Comment on lines 60 to 70
static uint8_t hsmShePrngState[WOLFHSM_SHE_KEY_SZ];
static uint8_t hsmSheSbState = WOLFHSM_SHE_SB_INIT;
static uint8_t hsmSheCmacKeyFound = 0;
static uint8_t hsmSheRamKeyPlain = 0;
static uint8_t hsmSheUidSet = 0;
static uint32_t hsmSheBlSize = 0;
static uint32_t hsmSheBlSizeReceived = 0;
static uint32_t hsmSheRndInited = 0;
/* cmac is global since the bootloader update can be called multiple times */
Cmac sheCmac[1];
Aes sheAes[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collect all required she server state into a single struct that is allocated/provided at the same time as the server. Note that this state is per server instance and NOT global, but the server configs could use the same SHE instance to provide the same state, if desired.

#include "wolfhsm/wh_packet.h"
#include "wolfhsm/wh_error.h"
#ifdef WOLFHSM_SHE_EXTENSION
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this entire file be protected with this macro?

if (server == NULL || (keyId & WOLFHSM_KEYID_MASK) == WOLFHSM_KEYID_ERASED
|| outSz == NULL) {
if (server == NULL || ((keyId & WOLFHSM_KEYID_MASK) == WOLFHSM_KEYID_ERASED
&& (keyId & WOLFHSM_KEYTYPE_MASK) != WOLFHSM_KEYTYPE_SHE) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be protected by the compile time ifdef for she_extension?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, the she keyId stuff is not compile guarded since it's reserved in case they update to use she key later but still want the same keystore

Comment on lines 245 to 260
#ifdef WOLFHSM_SHE_EXTENSION
/* use empty string if we couldn't find the master ecu key */
if (ret != 0 && keyId == WOLFHSM_SHE_MASTER_ECU_KEY_ID) {
/* use empty key of zeros if we couldn't find the master ecu key */
if (ret == WH_ERROR_NOTFOUND &&
(keyId & WOLFHSM_KEYTYPE_MASK) == WOLFHSM_KEYTYPE_SHE &&
(keyId & WOLFHSM_KEYID_MASK) == WOLFHSM_SHE_MASTER_ECU_KEY_ID) {
XMEMSET(out, 0, WOLFHSM_SHE_KEY_SZ);
meta->len = WOLFHSM_SHE_KEY_SZ;
meta->id = searchId;
*outSz = WOLFHSM_SHE_KEY_SZ;
if (outMeta != NULL) {
/* need empty flags and corect lenth and id */
XMEMSET(outMeta, 0, sizeof(meta));
meta->len = WOLFHSM_SHE_KEY_SZ;
meta->id = keyId;
}
ret = 0;
}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be handled in the SHE version of read key and not in the generic one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiple places can read the unset ecu key, they don't call their own she read function they make a she keyId and then call the normal read function, putting it here means no duplicated code

src/wh_client_she.c Show resolved Hide resolved
@jpbland1 jpbland1 requested review from billphipps and bigbrett May 21, 2024 04:50
@jpbland1
Copy link
Contributor Author

Adressed most of bills comments, reorganized the structs and changed the way the "non-loadable" she keys are loaded into the hsm

billphipps
billphipps previously approved these changes May 21, 2024
Copy link
Contributor

@billphipps billphipps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions to handle overrunning the packet size. Looks good enough for now.

sizeof(packet->sheExtendSeedReq.entropy));
/* send init rng req */
ret = wh_Client_SendRequest(c, WH_MESSAGE_GROUP_SHE, WH_SHE_EXTEND_SEED,
WOLFHSM_PACKET_STUB_SIZE, (uint8_t*)packet);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
WOLFHSM_PACKET_STUB_SIZE, (uint8_t*)packet);
WOLFHSM_PACKET_STUB_SIZE + sizeof(packet->sheExtendSeedReq), (uint8_t*)packet);

int ret;
uint8_t* packIn;
whPacket* packet;
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better error out if it can't be placed in a single packet.

Suggested change
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ)
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheEncEcbReq))

uint16_t dataSz;
uint8_t* packOut;
whPacket* packet;
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ|| sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheEncEcbRes))

int ret;
uint8_t* packIn;
whPacket* packet;
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || iv == NULL ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || iv == NULL ||
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheEncCbcReq || iv == NULL ||

uint16_t dataSz;
uint8_t* packOut;
whPacket* packet;
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheEncCbcRes))

int ret;
uint8_t* packIn;
whPacket* packet;
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ)
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheDecEcbReq))

uint16_t dataSz;
uint8_t* packOut;
whPacket* packet;
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheDecEcbRes))

src/wh_client_she.c Show resolved Hide resolved
int ret;
uint8_t* packIn;
whPacket* packet;
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || iv == NULL ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || iv == NULL ||
if (c == NULL || in == NULL || sz < WOLFHSM_SHE_KEY_SZ || || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheDecCbcReq) || iv == NULL ||

uint16_t dataSz;
uint8_t* packOut;
whPacket* packet;
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ)
if (c == NULL || out == NULL || sz < WOLFHSM_SHE_KEY_SZ || sz > (WH_COMM_DATA_LEN - WOLFHSM_PACKET_STUB_SIZE - sizeof(packet->sheDecCbcRes))

Copy link
Contributor

@billphipps billphipps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor fixes for next pr

@billphipps billphipps merged commit cc1527e into wolfSSL:main May 21, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants