bc-java icon indicating copy to clipboard operation
bc-java copied to clipboard

"worked around javax.mail change for attachment only messages." breaks code

Open r-sop opened this issue 1 year ago • 3 comments

Hi,

the commit https://github.com/bcgit/bc-java/commit/d050ec4c1c40544ae8d453fc769edb114f969c4b (bcmail 1.74) breaks our code:

content.setDataHandler(new DataHandler(message.getDataHandler().getDataSource()));

When I try to sign the following attachment-only Message:

MimeMessage messageToSign = new SimpleMimeMessage();
messageToSign.setContent(new byte[]{ 1 }, "application/octet-stream");
messageToSign.setFileName("file.gz");
messageToSign.saveChanges();

The signing fails silently without explicit error. The created signed MumeMultipart from the SMIMESignedGenerator is broken.

Setting the Datahandler and Conten-Headers manually "fixes" the problem:

//... 
MimeMultipart signedMultiPart = sMIMESignedGenerator.generate(messageToSign);
BodyPart bodyPart = signedMultiPart.getBodyPart(0);
bodyPart.setDataHandler(messageToSign.getDataHandler());
bodyPart.addHeader("Content-Transfer-Encoding", "base64");
bodyPart.addHeader("Content-Type", "application/octet-stream; name=file.gz");

The difference seems to be, that the messageToSign has no DataSource, but calling new DataHandler(message.getDataHandler().getDataSource()) assumes there is one?

// DataHandler-Source

    public void writeTo(OutputStream os) throws IOException {
	// for the DataSource case
	if (dataSource != null) {
// bcmail 1.74 way - throws Exception
	    InputStream is = null;
	    byte data[] = new byte[8*1024];
	    int bytes_read;

	    is = dataSource.getInputStream();

	    try {
		while ((bytes_read = is.read(data)) > 0) {
		    os.write(data, 0, bytes_read);
		}
	    } finally {
		is.close();
		is = null;
	    }
	} else { // for the Object case
// bcmail 1.73 way - works
	    DataContentHandler dch = getDataContentHandler();
	    dch.writeTo(object, objectMimeType, os);
	}
    }

EDIT Using a MimeBodyPart instead seems to fix the problem. Is my previous code wrong? Or should both ways work?

MimeBodyPart mimeBodyPartToSign = new MimeBodyPart();
mimeBodyPartToSign.setContent(new byte[]{ 1 }, "application/octet-stream");
mimeBodyPartToSign.setFileName("file.gz");

r-sop avatar Jun 20 '23 12:06 r-sop

I know this is going to sound dreadful, but you probably should be using a MimeBody part. What version of JavaMail are you using? The issue showed up for us because we updated the version of JavaMail we use locally - everything still worked except this one case, the assumption was that they'd fixed something which caused it to break. I'll admit attachment only messages are a bit of an edge condition, but even when we got everything working again it seemed surprising.

dghgit avatar Jun 21 '23 11:06 dghgit

Yes I did switch to MimeBodyPart, as it works for both 1.74 and older versions. I am currently stuck on java mail 1.6.7.

However, I find it kind of critical, that signature creation fails without any exception. And since I use sign then encrypt, it completely shadowed the error, which only occurred after decrypting when the signature verification failed with an ArrayIndexOutOfBoundsException!

So I think there should be a check if the DataHandler has a valid DataSource, or if the created MultiPart is valid. But for the bare minimum this should be documented.

r-sop avatar Jun 22 '23 04:06 r-sop

I'll see what I can do about adding a check, I should be able to get something that "works" now that I have another version of JavaMail to compare with.

dghgit avatar Jun 22 '23 04:06 dghgit