Skip to content

Commit f5d17bb

Browse files
authored
Merge pull request #150 from ColtonWilley/wp_aes_gcm_fips_streaming
Rewrite AES-GCM stream handling for FIPS
2 parents f6dd1c7 + 366c8cb commit f5d17bb

File tree

2 files changed

+375
-61
lines changed

2 files changed

+375
-61
lines changed

src/wp_aes_aead.c

Lines changed: 114 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@
3232

3333
#if defined(WP_HAVE_AESGCM) || defined(WP_HAVE_AESCCM)
3434

35+
/* For non-streaming AES-GCM, we have to spool all previous updates.
36+
* This is the number of extra bytes we add when allocating the internal
37+
* buffer used to spool the stream input. This way we if there is space
38+
* we can use the existing buffer, reducing the number of full realloc + copy
39+
* operations we need to do. Increase this number for better performance and
40+
* more memory usage, decrease for worse performance but less overhead */
41+
#ifndef WP_AES_GCM_EXTRA_BUF_LEN
42+
#define WP_AES_GCM_EXTRA_BUF_LEN 128
43+
#endif
44+
3545
/**
3646
* Authenticated Encryption with Associated Data structure.
3747
*/
@@ -94,10 +104,14 @@ typedef struct wp_AeadCtx {
94104
/** CCM is not streaming and needs to cache AAD data. */
95105
unsigned char* aad;
96106
#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM)
97-
/** Length of AAD data cached. */
107+
/** Length of data cached. */
98108
size_t inLen;
99109
/** CCM is not streaming and needs to cache AAD data. */
100110
unsigned char* in;
111+
/* Total buffer size */
112+
size_t bufSize;
113+
/* Original IV */
114+
unsigned char origIv[AES_BLOCK_SIZE];
101115
#endif
102116
} wp_AeadCtx;
103117

@@ -310,15 +324,24 @@ static int wp_aead_cache_in(wp_AeadCtx *ctx, const unsigned char *in,
310324
unsigned char *p;
311325

312326
if (inLen > 0) {
313-
p = (unsigned char*)OPENSSL_realloc(ctx->in, ctx->inLen + inLen);
314-
if (p == NULL) {
315-
ok = 0;
316-
}
317-
if (ok) {
318-
ctx->in = p;
327+
if (inLen < (ctx->bufSize - ctx->inLen)) {
328+
/* We can fit this new data into the extra space, dont realloc */
319329
XMEMCPY(ctx->in + ctx->inLen, in, inLen);
320330
ctx->inLen += inLen;
321331
}
332+
else {
333+
p = (unsigned char*)OPENSSL_realloc(ctx->in,
334+
ctx->inLen + inLen + WP_AES_GCM_EXTRA_BUF_LEN);
335+
if (p == NULL) {
336+
ok = 0;
337+
}
338+
if (ok) {
339+
ctx->bufSize = ctx->inLen + inLen + WP_AES_GCM_EXTRA_BUF_LEN;
340+
ctx->in = p;
341+
XMEMCPY(ctx->in + ctx->inLen, in, inLen);
342+
ctx->inLen += inLen;
343+
}
344+
}
322345
}
323346

324347
WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
@@ -823,8 +846,6 @@ static int wp_aesgcm_get_rand_iv(wp_AeadCtx* ctx, unsigned char* out,
823846
if (rc != 0) {
824847
ok = 0;
825848
}
826-
#else
827-
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
828849
#endif
829850
}
830851
if (ok) {
@@ -833,6 +854,9 @@ static int wp_aesgcm_get_rand_iv(wp_AeadCtx* ctx, unsigned char* out,
833854
olen = ctx->ivLen;
834855
}
835856
XMEMCPY(out, ctx->iv + ctx->ivLen - olen, olen);
857+
#ifndef WOLFSSL_AESGCM_STREAM
858+
XMEMCPY(ctx->origIv, ctx->iv, ctx->ivLen);
859+
#endif
836860
if (inc) {
837861
int i;
838862
unsigned char* p = ctx->iv + ctx->ivLen - 8;
@@ -869,6 +893,9 @@ static int wp_aesgcm_set_rand_iv(wp_AeadCtx *ctx, unsigned char *in,
869893
ok = 0;
870894
}
871895
else {
896+
#ifndef WOLFSSL_AESGCM_STREAM
897+
XMEMCPY(ctx->origIv, ctx->iv, ctx->ivLen);
898+
#endif
872899
XMEMCPY(ctx->iv + ctx->ivLen - inLen, in, inLen);
873900
ctx->ivState = IV_STATE_COPIED;
874901
}
@@ -1310,67 +1337,96 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out,
13101337
* @param [in, out] ctx AEAD context object.
13111338
* @param [out] out Buffer to hold decrypted/encrypted data.
13121339
* @param [out] outLen Length of data in output buffer.
1313-
* @param [in] in Data to be encrypted/decrypted.
1314-
* @param [in] inLen Length of data to be encrypted/decrypted.
1340+
* @param [in] offset Offset into the spooled data buffer.
1341+
* @param [in] done This is a final operation.
1342+
*
13151343
* @return 1 on success.
13161344
* @return 0 on failure.
13171345
*/
1318-
static int wp_aesgcm_encdec(wp_AeadCtx *ctx, unsigned char *out, size_t* outLen)
1346+
static int wp_aesgcm_encdec(wp_AeadCtx *ctx, unsigned char *out, size_t* outLen,
1347+
size_t offset, int done)
13191348
{
13201349
int ok = 1;
13211350
int rc;
1351+
unsigned char *tmp = NULL;
1352+
byte *iv = NULL;
13221353

13231354
if (ctx->tagLen == UNINITIALISED_SIZET) {
13241355
ctx->tagLen = EVP_GCM_TLS_TAG_LEN;
13251356
}
13261357

1327-
if (ctx->enc) {
1328-
if (!ctx->ivSet) {
1329-
rc = wc_AesGcmSetExtIV(&ctx->aes, ctx->iv, (word32)ctx->ivLen);
1330-
if (rc != 0) {
1358+
if (ctx->inLen > offset || (ctx->tagAvail == 0 && done)) {
1359+
/* Prepare a temp buffer to store all the output */
1360+
if (ctx->inLen > 0) {
1361+
tmp = OPENSSL_zalloc(ctx->inLen);
1362+
if (tmp == NULL) {
13311363
ok = 0;
13321364
}
13331365
}
1366+
/* Once loaded, always use original IV */
1367+
iv = ctx->iv;
1368+
if (ctx->ivState == IV_STATE_COPIED) {
1369+
iv = ctx->origIv;
1370+
}
13341371
if (ok) {
1335-
ctx->ivSet = 1;
1336-
/* IV coming out in this call. */
1337-
rc = wc_AesGcmEncrypt_ex(&ctx->aes, out, ctx->in,
1338-
(word32)ctx->inLen, ctx->iv, (word32)ctx->ivLen, ctx->buf,
1339-
(word32)ctx->tagLen, ctx->aad, (word32)ctx->aadLen);
1372+
rc = wc_AesGcmSetExtIV(&ctx->aes, iv, (word32)ctx->ivLen);
13401373
if (rc != 0) {
13411374
ok = 0;
13421375
}
1343-
if (ok) {
1344-
ctx->tagAvail = 1;
1376+
1377+
if (ok && ctx->ivState == IV_STATE_BUFFERED) {
1378+
ctx->ivState = IV_STATE_COPIED;
1379+
XMEMCPY(ctx->origIv, ctx->iv, ctx->ivLen);
13451380
}
13461381
}
1347-
}
1348-
else {
1349-
rc = wc_AesGcmDecrypt(&ctx->aes, out, ctx->in, (word32)ctx->inLen,
1350-
ctx->iv, (word32)ctx->ivLen, ctx->buf, (word32)ctx->tagLen,
1351-
ctx->aad, (word32)ctx->aadLen);
1352-
if (rc == AES_GCM_AUTH_E) {
1353-
ctx->authErr = 1;
1354-
rc = 0;
1382+
if (ctx->enc) {
1383+
if (ok) {
1384+
ctx->ivSet = 1;
1385+
/* IV coming out in this call. */
1386+
rc = wc_AesGcmEncrypt_ex(&ctx->aes, tmp, ctx->in,
1387+
(word32)ctx->inLen, iv, (word32)ctx->ivLen, ctx->buf,
1388+
(word32)ctx->tagLen, ctx->aad, (word32)ctx->aadLen);
1389+
if (rc != 0) {
1390+
ok = 0;
1391+
}
1392+
if (ok) {
1393+
ctx->tagAvail = 1;
1394+
}
1395+
}
13551396
}
1356-
if (rc != 0) {
1357-
ok = 0;
1397+
else {
1398+
/* Only the most recent auth err matters */
1399+
ctx->authErr = 0;
1400+
rc = wc_AesGcmDecrypt(&ctx->aes, tmp, ctx->in, (word32)ctx->inLen,
1401+
iv, (word32)ctx->ivLen, ctx->buf, (word32)ctx->tagLen,
1402+
ctx->aad, (word32)ctx->aadLen);
1403+
if (rc == AES_GCM_AUTH_E) {
1404+
ctx->authErr = 1;
1405+
rc = 0;
1406+
}
1407+
if (rc != 0) {
1408+
ok = 0;
1409+
}
13581410
}
1411+
/* Copy out relevant portion of output */
13591412
if (ok) {
1360-
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
1413+
XMEMCPY(out, tmp + offset, (ctx->inLen - offset));
1414+
*outLen = (ctx->inLen - offset);
13611415
}
1416+
OPENSSL_free(tmp);
13621417
}
1363-
if (ok) {
1364-
*outLen = ctx->inLen;
1418+
else {
1419+
*outLen = 0;
1420+
}
1421+
if (done) {
1422+
OPENSSL_free(ctx->aad);
1423+
ctx->aad = NULL;
1424+
ctx->aadLen = 0;
1425+
ctx->aadSet = 0;
1426+
OPENSSL_free(ctx->in);
1427+
ctx->in = NULL;
1428+
ctx->inLen = 0;
13651429
}
1366-
1367-
OPENSSL_free(ctx->aad);
1368-
ctx->aad = NULL;
1369-
ctx->aadLen = 0;
1370-
ctx->aadSet = 0;
1371-
OPENSSL_free(ctx->in);
1372-
ctx->in = NULL;
1373-
ctx->inLen = 0;
13741430

13751431
WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
13761432
return ok;
@@ -1392,6 +1448,8 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out,
13921448
size_t *outLen, size_t outSize, const unsigned char *in, size_t inLen)
13931449
{
13941450
int ok = 1;
1451+
int process = 0;
1452+
size_t curLen = 0;
13951453

13961454
if (ctx->tlsAadLen != UNINITIALISED_SIZET) {
13971455
ok = wp_aesgcm_tls_cipher(ctx, out, outLen, in, inLen);
@@ -1414,12 +1472,22 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out,
14141472
ok = 0;
14151473
}
14161474
else if (inLen > 0) {
1475+
curLen = ctx->inLen;
14171476
if (!wp_aead_cache_in(ctx, in, inLen)) {
14181477
ok = 0;
14191478
}
1479+
else {
1480+
process = 1;
1481+
}
14201482
}
14211483

1422-
*outLen = oLen;
1484+
/* If there is data to process, do it now */
1485+
if (process) {
1486+
ok = wp_aesgcm_encdec(ctx, out, outLen, curLen, 0);
1487+
}
1488+
else {
1489+
*outLen = oLen;
1490+
}
14231491
}
14241492

14251493
WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
@@ -1449,7 +1517,7 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out,
14491517
ok = 0;
14501518
}
14511519
else {
1452-
ok = wp_aesgcm_encdec(ctx, out, outLen);
1520+
ok = wp_aesgcm_encdec(ctx, out, outLen, ctx->inLen, 1);
14531521
ctx->ivSet = 0;
14541522
}
14551523

0 commit comments

Comments
 (0)