Skip to content

Commit 9c2f26c

Browse files
authored
fix: nonFramed maximum content length (#316)
nonFramed messages are encrypted under a single operation. The maximum number of bytes for a single AES-GCM "operation." is 2 ** 36 - 32 This is related to the GHASH block size, and can be thought of as the maximum bytes that can be encrypted with a single IV. The AWS Encryption SDK for Javascript does not support non-framed encrypt https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/data-format/message-body.md#non-framed-data
1 parent a7cab81 commit 9c2f26c

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

modules/serialize/src/decode_body_header.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import BN from 'bn.js'
5-
import { ContentType, SequenceIdentifier } from './identifiers'
5+
import { ContentType, SequenceIdentifier, Maximum } from './identifiers'
66
import {
77
HeaderInfo,
88
BodyHeader,
@@ -244,6 +244,13 @@ export function decodeNonFrameBodyHeader(
244244
// This will throw if the number is larger than Number.MAX_SAFE_INTEGER.
245245
// i.e. a 53 bit number
246246
const contentLength = contentLengthBN.toNumber()
247+
/* Postcondition: Non-framed content length MUST NOT exceed AES-GCM safe limits.
248+
* https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/data-format/message-body.md#encrypted-content-length
249+
*/
250+
needs(
251+
Maximum.BYTES_PER_AES_GCM_NONCE > contentLength,
252+
'Content length out of bounds.'
253+
)
247254
return {
248255
sequenceNumber: 1,
249256
iv,

modules/serialize/src/identifiers.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ export enum Maximum {
7474
* this value is set to 2 ** 53 - 1.
7575
*/
7676
BYTES_PER_MESSAGE = 2 ** 53 - 1,
77+
/* Maximum number of bytes for a single AES-GCM "operation."
78+
* This is related to the GHASH block size,
79+
* and can be thought of as the maximum bytes
80+
* that can be encrypted with a single key/IV pair.
81+
* The AWS Encryption SDK for Javascript
82+
* does not support non-framed encrypt
83+
* https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/data-format/message-body.md#non-framed-data
84+
* So this value is only needed to ensure
85+
* that messages submitted for decrypt
86+
* are well formed.
87+
*/
88+
BYTES_PER_AES_GCM_NONCE = 2 ** 36 - 32,
7789
// Maximum number of frames allowed in one message as defined in specification
7890
FRAME_COUNT = 2 ** 32 - 1,
7991
// Maximum bytes allowed in a single frame as defined in specification

modules/serialize/test/decode_body_header.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ describe('decodeNonFrameBodyHeader', () => {
502502
expect(test.tagLength).to.eql(16)
503503
expect(test.isFinalFrame).to.eql(true)
504504
expect(test.contentType).to.eql(ContentType.NO_FRAMING)
505+
expect(test.contentLength).to.eql(0)
505506
})
506507

507508
it('Precondition: The contentType must be NO_FRAMING.', () => {
@@ -562,6 +563,26 @@ describe('decodeNonFrameBodyHeader', () => {
562563
expect(() => decodeNonFrameBodyHeader(buffer, headerInfo, -1)).to.throw()
563564
})
564565

566+
it('Postcondition: Non-framed content length MUST NOT exceed AES-GCM safe limits.', () => {
567+
const headerInfo = {
568+
messageHeader: {
569+
contentType: ContentType.NO_FRAMING,
570+
},
571+
algorithmSuite: {
572+
ivLength: 12,
573+
tagLength: 16,
574+
},
575+
} as any
576+
577+
expect(() =>
578+
decodeNonFrameBodyHeader(
579+
fixtures.invalidNonFrameHeaderContentLengthExcedsLimits(),
580+
headerInfo,
581+
0
582+
)
583+
).to.throw('Content length out of bounds.')
584+
})
585+
565586
it('ArrayBuffer for a Uint8Array or Buffer may be larger than the Uint8Array or Buffer that it is a view over is.', () => {
566587
const headerInfo = {
567588
messageHeader: {

modules/serialize/test/fixtures.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,31 @@ export function basicNonFrameHeader() {
13171317
])
13181318
}
13191319

1320+
export function invalidNonFrameHeaderContentLengthExcedsLimits() {
1321+
return new Uint8Array([
1322+
0,
1323+
0,
1324+
0,
1325+
0,
1326+
0,
1327+
0,
1328+
0,
1329+
0,
1330+
0,
1331+
0,
1332+
0,
1333+
1,
1334+
0,
1335+
0,
1336+
0,
1337+
15,
1338+
255,
1339+
255,
1340+
255,
1341+
224,
1342+
])
1343+
}
1344+
13201345
export function basicEncryptionContext() {
13211346
return new Uint8Array([
13221347
0,

0 commit comments

Comments
 (0)