/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class SignatureFileVerifier {
/* Are we debugging ? */
/* cache of CodeSigner objects */
/** the PKCS7 block for this .DSA/.RSA/.EC file */
/** the raw bytes of the .SF file */
private byte sfBytes[];
/** the name of the signature block file, uppercased and without
* the extension (.DSA/.RSA/.EC)
*/
/** the ManifestDigester */
/** cache of created MessageDigest objects */
/* workaround for parsing Netscape jars */
private boolean workaround = false;
/* for generating certpath objects */
/**
* Create the named SignatureFileVerifier.
*
* @param name the name of the signature block file (.DSA/.RSA/.EC)
*
* @param rawBytes the raw bytes of the signature block file
*/
byte rawBytes[])
throws IOException, CertificateException
{
// new PKCS7() calls CertificateFactory.getInstance()
// need to use local providers here, see Providers class
try {
} finally {
}
this.signerCache = signerCache;
}
/**
* returns true if we need the .SF file
*/
public boolean needSignatureFileBytes()
{
}
/**
* returns true if we need this .SF file.
*
* @param name the name of the .SF file without the extension
*
*/
{
}
/**
* used to set the raw bytes of the .SF file when it
* is external to the signature block file.
*/
{
}
/**
* Utility method used by JarVerifier and JarSigner
* to determine the signature file names and PKCS7 block
* files names that are supported
*
* @param s file name
* @return true if the input file name is a supported
* Signature File or PKCS7 block file name
*/
// we currently only support DSA and RSA PKCS7 blocks
return true;
}
return false;
}
/** get digest from cache */
{
if (createdDigests == null)
try {
} catch (NoSuchAlgorithmException nsae) {
// ignore
}
}
return digest;
}
/**
* process the signature block file. Goes through the .SF file
* and adds code signers for each section where the .SF section
* hash was verified against the Manifest section.
*
*
*/
{
// calls Signature.getInstance() and MessageDigest.getInstance()
// need to use local providers here, see Providers class
try {
} finally {
}
}
{
// XXX: should this be an exception?
// for now we just ignore this signature file
return;
}
throw new SecurityException("cannot verify signature block file " +
name);
}
// make sure we have something to do all this work for...
if (newSigners == null)
return;
// see if we can verify the whole manifest first
// verify manifest main attributes
throw new SecurityException
("Invalid signature file digest for Manifest main attributes");
}
// go through each section in the signature file
if (manifestSigned ||
}
}
}
// MANIFEST.MF is always regarded as signed
}
/**
* See if the whole manifest was signed.
*/
throws IOException
{
boolean manifestSigned = false;
// go through all the attributes and process *-Digest-Manifest entries
// 16 is length of "-Digest-Manifest"
byte[] expectedHash =
digest.getAlgorithm());
}
expectedHash)) {
manifestSigned = true;
} else {
//XXX: we will continue and verify each section
}
}
}
}
return manifestSigned;
}
throws IOException
{
boolean attrsVerified = true;
// go through all the attributes and process
// digest entries for the manifest main attributes
byte[] expectedHash =
"Manifest Main Attributes digest " +
digest.getAlgorithm());
}
expectedHash)) {
// good
} else {
// we will *not* continue and verify each section
attrsVerified = false;
"Manifest main attributes failed");
}
break;
}
}
}
}
// this method returns 'true' if either:
// . manifest main attributes were not signed, or
// . manifest main attributes were signed and verified
return attrsVerified;
}
/**
* given the .SF digest header, and the data from the
* section in the manifest, see if the hashes match.
* if not, throw a SecurityException.
*
* @return true if all the -Digest headers verified
* @exception SecurityException if the hash was not equal
*/
throws IOException
{
boolean oneDigestVerified = false;
throw new SecurityException(
"no manifiest section for signature file entry "+name);
}
//sun.misc.HexDumpEncoder hex = new sun.misc.HexDumpEncoder();
//hex.encodeBuffer(data, System.out);
// go through all the attributes and process *-Digest entries
// 7 is length of "-Digest"
boolean ok = false;
byte[] expected =
byte[] computed;
if (workaround) {
} else {
}
}
oneDigestVerified = true;
ok = true;
} else {
// attempt to fallback to the workaround
if (!workaround) {
}
workaround = true;
oneDigestVerified = true;
ok = true;
}
}
}
if (!ok){
throw new SecurityException("invalid " +
digest.getAlgorithm() +
" signature file digest for " + name);
}
}
}
}
}
return oneDigestVerified;
}
/**
* Given the PKCS7 block and SignerInfo[], create an array of
* CodeSigner objects. We do this only *once* for a given
* signature block file.
*/
}
// Append the new code signer
}
}
} else {
return null;
}
}
/*
* Examines a signature timestamp token to generate a timestamp object.
*
* Examines the signer's unsigned attributes for a
* <tt>signatureTimestampToken</tt> attribute. If present,
* then it is parsed to extract the date and time at which the
* timestamp was generated.
*
* @param info A signer information element of a PKCS 7 block.
*
* @return A timestamp token or null if none is present.
* @throws IOException if an error is encountered while parsing the
* PKCS7 data.
* @throws NoSuchAlgorithmException if an error is encountered while
* verifying the PKCS7 object.
* @throws SignatureException if an error is encountered while
* verifying the PKCS7 object.
* @throws CertificateException if an error is encountered while generating
* the TSA's certpath.
*/
// Extract the signer's unsigned attributes
if (unsignedAttrs != null) {
if (timestampTokenAttr != null) {
// Extract the content (an encoded timestamp token info)
byte[] encodedTimestampTokenInfo =
// Extract the signer (the Timestamping Authority)
// while verifying the content
SignerInfo[] tsa =
// Expect only one signer
// Create a timestamp token info object
// Check that the signature timestamp applies to this signature
// Create a timestamp object
}
}
return timestamp;
}
/*
* Check that the signature timestamp applies to this signature.
* Match the hash present in the signature timestamp token against the hash
* of this signature.
*/
throws NoSuchAlgorithmException, SignatureException {
throw new SignatureException("Signature timestamp (#" +
" is inapplicable");
}
}
}
// for the toHex function
private static final char[] hexc =
{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/**
* convert a byte array to a hex string for debugging purposes
* @param data the binary data to be converted to a hex string
* @return an ASCII hex string
*/
}
}
// returns true if set contains signer
{
return true;
}
return false;
}
// returns true if subset is a subset of set
{
// check for the same object
return true;
boolean match;
return false;
}
return true;
}
/**
* returns true if signer contains exactly the same code signers as
* oldSigner and newSigner, false otherwise. oldSigner
* is allowed to be null.
*/
CodeSigner[] newSigners) {
// special case
return true;
boolean match;
// make sure all oldSigners are in signers
return false;
// make sure all newSigners are in signers
return false;
}
// now make sure all the code signers in signers are
// also in oldSigners or newSigners
boolean found =
if (!found)
return false;
}
return true;
}
// search through the cache for a match, go in reverse order
// as we are more likely to find a match with the last one
// added to the cache
return;
}
}
if (oldSigners == null) {
} else {
}
}
}