6948909: Jarsigner removes MANIFEST.MF info for badly packages jar's
Reviewed-by: mullan, xuelei
This commit is contained in:
parent
e3e5b8ad72
commit
a94d06f6b7
jdk
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1123,6 +1123,8 @@ public class JarSigner {
|
||||
BASE64Encoder encoder = new JarBASE64Encoder();
|
||||
Vector<ZipEntry> mfFiles = new Vector<ZipEntry>();
|
||||
|
||||
boolean wasSigned = false;
|
||||
|
||||
for (Enumeration<? extends ZipEntry> enum_=zipFile.entries();
|
||||
enum_.hasMoreElements();) {
|
||||
ZipEntry ze = enum_.nextElement();
|
||||
@ -1132,6 +1134,11 @@ public class JarSigner {
|
||||
// out first
|
||||
mfFiles.addElement(ze);
|
||||
|
||||
if (SignatureFileVerifier.isBlockOrSF(
|
||||
ze.getName().toUpperCase(Locale.ENGLISH))) {
|
||||
wasSigned = true;
|
||||
}
|
||||
|
||||
if (signatureRelated(ze.getName())) {
|
||||
// ignore signature-related and manifest files
|
||||
continue;
|
||||
@ -1159,37 +1166,41 @@ public class JarSigner {
|
||||
if (mfModified) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
manifest.write(baos);
|
||||
byte[] newBytes = baos.toByteArray();
|
||||
if (mfRawBytes != null
|
||||
&& oldAttr.equals(manifest.getMainAttributes())) {
|
||||
if (wasSigned) {
|
||||
byte[] newBytes = baos.toByteArray();
|
||||
if (mfRawBytes != null
|
||||
&& oldAttr.equals(manifest.getMainAttributes())) {
|
||||
|
||||
/*
|
||||
* Note:
|
||||
*
|
||||
* The Attributes object is based on HashMap and can handle
|
||||
* continuation columns. Therefore, even if the contents are
|
||||
* not changed (in a Map view), the bytes that it write()
|
||||
* may be different from the original bytes that it read()
|
||||
* from. Since the signature on the main attributes is based
|
||||
* on raw bytes, we must retain the exact bytes.
|
||||
*/
|
||||
/*
|
||||
* Note:
|
||||
*
|
||||
* The Attributes object is based on HashMap and can handle
|
||||
* continuation columns. Therefore, even if the contents are
|
||||
* not changed (in a Map view), the bytes that it write()
|
||||
* may be different from the original bytes that it read()
|
||||
* from. Since the signature on the main attributes is based
|
||||
* on raw bytes, we must retain the exact bytes.
|
||||
*/
|
||||
|
||||
int newPos = findHeaderEnd(newBytes);
|
||||
int oldPos = findHeaderEnd(mfRawBytes);
|
||||
int newPos = findHeaderEnd(newBytes);
|
||||
int oldPos = findHeaderEnd(mfRawBytes);
|
||||
|
||||
if (newPos == oldPos) {
|
||||
System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos);
|
||||
} else {
|
||||
// cat oldHead newTail > newBytes
|
||||
byte[] lastBytes = new byte[oldPos +
|
||||
newBytes.length - newPos];
|
||||
System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos);
|
||||
System.arraycopy(newBytes, newPos, lastBytes, oldPos,
|
||||
newBytes.length - newPos);
|
||||
newBytes = lastBytes;
|
||||
if (newPos == oldPos) {
|
||||
System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos);
|
||||
} else {
|
||||
// cat oldHead newTail > newBytes
|
||||
byte[] lastBytes = new byte[oldPos +
|
||||
newBytes.length - newPos];
|
||||
System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos);
|
||||
System.arraycopy(newBytes, newPos, lastBytes, oldPos,
|
||||
newBytes.length - newPos);
|
||||
newBytes = lastBytes;
|
||||
}
|
||||
}
|
||||
mfRawBytes = newBytes;
|
||||
} else {
|
||||
mfRawBytes = baos.toByteArray();
|
||||
}
|
||||
mfRawBytes = newBytes;
|
||||
}
|
||||
|
||||
// Write out the manifest
|
||||
@ -1411,23 +1422,31 @@ public class JarSigner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the position of an empty line inside bs
|
||||
* Find the length of header inside bs. The header is a multiple (>=0)
|
||||
* lines of attributes plus an empty line. The empty line is included
|
||||
* in the header.
|
||||
*/
|
||||
private int findHeaderEnd(byte[] bs) {
|
||||
// An empty line can be at the beginning...
|
||||
if (bs.length > 1 && bs[0] == '\r' && bs[1] == '\n') {
|
||||
return 0;
|
||||
}
|
||||
// ... or after another line
|
||||
for (int i=0; i<bs.length-3; i++) {
|
||||
if (bs[i] == '\r' && bs[i+1] == '\n' &&
|
||||
bs[i+2] == '\r' && bs[i+3] == '\n') {
|
||||
return i;
|
||||
// Initial state true to deal with empty header
|
||||
boolean newline = true; // just met a newline
|
||||
int len = bs.length;
|
||||
for (int i=0; i<len; i++) {
|
||||
switch (bs[i]) {
|
||||
case '\r':
|
||||
if (i < len && bs[i+1] == '\n') i++;
|
||||
// fallthrough
|
||||
case '\n':
|
||||
if (newline) return i+1; //+1 to get length
|
||||
newline = true;
|
||||
break;
|
||||
default:
|
||||
newline = false;
|
||||
}
|
||||
}
|
||||
// If header end is not found, return 0,
|
||||
// which means no behavior change.
|
||||
return 0;
|
||||
// If header end is not found, it means the MANIFEST.MF has only
|
||||
// the main attributes section and it does not end with 2 newlines.
|
||||
// Returns the whole length so that it can be completely replaced.
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
113
jdk/test/sun/security/tools/jarsigner/diffend.sh
Normal file
113
jdk/test/sun/security/tools/jarsigner/diffend.sh
Normal file
@ -0,0 +1,113 @@
|
||||
#
|
||||
# Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
# have any questions.
|
||||
#
|
||||
|
||||
# @test
|
||||
# @bug 6948909
|
||||
# @summary Jarsigner removes MANIFEST.MF info for badly packages jar's
|
||||
#
|
||||
|
||||
if [ "${TESTSRC}" = "" ] ; then
|
||||
TESTSRC="."
|
||||
fi
|
||||
if [ "${TESTCLASSES}" = "" ] ; then
|
||||
TESTCLASSES="."
|
||||
fi
|
||||
if [ "${TESTJAVA}" = "" ] ; then
|
||||
echo "TESTJAVA not set. Test cannot execute."
|
||||
echo "FAILED!!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# set platform-dependent variables
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
SunOS | Linux )
|
||||
NULL=/dev/null
|
||||
PS=":"
|
||||
FS="/"
|
||||
CP="${FS}bin${FS}cp -f"
|
||||
TMP=/tmp
|
||||
;;
|
||||
CYGWIN* )
|
||||
NULL=/dev/null
|
||||
PS=";"
|
||||
FS="/"
|
||||
CP="cp -f"
|
||||
TMP=/tmp
|
||||
;;
|
||||
Windows_* )
|
||||
NULL=NUL
|
||||
PS=";"
|
||||
FS="\\"
|
||||
CP="cp -f"
|
||||
TMP="c:/temp"
|
||||
;;
|
||||
* )
|
||||
echo "Unrecognized operating system!"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
echo 1 > 1
|
||||
mkdir META-INF
|
||||
|
||||
# Create a fake .RSA file so that jarsigner believes it's signed
|
||||
|
||||
touch META-INF/x.RSA
|
||||
|
||||
# A MANIFEST.MF using \n as newlines and no double newlines at the end
|
||||
|
||||
cat > META-INF/MANIFEST.MF <<EOF
|
||||
Manifest-Version: 1.0
|
||||
Created-By: 1.7.0-internal (Sun Microsystems Inc.)
|
||||
Today: Monday
|
||||
EOF
|
||||
|
||||
# With the fake .RSA file, to trigger the if (wasSigned) block
|
||||
|
||||
rm diffend.jar
|
||||
zip diffend.jar META-INF/MANIFEST.MF META-INF/x.RSA 1
|
||||
|
||||
${TESTJAVA}${FS}bin${FS}jarsigner \
|
||||
-keystore ${TESTSRC}${FS}JarSigning.keystore \
|
||||
-storepass bbbbbb \
|
||||
-digestalg SHA1 \
|
||||
-signedjar diffend.new.jar \
|
||||
diffend.jar c
|
||||
|
||||
unzip -p diffend.new.jar META-INF/MANIFEST.MF | grep Today || exit 1
|
||||
|
||||
# Without the fake .RSA file, to trigger the else block
|
||||
|
||||
rm diffend.jar
|
||||
zip diffend.jar META-INF/MANIFEST.MF 1
|
||||
|
||||
${TESTJAVA}${FS}bin${FS}jarsigner \
|
||||
-keystore ${TESTSRC}${FS}JarSigning.keystore \
|
||||
-storepass bbbbbb \
|
||||
-digestalg SHA1 \
|
||||
-signedjar diffend.new.jar \
|
||||
diffend.jar c
|
||||
|
||||
unzip -p diffend.new.jar META-INF/MANIFEST.MF | grep Today || exit 2
|
||||
|
Loading…
x
Reference in New Issue
Block a user