aboutsummaryrefslogtreecommitdiffstats
path: root/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/SignedJarBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/SignedJarBuilder.java')
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/SignedJarBuilder.java388
1 files changed, 0 insertions, 388 deletions
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/SignedJarBuilder.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/SignedJarBuilder.java
deleted file mode 100644
index 48f1b91..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/SignedJarBuilder.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.internal.build;
-
-import com.android.sdklib.internal.build.SignedJarBuilder.IZipEntryFilter.ZipAbortException;
-
-import sun.misc.BASE64Encoder;
-import sun.security.pkcs.ContentInfo;
-import sun.security.pkcs.PKCS7;
-import sun.security.pkcs.SignerInfo;
-import sun.security.x509.AlgorithmId;
-import sun.security.x509.X500Name;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.security.DigestOutputStream;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.Signature;
-import java.security.SignatureException;
-import java.security.cert.X509Certificate;
-import java.util.Map;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-/**
- * A Jar file builder with signature support.
- */
-public class SignedJarBuilder {
- private static final String DIGEST_ALGORITHM = "SHA1";
- private static final String DIGEST_ATTR = "SHA1-Digest";
- private static final String DIGEST_MANIFEST_ATTR = "SHA1-Digest-Manifest";
-
- /** Write to another stream and also feed it to the Signature object. */
- private static class SignatureOutputStream extends FilterOutputStream {
- private Signature mSignature;
- private int mCount = 0;
-
- public SignatureOutputStream(OutputStream out, Signature sig) {
- super(out);
- mSignature = sig;
- }
-
- @Override
- public void write(int b) throws IOException {
- try {
- mSignature.update((byte) b);
- } catch (SignatureException e) {
- throw new IOException("SignatureException: " + e);
- }
- super.write(b);
- mCount++;
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- try {
- mSignature.update(b, off, len);
- } catch (SignatureException e) {
- throw new IOException("SignatureException: " + e);
- }
- super.write(b, off, len);
- mCount += len;
- }
-
- public int size() {
- return mCount;
- }
- }
-
- private JarOutputStream mOutputJar;
- private PrivateKey mKey;
- private X509Certificate mCertificate;
- private Manifest mManifest;
- private BASE64Encoder mBase64Encoder;
- private MessageDigest mMessageDigest;
-
- private byte[] mBuffer = new byte[4096];
-
- /**
- * Classes which implement this interface provides a method to check whether a file should
- * be added to a Jar file.
- */
- public interface IZipEntryFilter {
-
- /**
- * An exception thrown during packaging of a zip file into APK file.
- * This is typically thrown by implementations of
- * {@link IZipEntryFilter#checkEntry(String)}.
- */
- public static class ZipAbortException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public ZipAbortException() {
- super();
- }
-
- public ZipAbortException(String format, Object... args) {
- super(String.format(format, args));
- }
-
- public ZipAbortException(Throwable cause, String format, Object... args) {
- super(String.format(format, args), cause);
- }
-
- public ZipAbortException(Throwable cause) {
- super(cause);
- }
- }
-
-
- /**
- * Checks a file for inclusion in a Jar archive.
- * @param archivePath the archive file path of the entry
- * @return <code>true</code> if the file should be included.
- * @throws ZipAbortException if writing the file should be aborted.
- */
- public boolean checkEntry(String archivePath) throws ZipAbortException;
- }
-
- /**
- * Creates a {@link SignedJarBuilder} with a given output stream, and signing information.
- * <p/>If either <code>key</code> or <code>certificate</code> is <code>null</code> then
- * the archive will not be signed.
- * @param out the {@link OutputStream} where to write the Jar archive.
- * @param key the {@link PrivateKey} used to sign the archive, or <code>null</code>.
- * @param certificate the {@link X509Certificate} used to sign the archive, or
- * <code>null</code>.
- * @throws IOException
- * @throws NoSuchAlgorithmException
- */
- public SignedJarBuilder(OutputStream out, PrivateKey key, X509Certificate certificate)
- throws IOException, NoSuchAlgorithmException {
- mOutputJar = new JarOutputStream(out);
- mOutputJar.setLevel(9);
- mKey = key;
- mCertificate = certificate;
-
- if (mKey != null && mCertificate != null) {
- mManifest = new Manifest();
- Attributes main = mManifest.getMainAttributes();
- main.putValue("Manifest-Version", "1.0");
- main.putValue("Created-By", "1.0 (Android)");
-
- mBase64Encoder = new BASE64Encoder();
- mMessageDigest = MessageDigest.getInstance(DIGEST_ALGORITHM);
- }
- }
-
- /**
- * Writes a new {@link File} into the archive.
- * @param inputFile the {@link File} to write.
- * @param jarPath the filepath inside the archive.
- * @throws IOException
- */
- public void writeFile(File inputFile, String jarPath) throws IOException {
- // Get an input stream on the file.
- FileInputStream fis = new FileInputStream(inputFile);
- try {
-
- // create the zip entry
- JarEntry entry = new JarEntry(jarPath);
- entry.setTime(inputFile.lastModified());
-
- writeEntry(fis, entry);
- } finally {
- // close the file stream used to read the file
- fis.close();
- }
- }
-
- /**
- * Copies the content of a Jar/Zip archive into the receiver archive.
- * <p/>An optional {@link IZipEntryFilter} allows to selectively choose which files
- * to copy over.
- * @param input the {@link InputStream} for the Jar/Zip to copy.
- * @param filter the filter or <code>null</code>
- * @throws IOException
- * @throws ZipAbortException if the {@link IZipEntryFilter} filter indicated that the write
- * must be aborted.
- */
- public void writeZip(InputStream input, IZipEntryFilter filter)
- throws IOException, ZipAbortException {
- ZipInputStream zis = new ZipInputStream(input);
-
- try {
- // loop on the entries of the intermediary package and put them in the final package.
- ZipEntry entry;
- while ((entry = zis.getNextEntry()) != null) {
- String name = entry.getName();
-
- // do not take directories or anything inside a potential META-INF folder.
- if (entry.isDirectory() || name.startsWith("META-INF/")) {
- continue;
- }
-
- // if we have a filter, we check the entry against it
- if (filter != null && filter.checkEntry(name) == false) {
- continue;
- }
-
- JarEntry newEntry;
-
- // Preserve the STORED method of the input entry.
- if (entry.getMethod() == JarEntry.STORED) {
- newEntry = new JarEntry(entry);
- } else {
- // Create a new entry so that the compressed len is recomputed.
- newEntry = new JarEntry(name);
- }
-
- writeEntry(zis, newEntry);
-
- zis.closeEntry();
- }
- } finally {
- zis.close();
- }
- }
-
- /**
- * Closes the Jar archive by creating the manifest, and signing the archive.
- * @throws IOException
- * @throws GeneralSecurityException
- */
- public void close() throws IOException, GeneralSecurityException {
- if (mManifest != null) {
- // write the manifest to the jar file
- mOutputJar.putNextEntry(new JarEntry(JarFile.MANIFEST_NAME));
- mManifest.write(mOutputJar);
-
- // CERT.SF
- Signature signature = Signature.getInstance("SHA1with" + mKey.getAlgorithm());
- signature.initSign(mKey);
- mOutputJar.putNextEntry(new JarEntry("META-INF/CERT.SF"));
- writeSignatureFile(new SignatureOutputStream(mOutputJar, signature));
-
- // CERT.*
- mOutputJar.putNextEntry(new JarEntry("META-INF/CERT." + mKey.getAlgorithm()));
- writeSignatureBlock(signature, mCertificate, mKey);
- }
-
- mOutputJar.close();
- mOutputJar = null;
- }
-
- /**
- * Clean up of the builder for interrupted workflow.
- * This does nothing if {@link #close()} was called successfully.
- */
- public void cleanUp() {
- if (mOutputJar != null) {
- try {
- mOutputJar.close();
- } catch (IOException e) {
- // pass
- }
- }
- }
-
- /**
- * Adds an entry to the output jar, and write its content from the {@link InputStream}
- * @param input The input stream from where to write the entry content.
- * @param entry the entry to write in the jar.
- * @throws IOException
- */
- private void writeEntry(InputStream input, JarEntry entry) throws IOException {
- // add the entry to the jar archive
- mOutputJar.putNextEntry(entry);
-
- // read the content of the entry from the input stream, and write it into the archive.
- int count;
- while ((count = input.read(mBuffer)) != -1) {
- mOutputJar.write(mBuffer, 0, count);
-
- // update the digest
- if (mMessageDigest != null) {
- mMessageDigest.update(mBuffer, 0, count);
- }
- }
-
- // close the entry for this file
- mOutputJar.closeEntry();
-
- if (mManifest != null) {
- // update the manifest for this entry.
- Attributes attr = mManifest.getAttributes(entry.getName());
- if (attr == null) {
- attr = new Attributes();
- mManifest.getEntries().put(entry.getName(), attr);
- }
- attr.putValue(DIGEST_ATTR, mBase64Encoder.encode(mMessageDigest.digest()));
- }
- }
-
- /** Writes a .SF file with a digest to the manifest. */
- private void writeSignatureFile(SignatureOutputStream out)
- throws IOException, GeneralSecurityException {
- Manifest sf = new Manifest();
- Attributes main = sf.getMainAttributes();
- main.putValue("Signature-Version", "1.0");
- main.putValue("Created-By", "1.0 (Android)");
-
- BASE64Encoder base64 = new BASE64Encoder();
- MessageDigest md = MessageDigest.getInstance(DIGEST_ALGORITHM);
- PrintStream print = new PrintStream(
- new DigestOutputStream(new ByteArrayOutputStream(), md),
- true, "UTF-8");
-
- // Digest of the entire manifest
- mManifest.write(print);
- print.flush();
- main.putValue(DIGEST_MANIFEST_ATTR, base64.encode(md.digest()));
-
- Map<String, Attributes> entries = mManifest.getEntries();
- for (Map.Entry<String, Attributes> entry : entries.entrySet()) {
- // Digest of the manifest stanza for this entry.
- print.print("Name: " + entry.getKey() + "\r\n");
- for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
- print.print(att.getKey() + ": " + att.getValue() + "\r\n");
- }
- print.print("\r\n");
- print.flush();
-
- Attributes sfAttr = new Attributes();
- sfAttr.putValue(DIGEST_ATTR, base64.encode(md.digest()));
- sf.getEntries().put(entry.getKey(), sfAttr);
- }
-
- sf.write(out);
-
- // A bug in the java.util.jar implementation of Android platforms
- // up to version 1.6 will cause a spurious IOException to be thrown
- // if the length of the signature file is a multiple of 1024 bytes.
- // As a workaround, add an extra CRLF in this case.
- if ((out.size() % 1024) == 0) {
- out.write('\r');
- out.write('\n');
- }
- }
-
- /** Write the certificate file with a digital signature. */
- private void writeSignatureBlock(Signature signature, X509Certificate publicKey,
- PrivateKey privateKey)
- throws IOException, GeneralSecurityException {
- SignerInfo signerInfo = new SignerInfo(
- new X500Name(publicKey.getIssuerX500Principal().getName()),
- publicKey.getSerialNumber(),
- AlgorithmId.get(DIGEST_ALGORITHM),
- AlgorithmId.get(privateKey.getAlgorithm()),
- signature.sign());
-
- PKCS7 pkcs7 = new PKCS7(
- new AlgorithmId[] { AlgorithmId.get(DIGEST_ALGORITHM) },
- new ContentInfo(ContentInfo.DATA_OID, null),
- new X509Certificate[] { publicKey },
- new SignerInfo[] { signerInfo });
-
- pkcs7.encodeSignedData(mOutputJar);
- }
-}