use of java.util.jar.Attributes in project XobotOS by xamarin.
the class URLClassLoader method definePackage.
/**
* Defines a new package using the information extracted from the specified
* manifest.
*
* @param packageName
* the name of the new package.
* @param manifest
* the manifest containing additional information for the new
* package.
* @param url
* the URL to the code source for the new package.
* @return the created package.
* @throws IllegalArgumentException
* if a package with the given name already exists.
*/
protected Package definePackage(String packageName, Manifest manifest, URL url) throws IllegalArgumentException {
Attributes mainAttributes = manifest.getMainAttributes();
String dirName = packageName.replace('.', '/') + "/";
Attributes packageAttributes = manifest.getAttributes(dirName);
boolean noEntry = false;
if (packageAttributes == null) {
noEntry = true;
packageAttributes = mainAttributes;
}
String specificationTitle = packageAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE);
if (specificationTitle == null && !noEntry) {
specificationTitle = mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE);
}
String specificationVersion = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
if (specificationVersion == null && !noEntry) {
specificationVersion = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
}
String specificationVendor = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR);
if (specificationVendor == null && !noEntry) {
specificationVendor = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR);
}
String implementationTitle = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
if (implementationTitle == null && !noEntry) {
implementationTitle = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
}
String implementationVersion = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
if (implementationVersion == null && !noEntry) {
implementationVersion = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
}
String implementationVendor = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
if (implementationVendor == null && !noEntry) {
implementationVendor = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
}
return definePackage(packageName, specificationTitle, specificationVersion, specificationVendor, implementationTitle, implementationVersion, implementationVendor, isSealed(manifest, dirName) ? url : null);
}
use of java.util.jar.Attributes in project otertool by wuntee.
the class JarSigner method signJar.
void signJar(String jarName, String alias, String[] args) throws Exception {
boolean aliasUsed = false;
X509Certificate tsaCert = null;
if (sigfile == null) {
sigfile = alias;
aliasUsed = true;
}
if (sigfile.length() > 8) {
sigfile = sigfile.substring(0, 8).toUpperCase();
} else {
sigfile = sigfile.toUpperCase();
}
StringBuilder tmpSigFile = new StringBuilder(sigfile.length());
for (int j = 0; j < sigfile.length(); j++) {
char c = sigfile.charAt(j);
if (!((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '-') || (c == '_'))) {
if (aliasUsed) {
// convert illegal characters from the alias to be _'s
c = '_';
} else {
throw new RuntimeException(rb.getString("signature filename must consist of the following characters: A-Z, 0-9, _ or -"));
}
}
tmpSigFile.append(c);
}
sigfile = tmpSigFile.toString();
String tmpJarName;
if (signedjar == null)
tmpJarName = jarName + ".sig";
else
tmpJarName = signedjar;
File jarFile = new File(jarName);
File signedJarFile = new File(tmpJarName);
// Open the jar (zip) file
try {
zipFile = new ZipFile(jarName);
} catch (IOException ioe) {
error(rb.getString("unable to open jar file: ") + jarName, ioe);
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(signedJarFile);
} catch (IOException ioe) {
error(rb.getString("unable to create: ") + tmpJarName, ioe);
}
PrintStream ps = new PrintStream(fos);
ZipOutputStream zos = new ZipOutputStream(ps);
/* First guess at what they might be - we don't xclude RSA ones. */
String sfFilename = (META_INF + sigfile + ".SF").toUpperCase();
String bkFilename = (META_INF + sigfile + ".DSA").toUpperCase();
Manifest manifest = new Manifest();
Map<String, Attributes> mfEntries = manifest.getEntries();
// The Attributes of manifest before updating
Attributes oldAttr = null;
boolean mfModified = false;
boolean mfCreated = false;
byte[] mfRawBytes = null;
try {
MessageDigest[] digests = { MessageDigest.getInstance(digestalg) };
// Check if manifest exists
ZipEntry mfFile;
if ((mfFile = getManifestFile(zipFile)) != null) {
// Manifest exists. Read its raw bytes.
mfRawBytes = getBytes(zipFile, mfFile);
manifest.read(new ByteArrayInputStream(mfRawBytes));
oldAttr = (Attributes) (manifest.getMainAttributes().clone());
} else {
// Create new manifest
Attributes mattr = manifest.getMainAttributes();
mattr.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
String javaVendor = System.getProperty("java.vendor");
String jdkVersion = System.getProperty("java.version");
mattr.putValue("Created-By", jdkVersion + " (" + javaVendor + ")");
mfFile = new ZipEntry(JarFile.MANIFEST_NAME);
mfCreated = true;
}
/*
* For each entry in jar
* (except for signature-related META-INF entries),
* do the following:
*
* - if entry is not contained in manifest, add it to manifest;
* - if entry is contained in manifest, calculate its hash and
* compare it with the one in the manifest; if they are
* different, replace the hash in the manifest with the newly
* generated one. (This may invalidate existing signatures!)
*/
BASE64Encoder encoder = new JarBASE64Encoder();
Vector<ZipEntry> mfFiles = new Vector<ZipEntry>();
for (Enumeration<? extends ZipEntry> enum_ = zipFile.entries(); enum_.hasMoreElements(); ) {
ZipEntry ze = enum_.nextElement();
if (ze.getName().startsWith(META_INF)) {
// Store META-INF files in vector, so they can be written
// out first
mfFiles.addElement(ze);
if (signatureRelated(ze.getName())) {
// ignore signature-related and manifest files
continue;
}
}
if (manifest.getAttributes(ze.getName()) != null) {
// possibly update its digest attributes
if (updateDigests(ze, zipFile, digests, encoder, manifest) == true) {
mfModified = true;
}
} else if (!ze.isDirectory()) {
// Add entry to manifest
Attributes attrs = getDigestAttributes(ze, zipFile, digests, encoder);
mfEntries.put(ze.getName(), attrs);
mfModified = true;
}
}
// Recalculate the manifest raw bytes if necessary
if (mfModified) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
manifest.write(baos);
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.
*/
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;
}
}
mfRawBytes = newBytes;
}
// Write out the manifest
if (mfModified) {
// manifest file has new length
mfFile = new ZipEntry(JarFile.MANIFEST_NAME);
}
zos.putNextEntry(mfFile);
zos.write(mfRawBytes);
// Calculate SignatureFile (".SF") and SignatureBlockFile
ManifestDigester manDig = new ManifestDigester(mfRawBytes);
SignatureFile sf = new SignatureFile(digests, manifest, manDig, sigfile, signManifest);
if (tsaAlias != null) {
tsaCert = getTsaCert(tsaAlias);
}
SignatureFile.Block block = null;
try {
block = sf.generateBlock(privateKey, sigalg, certChain, externalSF, tsaUrl, tsaCert, signingMechanism, args, zipFile);
} catch (SocketTimeoutException e) {
// Provide a helpful message when TSA is beyond a firewall
error(rb.getString("unable to sign jar: ") + rb.getString("no response from the Timestamping Authority. ") + rb.getString("When connecting from behind a firewall then an HTTP proxy may need to be specified. ") + rb.getString("Supply the following options to jarsigner: ") + "\n -J-Dhttp.proxyHost=<hostname> " + "\n -J-Dhttp.proxyPort=<portnumber> ", e);
}
sfFilename = sf.getMetaName();
bkFilename = block.getMetaName();
ZipEntry sfFile = new ZipEntry(sfFilename);
ZipEntry bkFile = new ZipEntry(bkFilename);
long time = System.currentTimeMillis();
sfFile.setTime(time);
bkFile.setTime(time);
// signature file
zos.putNextEntry(sfFile);
sf.write(zos);
// signature block file
zos.putNextEntry(bkFile);
block.write(zos);
// vector
for (int i = 0; i < mfFiles.size(); i++) {
ZipEntry ze = mfFiles.elementAt(i);
if (!ze.getName().equalsIgnoreCase(JarFile.MANIFEST_NAME) && !ze.getName().equalsIgnoreCase(sfFilename) && !ze.getName().equalsIgnoreCase(bkFilename)) {
writeEntry(zipFile, zos, ze);
}
}
// Write out all other files
for (Enumeration<? extends ZipEntry> enum_ = zipFile.entries(); enum_.hasMoreElements(); ) {
ZipEntry ze = enum_.nextElement();
if (!ze.getName().startsWith(META_INF)) {
writeEntry(zipFile, zos, ze);
}
}
} catch (IOException ioe) {
error(rb.getString("unable to sign jar: ") + ioe, ioe);
} finally {
// close the resouces
if (zipFile != null) {
zipFile.close();
zipFile = null;
}
if (zos != null) {
zos.close();
}
}
// try {
if (signedjar == null) {
// one, then delete the original.
if (!signedJarFile.renameTo(jarFile)) {
File origJar = new File(jarName + ".orig");
if (jarFile.renameTo(origJar)) {
if (signedJarFile.renameTo(jarFile)) {
origJar.delete();
} else {
MessageFormat form = new MessageFormat(rb.getString("attempt to rename signedJarFile to jarFile failed"));
Object[] source = { signedJarFile, jarFile };
error(form.format(source));
}
} else {
MessageFormat form = new MessageFormat(rb.getString("attempt to rename jarFile to origJar failed"));
Object[] source = { jarFile, origJar };
error(form.format(source));
}
}
}
if (hasExpiredCert || hasExpiringCert || notYetValidCert || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
logger.warn(rb.getString("Warning: "));
if (badKeyUsage) {
logger.warn(rb.getString("The signer certificate's KeyUsage extension doesn't allow code signing."));
}
if (badExtendedKeyUsage) {
logger.warn(rb.getString("The signer certificate's ExtendedKeyUsage extension doesn't allow code signing."));
}
if (badNetscapeCertType) {
logger.warn(rb.getString("The signer certificate's NetscapeCertType extension doesn't allow code signing."));
}
if (hasExpiredCert) {
logger.warn(rb.getString("The signer certificate has expired."));
} else if (hasExpiringCert) {
logger.warn(rb.getString("The signer certificate will expire within six months."));
} else if (notYetValidCert) {
logger.warn(rb.getString("The signer certificate is not yet valid."));
}
}
// no IOException thrown in the above try clause, so disable
// the catch clause.
// } catch(IOException ioe) {
// error(rb.getString("unable to sign jar: ")+ioe, ioe);
// }
}
use of java.util.jar.Attributes in project otertool by wuntee.
the class JarSigner method updateDigests.
/*
* Updates the digest attributes of a manifest entry, by adding or
* replacing digest values.
* A digest value is added if the manifest entry does not contain a digest
* for that particular algorithm.
* A digest value is replaced if it is obsolete.
*
* Returns true if the manifest entry has been changed, and false
* otherwise.
*/
private boolean updateDigests(ZipEntry ze, ZipFile zf, MessageDigest[] digests, BASE64Encoder encoder, Manifest mf) throws IOException {
boolean update = false;
Attributes attrs = mf.getAttributes(ze.getName());
String[] base64Digests = getDigests(ze, zf, digests, encoder);
for (int i = 0; i < digests.length; i++) {
String name = digests[i].getAlgorithm() + "-Digest";
String mfDigest = attrs.getValue(name);
if (mfDigest == null && digests[i].getAlgorithm().equalsIgnoreCase("SHA")) {
// treat "SHA" and "SHA1" the same
mfDigest = attrs.getValue("SHA-Digest");
}
if (mfDigest == null) {
// compute digest and add it to list of attributes
attrs.putValue(name, base64Digests[i]);
update = true;
} else {
// if they are different
if (!mfDigest.equalsIgnoreCase(base64Digests[i])) {
attrs.putValue(name, base64Digests[i]);
update = true;
}
}
}
return update;
}
use of java.util.jar.Attributes in project android_frameworks_base by ResurrectionRemix.
the class StrictJarVerifier method initEntry.
/**
* Invoked for each new JAR entry read operation from the input
* stream. This method constructs and returns a new {@link VerifierEntry}
* which contains the certificates used to sign the entry and its hash value
* as specified in the JAR MANIFEST format.
*
* @param name
* the name of an entry in a JAR file which is <b>not</b> in the
* {@code META-INF} directory.
* @return a new instance of {@link VerifierEntry} which can be used by
* callers as an {@link OutputStream}.
*/
VerifierEntry initEntry(String name) {
// been found, do not verify.
if (manifest == null || signatures.isEmpty()) {
return null;
}
Attributes attributes = manifest.getAttributes(name);
// entry has no digest
if (attributes == null) {
return null;
}
ArrayList<Certificate[]> certChains = new ArrayList<Certificate[]>();
Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
HashMap<String, Attributes> hm = entry.getValue();
if (hm.get(name) != null) {
// Found an entry for entry name in .SF file
String signatureFile = entry.getKey();
Certificate[] certChain = certificates.get(signatureFile);
if (certChain != null) {
certChains.add(certChain);
}
}
}
// entry is not signed
if (certChains.isEmpty()) {
return null;
}
Certificate[][] certChainsArray = certChains.toArray(new Certificate[certChains.size()][]);
for (int i = 0; i < DIGEST_ALGORITHMS.length; i++) {
final String algorithm = DIGEST_ALGORITHMS[i];
final String hash = attributes.getValue(algorithm + "-Digest");
if (hash == null) {
continue;
}
byte[] hashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
try {
return new VerifierEntry(name, MessageDigest.getInstance(algorithm), hashBytes, certChainsArray, verifiedEntries);
} catch (NoSuchAlgorithmException ignored) {
}
}
return null;
}
use of java.util.jar.Attributes in project android_frameworks_base by ResurrectionRemix.
the class StrictJarVerifier method verifyCertificate.
/**
* @param certFile
*/
private void verifyCertificate(String certFile) {
// Found Digital Sig, .SF should already have been read
String signatureFile = certFile.substring(0, certFile.lastIndexOf('.')) + ".SF";
byte[] sfBytes = metaEntries.get(signatureFile);
if (sfBytes == null) {
return;
}
byte[] manifestBytes = metaEntries.get(JarFile.MANIFEST_NAME);
// Manifest entry is required for any verifications.
if (manifestBytes == null) {
return;
}
byte[] sBlockBytes = metaEntries.get(certFile);
try {
Certificate[] signerCertChain = verifyBytes(sBlockBytes, sfBytes);
if (signerCertChain != null) {
certificates.put(signatureFile, signerCertChain);
}
} catch (GeneralSecurityException e) {
throw failedVerification(jarName, signatureFile, e);
}
// Verify manifest hash in .sf file
Attributes attributes = new Attributes();
HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
try {
StrictJarManifestReader im = new StrictJarManifestReader(sfBytes, attributes);
im.readEntries(entries, null);
} catch (IOException e) {
return;
}
// If requested, check whether APK Signature Scheme v2 signature was stripped.
if (signatureSchemeRollbackProtectionsEnforced) {
String apkSignatureSchemeIdList = attributes.getValue(ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
if (apkSignatureSchemeIdList != null) {
// This field contains a comma-separated list of APK signature scheme IDs which
// were used to sign this APK. If an ID is known to us, it means signatures of that
// scheme were stripped from the APK because otherwise we wouldn't have fallen back
// to verifying the APK using the JAR signature scheme.
boolean v2SignatureGenerated = false;
StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
while (tokenizer.hasMoreTokens()) {
String idText = tokenizer.nextToken().trim();
if (idText.isEmpty()) {
continue;
}
int id;
try {
id = Integer.parseInt(idText);
} catch (Exception ignored) {
continue;
}
if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
// This APK was supposed to be signed with APK Signature Scheme v2 but no
// such signature was found.
v2SignatureGenerated = true;
break;
}
}
if (v2SignatureGenerated) {
throw new SecurityException(signatureFile + " indicates " + jarName + " is signed using APK Signature Scheme v2, but no such signature was" + " found. Signature stripped?");
}
}
}
// Do we actually have any signatures to look at?
if (attributes.get(Attributes.Name.SIGNATURE_VERSION) == null) {
return;
}
boolean createdBySigntool = false;
String createdBy = attributes.getValue("Created-By");
if (createdBy != null) {
createdBySigntool = createdBy.indexOf("signtool") != -1;
}
// such verification.
if (mainAttributesEnd > 0 && !createdBySigntool) {
String digestAttribute = "-Digest-Manifest-Main-Attributes";
if (!verify(attributes, digestAttribute, manifestBytes, 0, mainAttributesEnd, false, true)) {
throw failedVerification(jarName, signatureFile);
}
}
// Use .SF to verify the whole manifest.
String digestAttribute = createdBySigntool ? "-Digest" : "-Digest-Manifest";
if (!verify(attributes, digestAttribute, manifestBytes, 0, manifestBytes.length, false, false)) {
Iterator<Map.Entry<String, Attributes>> it = entries.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Attributes> entry = it.next();
StrictJarManifest.Chunk chunk = manifest.getChunk(entry.getKey());
if (chunk == null) {
return;
}
if (!verify(entry.getValue(), "-Digest", manifestBytes, chunk.start, chunk.end, createdBySigntool, false)) {
throw invalidDigest(signatureFile, entry.getKey(), jarName);
}
}
}
metaEntries.put(signatureFile, null);
signatures.put(signatureFile, entries);
}
Aggregations