allthingssecurity opened a new pull request, #28711:
URL: https://github.com/apache/camel/pull/28711

   # Description
   
   [CAMEL-26306](https://issues.apache.org/jira/browse/CAMEL-26306)
   
   `AS2SessionInputBuffer.readLine` reported a line as ending with CRLF 
(`isLastLineReadEnrichedByCarriageReturn()`) only when the CR was in the read 
buffer right before the LF (`i > 0 && buffer[i - 1] == CR`). When the CR was 
the last byte of one read and the LF the first byte of the next, the CR was 
already in the line buffer: the line itself was right, but it was reported as 
ending with a bare LF.
   
   `EntityParser.parseBodyPartText` rebuilds the content of a body part from 
the lines and these flags (since CAMEL-15111, Camel 3.18.5 and 4.0, LF and CRLF 
line endings are kept as received), so that CRLF became LF in the EDI message 
(`parseEDIEntityBody` -> `parseBodyPartBytes`), in a text/plain part (the human 
readable part of an MDN) and in the other parts read through 
`parseBodyPartBytes`. When that CRLF was the one before a delimiter line, 
`parseBodyPartText` removed two characters for it (`setLength(length - 2)`), so 
the last byte of the content was lost instead.
   
   The line reader reads the entity content 8 KB at a time. The server parses 
the received body from a `ByteArrayInputStream` 
(`AS2BHttpServerConnection.receiveRequestEntity`), and the decrypted or 
decompressed content of an encrypted or compressed message is parsed the same 
way (`EntityParser.parseEntity`), so this happened for every CRLF whose CR is 
the last byte of an 8 KB read: offset 8191, 16383, ... of the body (of the 
decrypted or decompressed content for those). With 80 byte lines about one read 
in 80 ends that way, so an EDI file of 1 MB is more likely than not to be 
changed. The client parses an MDN response straight from the connection, where 
a read can end at any byte (not tested).
   
   What it does to a message:
   - signed: the signature is verified over the parsed content 
(`SigningUtils.isValid`), so verification fails and the message is rejected 
("Failed to validate the signature") when `validateSigningCertificateChain` is 
set. The new signed test checks that this signature check fails on main.
   - unsigned: the route gets the changed content. The MIC in the MDN is 
computed over the changed content too (`MicUtils.createReceivedContentMic`), so 
it does not match the sender's MIC (reasoned from the code, not tested).
   
   Changes:
   - `readLine`: when the LF is the first byte of the read buffer, the CR is 
taken from the end of the line buffer. Otherwise the byte before the LF must 
belong to this line (`i > bufferpos`), so a CR consumed before the line by 
`read(InputStream)` is no longer taken for its line ending either.
   - No option, default or API changes; no upgrade guide entry. The same check 
is on camel-4.22.x and 4.18.x (read, not run); the change is local to 
`readLine` and can be backported. On 4.18.x 
`AS2BHttpServerConnection.receiveRequestEntity` has no `ByteArrayInputStream` 
copy: the server parses the body straight from the connection, so there a read 
can end at any byte (read, not run).
   
   Tests:
   - New `AS2SessionInputBufferTest`: a CRLF split between two reads of a 
chunked stream, a CR that is the last byte of a full 8 byte read buffer, and a 
CR consumed by `read` before an empty line that ends with a bare LF. All three 
fail on main and pass with the fix.
   - New 
`EntityParserContentLineEndingTest.parseEdiMessageKeepsACrLfSplitByTheReadBuffer`:
 an unsigned `application/edifact` request through 
`EntityParser.parseAS2MessageEntity` (the call the server connection makes) 
whose first line is 8191 bytes, so its CR is the last byte of the first 8 KB 
read. It fails on main (the CR at offset 8191 is missing from 
`getEdiMessage()`) and passes with the fix.
   - New 
`EntityParserContentLineEndingTest.signedEdiMessageWithACrLfSplitByTheReadBufferKeepsItsSignature`
 (2 cases): a `multipart/signed` EDI message whose body has a CR at offset 
8191, inside the EDI content or before the delimiter line that follows it. On 
main the signature check of the parsed message fails for both (and the content 
has a CR less, or its last byte less); with the fix the signature is valid and 
the content is unchanged.
   - camel-as2-api: 117 tests, 0 failures. camel-as2-component: 157 tests (the 
45 unit tests and the 112 tests of the `*IT` classes, which start the AS2 
client and server in the JVM), 0 failures, 1 skipped. The core modules were 
built from this branch, as the local snapshot jars are older; 
`httpclient-version` 5.6.4 locally (5.6.5 is not in the offline repository). 
The formatter and import-sort plugins ran.
   
   How it was found: an OSS-Fuzz-style harness for the MIME boundary handling 
that Camel does itself (`EntityParser.parseBodyPartText` on 
`AS2SessionInputBuffer`, property: the text before the first delimiter line, 
whatever the read chunking), run on HotSpot with seeded random and 
grammar-aware inputs, found it in its first second; the minimised input is a 
body of CR and LF delivered in two reads. A JVM model in Rocq that executes the 
real class files then states it as kernel-checked theorems on the class files 
of main and of this change (`main_split_crlf_reported_as_lf`: "a CR LF b CR LF" 
read as "a CR" + "LF b CR LF" reports the first line with a bare LF; 
`fix_split_crlf_reported_as_crlf`). HotSpot gives the same results for the same 
class files.
   
   # Target
   
   - [x] I checked that the commit is targeting the correct branch (Camel 4 
uses the `main` branch)
   
   # Tracking
   - [x] If this is a large change, bug fix, or code improvement, I checked 
there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL-26306) 
filed for the change (usually before you start working on it): 
[CAMEL-26306](https://issues.apache.org/jira/browse/CAMEL-26306).
   
   # Apache Camel coding standards and style
   
   - [x] I checked that each commit in the pull request has a meaningful 
subject line and body.
   - [ ] I have run `mvn clean install -DskipTests` locally from root folder 
and I have committed all auto-generated changes.
     (I built the core modules and camel-as2 and ran the tests above, including 
the formatter and import-sort plugins. No generated file changes. I did not run 
the full root build.)
   
   # AI-assisted contributions
   
   - [x] If this PR includes AI-generated code, commits have proper 
co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR 
description identifies the AI tool used.
     This PR was prepared with Claude Code (Claude Opus 5.5). The commit 
carries a `Co-Authored-By` trailer.
   
   _Claude Code on behalf of allthingssecurity_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to