669 // Should not happen. User provided alg were checked, and default |
669 // Should not happen. User provided alg were checked, and default |
670 // alg should always be available. |
670 // alg should always be available. |
671 throw new AssertionError(asae); |
671 throw new AssertionError(asae); |
672 } |
672 } |
673 |
673 |
674 PrintStream ps = new PrintStream(os); |
674 ZipOutputStream zos = new ZipOutputStream(os); |
675 ZipOutputStream zos = new ZipOutputStream(ps); |
|
676 |
675 |
677 Manifest manifest = new Manifest(); |
676 Manifest manifest = new Manifest(); |
678 Map<String, Attributes> mfEntries = manifest.getEntries(); |
|
679 |
|
680 // The Attributes of manifest before updating |
|
681 Attributes oldAttr = null; |
|
682 |
|
683 boolean mfModified = false; |
|
684 boolean mfCreated = false; |
|
685 byte[] mfRawBytes = null; |
677 byte[] mfRawBytes = null; |
686 |
678 |
687 // Check if manifest exists |
679 // Check if manifest exists |
688 ZipEntry mfFile; |
680 ZipEntry mfFile = getManifestFile(zipFile); |
689 if ((mfFile = getManifestFile(zipFile)) != null) { |
681 boolean mfCreated = mfFile == null; |
|
682 if (!mfCreated) { |
690 // Manifest exists. Read its raw bytes. |
683 // Manifest exists. Read its raw bytes. |
691 mfRawBytes = zipFile.getInputStream(mfFile).readAllBytes(); |
684 mfRawBytes = zipFile.getInputStream(mfFile).readAllBytes(); |
692 manifest.read(new ByteArrayInputStream(mfRawBytes)); |
685 manifest.read(new ByteArrayInputStream(mfRawBytes)); |
693 oldAttr = (Attributes) (manifest.getMainAttributes().clone()); |
|
694 } else { |
686 } else { |
695 // Create new manifest |
687 // Create new manifest |
696 Attributes mattr = manifest.getMainAttributes(); |
688 Attributes mattr = manifest.getMainAttributes(); |
697 mattr.putValue(Attributes.Name.MANIFEST_VERSION.toString(), |
689 mattr.putValue(Attributes.Name.MANIFEST_VERSION.toString(), |
698 "1.0"); |
690 "1.0"); |
699 String javaVendor = System.getProperty("java.vendor"); |
691 String javaVendor = System.getProperty("java.vendor"); |
700 String jdkVersion = System.getProperty("java.version"); |
692 String jdkVersion = System.getProperty("java.version"); |
701 mattr.putValue("Created-By", jdkVersion + " (" + javaVendor |
693 mattr.putValue("Created-By", jdkVersion + " (" + javaVendor |
702 + ")"); |
694 + ")"); |
703 mfFile = new ZipEntry(JarFile.MANIFEST_NAME); |
695 mfFile = new ZipEntry(JarFile.MANIFEST_NAME); |
704 mfCreated = true; |
|
705 } |
696 } |
706 |
697 |
707 /* |
698 /* |
708 * For each entry in jar |
699 * For each entry in jar |
709 * (except for signature-related META-INF entries), |
700 * (except for signature-related META-INF entries), |
740 } |
735 } |
741 |
736 |
742 if (manifest.getAttributes(ze.getName()) != null) { |
737 if (manifest.getAttributes(ze.getName()) != null) { |
743 // jar entry is contained in manifest, check and |
738 // jar entry is contained in manifest, check and |
744 // possibly update its digest attributes |
739 // possibly update its digest attributes |
745 if (updateDigests(ze, zipFile, digests, |
740 updateDigests(ze, zipFile, digests, manifest); |
746 manifest)) { |
|
747 mfModified = true; |
|
748 } |
|
749 } else if (!ze.isDirectory()) { |
741 } else if (!ze.isDirectory()) { |
750 // Add entry to manifest |
742 // Add entry to manifest |
751 Attributes attrs = getDigestAttributes(ze, zipFile, digests); |
743 Attributes attrs = getDigestAttributes(ze, zipFile, digests); |
752 mfEntries.put(ze.getName(), attrs); |
744 manifest.getEntries().put(ze.getName(), attrs); |
753 mfModified = true; |
745 } |
754 } |
746 } |
755 } |
747 |
756 |
748 /* |
757 // Recalculate the manifest raw bytes if necessary |
749 * Note: |
758 if (mfModified) { |
750 * |
759 ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
751 * The Attributes object is based on HashMap and can handle |
|
752 * continuation lines. Therefore, even if the contents are not changed |
|
753 * (in a Map view), the bytes that it write() may be different from |
|
754 * the original bytes that it read() from. Since the signature is |
|
755 * based on raw bytes, we must retain the exact bytes. |
|
756 */ |
|
757 boolean mfModified; |
|
758 ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
|
759 if (mfCreated || !wasSigned) { |
|
760 mfModified = true; |
760 manifest.write(baos); |
761 manifest.write(baos); |
761 if (wasSigned) { |
762 mfRawBytes = baos.toByteArray(); |
762 byte[] newBytes = baos.toByteArray(); |
763 } else { |
763 if (mfRawBytes != null |
764 |
764 && oldAttr.equals(manifest.getMainAttributes())) { |
765 // the manifest before updating |
765 |
766 Manifest oldManifest = new Manifest( |
766 /* |
767 new ByteArrayInputStream(mfRawBytes)); |
767 * Note: |
768 mfModified = !oldManifest.equals(manifest); |
768 * |
769 if (!mfModified) { |
769 * The Attributes object is based on HashMap and can handle |
770 // leave whole manifest (mfRawBytes) unmodified |
770 * continuation columns. Therefore, even if the contents are |
771 } else { |
771 * not changed (in a Map view), the bytes that it write() |
772 // reproduce the manifest raw bytes for unmodified sections |
772 * may be different from the original bytes that it read() |
773 manifest.write(baos); |
773 * from. Since the signature on the main attributes is based |
774 byte[] mfNewRawBytes = baos.toByteArray(); |
774 * on raw bytes, we must retain the exact bytes. |
775 baos.reset(); |
775 */ |
776 |
776 |
777 ManifestDigester oldMd = new ManifestDigester(mfRawBytes); |
777 int newPos = findHeaderEnd(newBytes); |
778 ManifestDigester newMd = new ManifestDigester(mfNewRawBytes); |
778 int oldPos = findHeaderEnd(mfRawBytes); |
779 |
779 |
780 // main attributes |
780 if (newPos == oldPos) { |
781 if (manifest.getMainAttributes().equals( |
781 System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos); |
782 oldManifest.getMainAttributes()) |
|
783 && (manifest.getEntries().isEmpty() || |
|
784 oldMd.getMainAttsEntry().isProperlyDelimited())) { |
|
785 oldMd.getMainAttsEntry().reproduceRaw(baos); |
|
786 } else { |
|
787 newMd.getMainAttsEntry().reproduceRaw(baos); |
|
788 } |
|
789 |
|
790 // individual sections |
|
791 for (Map.Entry<String,Attributes> entry : |
|
792 manifest.getEntries().entrySet()) { |
|
793 String sectionName = entry.getKey(); |
|
794 Attributes entryAtts = entry.getValue(); |
|
795 if (entryAtts.equals(oldManifest.getAttributes(sectionName)) |
|
796 && oldMd.get(sectionName).isProperlyDelimited()) { |
|
797 oldMd.get(sectionName).reproduceRaw(baos); |
782 } else { |
798 } else { |
783 // cat oldHead newTail > newBytes |
799 newMd.get(sectionName).reproduceRaw(baos); |
784 byte[] lastBytes = new byte[oldPos + |
|
785 newBytes.length - newPos]; |
|
786 System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos); |
|
787 System.arraycopy(newBytes, newPos, lastBytes, oldPos, |
|
788 newBytes.length - newPos); |
|
789 newBytes = lastBytes; |
|
790 } |
800 } |
791 } |
801 } |
792 mfRawBytes = newBytes; |
802 |
793 } else { |
|
794 mfRawBytes = baos.toByteArray(); |
803 mfRawBytes = baos.toByteArray(); |
795 } |
804 } |
796 } |
805 } |
797 |
806 |
798 // Write out the manifest |
807 // Write out the manifest |
799 if (mfModified) { |
808 if (mfModified) { |
800 // manifest file has new length |
809 // manifest file has new length |
801 mfFile = new ZipEntry(JarFile.MANIFEST_NAME); |
810 mfFile = new ZipEntry(JarFile.MANIFEST_NAME); |
802 } |
811 } |
803 if (handler != null) { |
812 if (handler != null) { |
804 if (mfCreated) { |
813 if (mfCreated || !mfModified) { |
805 handler.accept("adding", mfFile.getName()); |
814 handler.accept("adding", mfFile.getName()); |
806 } else if (mfModified) { |
815 } else { |
807 handler.accept("updating", mfFile.getName()); |
816 handler.accept("updating", mfFile.getName()); |
808 } |
817 } |
809 } |
818 } |
810 |
|
811 zos.putNextEntry(mfFile); |
819 zos.putNextEntry(mfFile); |
812 zos.write(mfRawBytes); |
820 zos.write(mfRawBytes); |
813 |
821 |
814 // Calculate SignatureFile (".SF") and SignatureBlockFile |
822 // Calculate SignatureFile (".SF") and SignatureBlockFile |
815 ManifestDigester manDig = new ManifestDigester(mfRawBytes); |
823 ManifestDigester manDig = new ManifestDigester(mfRawBytes); |
887 for (int i = 0; i < mfFiles.size(); i++) { |
894 for (int i = 0; i < mfFiles.size(); i++) { |
888 ZipEntry ze = mfFiles.elementAt(i); |
895 ZipEntry ze = mfFiles.elementAt(i); |
889 if (!ze.getName().equalsIgnoreCase(JarFile.MANIFEST_NAME) |
896 if (!ze.getName().equalsIgnoreCase(JarFile.MANIFEST_NAME) |
890 && !ze.getName().equalsIgnoreCase(sfFilename) |
897 && !ze.getName().equalsIgnoreCase(sfFilename) |
891 && !ze.getName().equalsIgnoreCase(bkFilename)) { |
898 && !ze.getName().equalsIgnoreCase(bkFilename)) { |
|
899 if (ze.getName().startsWith(SignatureFile |
|
900 .getBaseSignatureFilesName(signerName)) |
|
901 && SignatureFileVerifier.isBlockOrSF(ze.getName())) { |
|
902 if (handler != null) { |
|
903 handler.accept("updating", ze.getName()); |
|
904 } |
|
905 continue; |
|
906 } |
892 if (handler != null) { |
907 if (handler != null) { |
893 if (manifest.getAttributes(ze.getName()) != null) { |
908 if (manifest.getAttributes(ze.getName()) != null) { |
894 handler.accept("signing", ze.getName()); |
909 handler.accept("signing", ze.getName()); |
895 } else if (!ze.isDirectory()) { |
910 } else if (!ze.isDirectory()) { |
896 handler.accept("adding", ze.getName()); |
911 handler.accept("adding", ze.getName()); |
1179 // Write .SF file |
1156 // Write .SF file |
1180 public void write(OutputStream out) throws IOException { |
1157 public void write(OutputStream out) throws IOException { |
1181 sf.write(out); |
1158 sf.write(out); |
1182 } |
1159 } |
1183 |
1160 |
|
1161 private static String getBaseSignatureFilesName(String baseName) { |
|
1162 return "META-INF/" + baseName + "."; |
|
1163 } |
|
1164 |
1184 // get .SF file name |
1165 // get .SF file name |
1185 public String getMetaName() { |
1166 public String getMetaName() { |
1186 return "META-INF/" + baseName + ".SF"; |
1167 return getBaseSignatureFilesName(baseName) + "SF"; |
1187 } |
1168 } |
1188 |
1169 |
1189 // get .DSA (or .DSA, .EC) file name |
1170 // get .DSA (or .DSA, .EC) file name |
1190 public String getBlockName(PrivateKey privateKey) { |
1171 public String getBlockName(PrivateKey privateKey) { |
1191 String keyAlgorithm = privateKey.getAlgorithm(); |
1172 String keyAlgorithm = privateKey.getAlgorithm(); |
1192 return "META-INF/" + baseName + "." + keyAlgorithm; |
1173 return getBaseSignatureFilesName(baseName) + keyAlgorithm; |
1193 } |
1174 } |
1194 |
1175 |
1195 // Generates the PKCS#7 content of block file |
1176 // Generates the PKCS#7 content of block file |
1196 @SuppressWarnings("deprecation") |
1177 @SuppressWarnings("deprecation") |
1197 public byte[] generateBlock(ContentSignerParameters params, |
1178 public byte[] generateBlock(ContentSignerParameters params, |