summaryrefslogtreecommitdiff
path: root/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java')
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java
new file mode 100644
index 0000000..669cf70
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.bouncycastle.util.encoders.Base64Encoder;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.packaging.PackageFile;
+
+/**
+ * This class implements the package signature file, that follows the jar
+ * signing process.
+ */
+public class SignatureFile
+{
+ /**
+ * The package file
+ */
+ private final PackageFile packageFile;
+
+ /**
+ * The base encoder
+ */
+ private Base64Encoder encoder = new Base64Encoder();
+
+ /**
+ * Manifest Created-By attribute
+ */
+ private final String createdBy;
+
+ /**
+ * Default Constructor
+ *
+ * @param packageFile
+ * the signed package file to be signed
+ * @param alias
+ * the certificate alias
+ * @param encoder
+ * the BASE64 encoder
+ * @param createdBy
+ * Created-By manifest attribute
+ */
+ public SignatureFile(PackageFile packageFile, String alias, Base64Encoder encoder,
+ String createdBy)
+ {
+ this.packageFile = packageFile;
+ this.encoder = encoder;
+ this.createdBy = createdBy;
+ }
+
+ /**
+ * Return the filename with relative path from root (normally
+ * META-INF/alias.SF).
+ */
+ @Override
+ public String toString()
+ {
+ return CertificateManagerActivator.METAFILES_DIR
+ + CertificateManagerActivator.JAR_SEPARATOR + ISignConstants.SIGNATURE_FILE_NAME
+ + ISignConstants.SIGNATURE_FILE_NAME_EXTENSION;
+
+ }
+
+ /**
+ * Writes this file to an output stream.
+ *
+ * @param outputStream
+ * the stream to write this file
+ * @throws IOException
+ * if an I/O error occurs during the signing process
+ * @throws SignException
+ * if a processing error occurs during the signing process
+ */
+ public void write(OutputStream outputStream) throws IOException, SignException
+ {
+ // the manifest file
+ Manifest manifestFile = this.packageFile.getManifest();
+
+ // the manifest digester
+ ManifestDigester manifestDigester = new ManifestDigester(manifestFile);
+
+ // the signature file to be constructed
+ Manifest signatureFile = new Manifest();
+
+ // the manifest digested main attributes
+ byte[] digestedMainAttributes = manifestDigester.getDigestedManifestMainAttributes();
+
+ // the digest of entire manifest
+ byte[] digestedManifest = manifestDigester.getDigestedManifest();
+
+ // put the required main attributes to a valid signature file
+ // (Version, CreatedBy, Main Attrib digest, Manifest digest)
+ Attributes signatureFileMainAtt = signatureFile.getMainAttributes();
+ signatureFileMainAtt.putValue(ISignConstants.SIGNATURE_VERSION_KEY,
+ ISignConstants.SIGNATURE_VERSION_VALUE);
+ signatureFileMainAtt.putValue(CertificateManagerActivator.CREATED_BY_FIELD, this.createdBy);
+
+ ByteArrayOutputStream stream = null;
+
+ try
+ {
+ stream = new ByteArrayOutputStream();
+ encoder.encode(digestedMainAttributes, 0, digestedMainAttributes.length, stream);
+ String encodedMainAttributesDigest = stream.toString();
+
+ stream.reset();
+ encoder.encode(digestedManifest, 0, digestedManifest.length, stream);
+ String encodedManifestDigest = stream.toString();
+
+ signatureFileMainAtt.putValue(ISignConstants.SHA1_DIGEST_MANIFEST_MAIN,
+ encodedMainAttributesDigest);
+ signatureFileMainAtt.putValue(ISignConstants.SHA1_DIGEST_MANIFEST,
+ encodedManifestDigest);
+ }
+ finally
+ {
+ if (stream != null)
+ {
+ try
+ {
+ stream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream writing signature file. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ // calculate the digest from each entry of manifest
+ ByteArrayOutputStream baos = null;
+ try
+ {
+ baos = new ByteArrayOutputStream();
+ manifestFile.write(baos);
+
+ Map<String, Attributes> manifestEntries = manifestFile.getEntries();
+ Map<String, Attributes> signatureFileEntries = signatureFile.getEntries();
+ HashMap<String, ManifestEntry> entries = manifestDigester.getEntries();
+
+ for (String manifestEntryKey : manifestEntries.keySet())
+ {
+ ManifestEntry signatureFileEntry = entries.get(manifestEntryKey);
+
+ byte[] digestedArray = signatureFileEntry.digest();
+
+ ByteArrayOutputStream encodedStream = null;
+
+ try
+ {
+ encodedStream = new ByteArrayOutputStream();
+ this.encoder.encode(digestedArray, 0, digestedArray.length, encodedStream);
+
+ String digestedValue = encodedStream.toString();
+
+ Attributes signatureFileAtt = new Attributes();
+ signatureFileAtt.putValue(ISignConstants.SHA1_DIGEST, digestedValue);
+ signatureFileEntries.put(manifestEntryKey, signatureFileAtt);
+ }
+ finally
+ {
+ try
+ {
+ if (encodedStream != null)
+ {
+ encodedStream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream: " + e.getMessage());
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(SignatureFile.class,
+ "I/O error digesting manifest entries: " + e.getMessage());
+
+ throw new SignException("I/O error digesting manifest entries", e);
+ }
+ finally
+ {
+ try
+ {
+ if (baos != null)
+ {
+ baos.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream: " + e.getMessage());
+ }
+ }
+
+ // I/O exceptions below are thrown unmodified
+ signatureFile.write(outputStream);
+
+ StudioLogger.info(SignatureFile.class, "Signature file was written");
+ }
+}