|
35 | 35 |
|
36 | 36 | #ifdef WOLFHSM_CFG_KEYWRAP |
37 | 37 |
|
| 38 | +#define WH_TEST_KEKID 1 |
| 39 | +static int _InitServerKek(whClientContext* ctx) |
| 40 | +{ |
| 41 | + /* IMPORTANT NOTE: Server KEK is typically intrinsic or set during |
| 42 | + * provisioning. Uploading the KEK via the client is for testing purposes |
| 43 | + * only and not intended as a recommendation */ |
| 44 | + whKeyId serverKeyId = WH_TEST_KEKID; |
| 45 | + whNvmFlags flags = WH_NVM_FLAGS_NONEXPORTABLE; |
| 46 | + uint8_t label[WH_NVM_LABEL_LEN] = "Server KEK key"; |
| 47 | + uint8_t kek[] = {0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e, |
| 48 | + 0x06, 0x6e, 0x19, 0xce, 0x98, 0x44, 0x54, 0x0d, |
| 49 | + 0x78, 0xa0, 0xbe, 0xe7, 0x35, 0x43, 0x40, 0xa4, |
| 50 | + 0x22, 0x8a, 0xd1, 0x0e, 0xa3, 0x63, 0x1c, 0x0b}; |
| 51 | + |
| 52 | + return wh_Client_KeyCache(ctx, flags, label, sizeof(label), kek, |
| 53 | + sizeof(kek), &serverKeyId); |
| 54 | +} |
| 55 | + |
| 56 | +static int _CleanupServerKek(whClientContext* ctx) |
| 57 | +{ |
| 58 | + return wh_Client_KeyErase(ctx, WH_TEST_KEKID); |
| 59 | +} |
| 60 | + |
38 | 61 | #ifndef NO_AES |
39 | 62 | #ifdef HAVE_AESGCM |
40 | 63 |
|
|
45 | 68 | #define WH_TEST_AES_WRAPPED_KEYSIZE \ |
46 | 69 | (WH_TEST_AES_IVSIZE + WH_TEST_AES_TAGSIZE + WH_TEST_AES_KEYSIZE + \ |
47 | 70 | sizeof(whNvmMetadata)) |
48 | | -#define WH_TEST_WRAPKEY_ID 8 |
| 71 | +#define WH_TEST_AESGCM_WRAPKEY_ID 8 |
49 | 72 |
|
50 | | -int wh_DemoClient_AesGcmKeyWrapBasic(whClientContext* ctx, WC_RNG* rng) |
| 73 | +int wh_DemoClient_AesGcmKeyWrap(whClientContext* client) |
51 | 74 | { |
52 | 75 | int ret = 0; |
53 | | - uint8_t kek[WH_TEST_AES_KEYSIZE]; |
54 | | - uint8_t clientKey[WH_TEST_AES_KEYSIZE]; |
55 | | - uint8_t tmpClientKey[WH_TEST_AES_KEYSIZE]; |
| 76 | + Aes aes[1]; |
| 77 | + WC_RNG rng[1]; |
| 78 | + uint8_t key[WH_TEST_AES_KEYSIZE]; |
| 79 | + uint8_t exportedKey[WH_TEST_AES_KEYSIZE]; |
| 80 | + whNvmMetadata metadata = { |
| 81 | + .id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, 0, WH_TEST_AESGCM_WRAPKEY_ID), |
| 82 | + .label = "AES Key Label", |
| 83 | + .access = WH_NVM_ACCESS_ANY, |
| 84 | + .len = WH_TEST_AES_KEYSIZE}; |
| 85 | + whNvmMetadata exportedMetadata; |
56 | 86 | uint8_t wrappedKey[WH_TEST_AES_WRAPPED_KEYSIZE]; |
57 | | - uint8_t label[WH_NVM_LABEL_LEN] = "Server AES Key Label"; |
58 | | - whKeyId serverKeyId; |
59 | 87 | whKeyId wrappedKeyId; |
60 | | - whNvmMetadata metadata = {.id = WH_TEST_WRAPKEY_ID, |
61 | | - .label = "AES Key Label", |
62 | | - .access = WH_NVM_ACCESS_ANY, |
63 | | - .len = WH_TEST_AES_KEYSIZE}; |
64 | | - whNvmMetadata tmpMetadata; |
65 | | - |
66 | | - /* Generate a random KEK to encrypt the client key */ |
67 | | - ret = wc_RNG_GenerateBlock(rng, kek, sizeof(kek)); |
68 | | - if (ret != 0) { |
69 | | - printf("Failed to wc_RNG_GenerateBlock for key %d\n", ret); |
| 88 | + |
| 89 | + const uint8_t plaintext[] = "hello, wolfSSL AES-GCM!"; |
| 90 | + uint8_t ciphertext[sizeof(plaintext)]; |
| 91 | + uint8_t decrypted[sizeof(plaintext)]; |
| 92 | + |
| 93 | + uint8_t tag[WH_TEST_AES_TAGSIZE]; |
| 94 | + uint8_t iv[WH_TEST_AES_IVSIZE]; |
| 95 | + const uint8_t aad[] = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, |
| 96 | + 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, |
| 97 | + 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2}; |
| 98 | + |
| 99 | + /* Initialize the server KEK */ |
| 100 | + |
| 101 | + /* The key wrap feature requires the server to have a Key Encryption Key |
| 102 | + * (I.E. KEK) available for the client to use. In the case of this demo we |
| 103 | + * have the client initializing the KEK which is not recommended. Typically |
| 104 | + * the KEK ID would be a hard coded value that the client and server share |
| 105 | + * and the KEK would be provisioned on the server prior to runtime */ |
| 106 | + ret = _InitServerKek(client); |
| 107 | + if (ret != WH_ERROR_OK) { |
| 108 | + printf("Failed to _InitServerKek %d\n", ret); |
70 | 109 | return ret; |
71 | 110 | } |
72 | 111 |
|
73 | | - /* Generate a random client key */ |
74 | | - ret = wc_RNG_GenerateBlock(rng, clientKey, sizeof(clientKey)); |
| 112 | + /* Generating and wrapping a key */ |
| 113 | + |
| 114 | + /* Initialize the RNG so we can generate an AES GCM key to wrap */ |
| 115 | + ret = wc_InitRng_ex(rng, NULL, WH_DEV_ID); |
75 | 116 | if (ret != 0) { |
76 | | - printf("Failed to wc_RNG_GenerateBlock for key data %d\n", ret); |
77 | | - return ret; |
| 117 | + printf("Failed to wc_InitRng_ex %d\n", ret); |
| 118 | + goto cleanup_kek; |
78 | 119 | } |
79 | 120 |
|
80 | | - /* Request the server to cache the KEK and give us back a key ID*/ |
81 | | - ret = wh_Client_KeyCache(ctx, 0, label, sizeof(label), kek, sizeof(kek), |
82 | | - &serverKeyId); |
| 121 | + /* Now we generate the AES GCM key using the RNG */ |
| 122 | + ret = wc_RNG_GenerateBlock(rng, key, sizeof(key)); |
83 | 123 | if (ret != 0) { |
84 | | - printf("Failed to wh_Client_KeyCache %d\n", ret); |
85 | | - return ret; |
| 124 | + printf("Failed to wc_RNG_GenerateBlock for key data %d\n", ret); |
| 125 | + goto cleanup_rng; |
86 | 126 | } |
87 | 127 |
|
88 | | - /* Request the server to wrap the client key using the KEK we just cached */ |
89 | | - ret = wh_Client_KeyWrap(ctx, WC_CIPHER_AES_GCM, serverKeyId, clientKey, |
90 | | - sizeof(clientKey), &metadata, wrappedKey, |
| 128 | + /* Now we request the server to wrap the key using the KEK we |
| 129 | + * establish above in the first step. */ |
| 130 | + ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, key, |
| 131 | + sizeof(key), &metadata, wrappedKey, |
91 | 132 | sizeof(wrappedKey)); |
92 | 133 | if (ret != 0) { |
93 | 134 | printf("Failed to wh_Client_KeyWrap %d\n", ret); |
94 | | - return ret; |
| 135 | + goto cleanup_rng; |
95 | 136 | } |
96 | 137 |
|
97 | | - /* Request the server to unwrap and cache the wrapped key we just created */ |
98 | | - ret = wh_Client_KeyUnwrapAndCache(ctx, WC_CIPHER_AES_GCM, serverKeyId, |
| 138 | + /* Now that the key is wrapped you store this in Non-Volatile Memory however |
| 139 | + * you wish */ |
| 140 | + |
| 141 | + |
| 142 | + /* Using a wrapped key to do crypto operations*/ |
| 143 | + |
| 144 | + /* Request the server to unwrap and cache the wrapped key we just created. |
| 145 | + * This will provide us back a key ID that the client can use to do crypto |
| 146 | + * operations */ |
| 147 | + ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, |
99 | 148 | wrappedKey, sizeof(wrappedKey), |
100 | 149 | &wrappedKeyId); |
101 | 150 | if (ret != 0) { |
102 | 151 | printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret); |
103 | | - return ret; |
| 152 | + goto cleanup_rng; |
| 153 | + } |
| 154 | + |
| 155 | + /* Initialize AES context */ |
| 156 | + ret = wc_AesInit(aes, NULL, WH_DEV_ID); |
| 157 | + if (ret != 0) { |
| 158 | + printf("Failed to wc_AesInit %d\n", ret); |
| 159 | + goto cleanup_cached_key; |
| 160 | + } |
| 161 | + |
| 162 | + /* Set the key id for this AES context to the wrapped key ID that the server |
| 163 | + * provided us */ |
| 164 | + ret = wh_Client_AesSetKeyId(aes, wrappedKeyId); |
| 165 | + if (ret != 0) { |
| 166 | + printf("Failed to wh_Client_AesSetKeyId %d\n", ret); |
| 167 | + goto cleanup_aes; |
| 168 | + } |
| 169 | + |
| 170 | + /* Generate a random IV for the AES GCM encryption operation we are about to |
| 171 | + * do */ |
| 172 | + ret = wc_RNG_GenerateBlock(rng, iv, sizeof(iv)); |
| 173 | + if (ret != 0) { |
| 174 | + printf("Failed to wc_RNG_GenerateBlock for AES-GCM key %d\n", ret); |
| 175 | + goto cleanup_aes; |
104 | 176 | } |
105 | 177 |
|
| 178 | + /* Request the server to encrypt some data using the |
| 179 | + * unwrapped and cached key via the key ID */ |
| 180 | + ret = wc_AesGcmEncrypt(aes, ciphertext, plaintext, sizeof(plaintext), iv, |
| 181 | + sizeof(iv), tag, sizeof(tag), aad, sizeof(aad)); |
| 182 | + if (ret != 0) { |
| 183 | + printf("Failed to wc_AesGcmEncrypt %d\n", ret); |
| 184 | + goto cleanup_aes; |
| 185 | + } |
| 186 | + |
| 187 | + /* Request the server to decrypt the encrypted data using the |
| 188 | + * unwrapped and cached key via the key ID */ |
| 189 | + ret = wc_AesGcmDecrypt(aes, decrypted, /* out */ |
| 190 | + ciphertext, sizeof(ciphertext), /* in, inLen */ |
| 191 | + iv, sizeof(iv), /* iv, ivLen */ |
| 192 | + tag, sizeof(tag), /* authTag, authTagSz */ |
| 193 | + aad, sizeof(aad)); /* authIn (AAD), authInSz */ |
| 194 | + if (ret != 0) { |
| 195 | + ret = WH_ERROR_ABORTED; |
| 196 | + printf("Failed to wc_AesGcmDecrypt %d\n", ret); |
| 197 | + goto cleanup_aes; |
| 198 | + } |
| 199 | + |
| 200 | + /* Check if the decrypted data matches an expected value */ |
| 201 | + if (memcmp(decrypted, plaintext, sizeof(decrypted)) != 0) { |
| 202 | + ret = WH_ERROR_ABORTED; |
| 203 | + printf("Decrypted value does not match expected value\n"); |
| 204 | + goto cleanup_aes; |
| 205 | + } |
| 206 | + |
| 207 | + /* Exporting a wrapped key */ |
| 208 | + |
106 | 209 | /* Request the server to unwrap and export the wrapped key we created */ |
107 | | - ret = wh_Client_KeyUnwrapAndExport( |
108 | | - ctx, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, sizeof(wrappedKey), |
109 | | - &tmpMetadata, tmpClientKey, sizeof(tmpClientKey)); |
| 210 | + ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, |
| 211 | + wrappedKey, sizeof(wrappedKey), |
| 212 | + &exportedMetadata, exportedKey, |
| 213 | + sizeof(exportedKey)); |
110 | 214 | if (ret != 0) { |
111 | 215 | printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret); |
112 | | - return ret; |
| 216 | + goto cleanup_aes; |
113 | 217 | } |
114 | 218 |
|
115 | | - |
116 | 219 | /* Compare the exported key to the client key we requested to wrap */ |
117 | | - if (memcmp(clientKey, tmpClientKey, sizeof(clientKey)) != 0) { |
| 220 | + if (memcmp(key, exportedKey, sizeof(key)) != 0) { |
| 221 | + ret = WH_ERROR_ABORTED; |
118 | 222 | printf("AES GCM wrap/unwrap key failed to match\n"); |
119 | | - return ret; |
| 223 | + goto cleanup_aes; |
120 | 224 | } |
121 | 225 |
|
122 | 226 | /* Compare the exported metadata to the metadata we requested to wrap */ |
123 | | - if (memcmp(&metadata, &tmpMetadata, sizeof(metadata)) != 0) { |
| 227 | + if (memcmp(&metadata, &exportedMetadata, sizeof(metadata)) != 0) { |
| 228 | + ret = WH_ERROR_ABORTED; |
124 | 229 | printf("AES GCM wrap/unwrap metadata failed to match\n"); |
125 | | - return ret; |
| 230 | + goto cleanup_aes; |
126 | 231 | } |
127 | 232 |
|
| 233 | +cleanup_aes: |
| 234 | + wc_AesFree(aes); |
| 235 | +cleanup_cached_key: |
| 236 | + wh_Client_KeyErase(client, wrappedKeyId); |
| 237 | +cleanup_rng: |
| 238 | + wc_FreeRng(rng); |
| 239 | +cleanup_kek: |
| 240 | + _CleanupServerKek(client); |
| 241 | + |
128 | 242 | return ret; |
129 | 243 | } |
130 | 244 |
|
131 | 245 | #endif /* HAVE_AESGCM */ |
132 | 246 |
|
133 | | -int wh_DemoClient_AesKeyWrapBasic(whClientContext* clientContext, WC_RNG* rng) |
134 | | -{ |
135 | | - int ret = WH_ERROR_OK; |
136 | | - |
137 | | -#ifdef HAVE_AESGCM |
138 | | - ret = wh_DemoClient_AesGcmKeyWrapBasic(clientContext, rng); |
139 | | -#endif |
140 | | - |
141 | | - return ret; |
142 | | -} |
143 | 247 |
|
144 | 248 | #endif /* !NO_AES */ |
145 | | -int wh_DemoClient_KeyWrapBasic(whClientContext* clientContext) |
| 249 | + |
| 250 | +int wh_DemoClient_KeyWrap(whClientContext* client) |
146 | 251 | { |
147 | 252 |
|
148 | | - int ret; |
149 | | - WC_RNG rng[1]; |
| 253 | + int ret; |
150 | 254 |
|
151 | | - ret = wc_InitRng_ex(rng, NULL, WH_DEV_ID); |
152 | | - if (ret != 0) { |
153 | | - printf("Failed to wc_InitRng_ex %d\n", ret); |
| 255 | +#ifndef NO_AES |
| 256 | +#ifdef HAVE_AESGCM |
| 257 | + |
| 258 | + ret = wh_DemoClient_AesGcmKeyWrap(client); |
| 259 | + if (ret != WH_ERROR_OK) { |
| 260 | + printf("Failed to wh_DemoClient_AesGcmKeyWrap %d\n", ret); |
154 | 261 | return ret; |
155 | 262 | } |
156 | 263 |
|
157 | | -#ifndef NO_AES |
158 | | - ret = wh_DemoClient_AesKeyWrapBasic(clientContext, rng); |
159 | | -#endif |
| 264 | +#endif /* !NO_AES */ |
| 265 | +#endif /* HAVE_AESGCM */ |
160 | 266 |
|
161 | | - wc_FreeRng(rng); |
162 | 267 | return ret; |
163 | 268 | } |
164 | 269 | #endif /* WOLFHSM_CFG_KEYWRAP */ |
0 commit comments