CVE-2020-25021 (published 2020-09-04T04:15Z)

An issue was discovered in Noise-Java through 2020-08-27. ChaChaPolyCipherState.encryptWithAd() allows out-of-bounds access.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-125
cwe_name: Out-of-bounds Read
description: The product reads data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/rweather/noise-java
commit_details: repo_url: https://github.com/rweather/noise-java
author: Rhys Weatherley
author_date: 2020-08-29 07:59:27+10:00
msg: Improve array bounds checks in CipherState implementations

Thanks to Pietro Oliva for identifying these issues.
repository: repo_url: https://github.com/rweather/noise-java
repo_name: rweather/noise-java
description: Plain Java implementation of the Noise protocol
repo_language: Java
owner: rweather
file_changes: filename: .gitignore
change_type: ModificationType.MODIFY
diff: @@ -3,3 +3,4 @@ target
 .metadata
 .project
 doc
+*.class

programming_language: Markdown
filename: AESGCMFallbackCipherState.java
change_type: ModificationType.MODIFY
diff: @@ -185,10 +185,11 @@ class AESGCMFallbackCipherState implements CipherState {
 			byte[] ciphertext, int ciphertextOffset, int length)
 			throws ShortBufferException {
 		int space;
-		if (ciphertextOffset > ciphertext.length)
-			space = 0;
-		else
-			space = ciphertext.length - ciphertextOffset;
+		if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
+			throw new IllegalArgumentException();
+		if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length)
+			throw new IllegalArgumentException();
+		space = ciphertext.length - ciphertextOffset;
 		if (!haskey) {
 			// The key is not set yet - return the plaintext as-is.
 			if (length > space)
@@ -214,16 +215,15 @@ class AESGCMFallbackCipherState implements CipherState {
 			int ciphertextOffset, byte[] plaintext, int plaintextOffset,
 			int length) throws ShortBufferException, BadPaddingException {
 		int space;
-		if (ciphertextOffset > ciphertext.length)
-			space = 0;
+		if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
+			throw new IllegalArgumentException();
 		else
 			space = ciphertext.length - ciphertextOffset;
 		if (length > space)
 			throw new ShortBufferException();
-		if (plaintextOffset > plaintext.length)
-			space = 0;
-		else
-			space = plaintext.length - plaintextOffset;
+		if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length)
+			throw new IllegalArgumentException();
+		space = plaintext.length - plaintextOffset;
 		if (!haskey) {
 			// The key is not set yet - return the ciphertext as-is.
 			if (length > space)

programming_language: Java
filename: AESGCMOnCtrCipherState.java
change_type: ModificationType.MODIFY
diff: @@ -218,10 +218,11 @@ class AESGCMOnCtrCipherState implements CipherState {
 			byte[] ciphertext, int ciphertextOffset, int length)
 			throws ShortBufferException {
 		int space;
-		if (ciphertextOffset > ciphertext.length)
-			space = 0;
-		else
-			space = ciphertext.length - ciphertextOffset;
+		if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
+			throw new IllegalArgumentException();
+		if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length)
+			throw new IllegalArgumentException();
+		space = ciphertext.length - ciphertextOffset;
 		if (keySpec == null) {
 			// The key is not set yet - return the plaintext as-is.
 			if (length > space)
@@ -262,16 +263,15 @@ class AESGCMOnCtrCipherState implements CipherState {
 			int ciphertextOffset, byte[] plaintext, int plaintextOffset,
 			int length) throws ShortBufferException, BadPaddingException {
 		int space;
-		if (ciphertextOffset > ciphertext.length)
-			space = 0;
+		if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
+			throw new IllegalArgumentException();
 		else
 			space = ciphertext.length - ciphertextOffset;
 		if (length > space)
 			throw new ShortBufferException();
-		if (plaintextOffset > plaintext.length)
-			space = 0;
-		else
-			space = plaintext.length - plaintextOffset;
+		if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length)
+			throw new IllegalArgumentException();
+		space = plaintext.length - plaintextOffset;
 		if (keySpec == null) {
 			// The key is not set yet - return the ciphertext as-is.
 			if (length > space)

programming_language: Java
filename: ChaChaPolyCipherState.java
change_type: ModificationType.MODIFY
diff: @@ -214,10 +214,11 @@ class ChaChaPolyCipherState implements CipherState {
 	public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
 			byte[] ciphertext, int ciphertextOffset, int length) throws ShortBufferException {
 		int space;
-		if (ciphertextOffset > ciphertext.length)
-			space = 0;
-		else
-			space = ciphertext.length - ciphertextOffset;
+		if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
+			throw new IllegalArgumentException();
+		if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length)
+			throw new IllegalArgumentException();
+		space = ciphertext.length - ciphertextOffset;
 		if (!haskey) {
 			// The key is not set yet - return the plaintext as-is.
 			if (length > space)
@@ -241,16 +242,15 @@ class ChaChaPolyCipherState implements CipherState {
 			int ciphertextOffset, byte[] plaintext, int plaintextOffset,
 			int length) throws ShortBufferException, BadPaddingException {
 		int space;
-		if (ciphertextOffset > ciphertext.length)
-			space = 0;
+		if (ciphertextOffset < 0 || ciphertextOffset > ciphertext.length)
+			throw new IllegalArgumentException();
 		else
 			space = ciphertext.length - ciphertextOffset;
 		if (length > space)
 			throw new ShortBufferException();
-		if (plaintextOffset > plaintext.length)
-			space = 0;
-		else
-			space = plaintext.length - plaintextOffset;
+		if (length < 0 || plaintextOffset < 0 || plaintextOffset > plaintext.length)
+			throw new IllegalArgumentException();
+		space = plaintext.length - plaintextOffset;
 		if (!haskey) {
 			// The key is not set yet - return the ciphertext as-is.
 			if (length > space)

programming_language: Java
filename: CipherState.java
change_type: ModificationType.MODIFY
diff: @@ -100,6 +100,8 @@ public interface CipherState extends Destroyable {
 	 * 
 	 * @throws IllegalStateException The nonce has wrapped around.
 	 * 
+	 * @throws IllegalArgumentException One of the parameters is out of range.
+	 *
 	 * The plaintext and ciphertext buffers can be the same for in-place
 	 * encryption.  In that case, plaintextOffset must be identical to
 	 * ciphertextOffset.
@@ -130,6 +132,8 @@ public interface CipherState extends Destroyable {
 	 * 
 	 * @throws IllegalStateException The nonce has wrapped around.
 	 * 
+	 * @throws IllegalArgumentException One of the parameters is out of range.
+	 *
 	 * The plaintext and ciphertext buffers can be the same for in-place
 	 * decryption.  In that case, ciphertextOffset must be identical to
 	 * plaintextOffset.

programming_language: Java