Skip to content

Commit

Permalink
Merge pull request #5268 from bjhargrave/jar-signing
Browse files Browse the repository at this point in the history
signing: Write META-INF signing resources immediately after manifest
  • Loading branch information
bjhargrave committed May 28, 2022
2 parents 02fa8fd + 37e7d2d commit 1e03d93
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 238 deletions.
16 changes: 8 additions & 8 deletions biz.aQute.bndlib/src/aQute/bnd/differ/DiffPluginImpl.java
@@ -1,5 +1,6 @@
package aQute.bnd.differ;

import static aQute.bnd.osgi.Jar.METAINF_SIGNING_P;
import static aQute.bnd.service.diff.Delta.CHANGED;

import java.io.File;
Expand All @@ -13,7 +14,6 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.Manifest;
import java.util.regex.Pattern;

import aQute.bnd.header.Attrs;
import aQute.bnd.header.OSGiHeader;
Expand Down Expand Up @@ -129,8 +129,6 @@ private Element bundleElement(Analyzer analyzer) throws Exception {
/**
* Create an element representing all resources in the JAR
*/
private final static Pattern META_INF_P = Pattern.compile("META-INF/([^/]+\\.(MF|SF|DSA|RSA))|(SIG-.*)");

private Element resourcesElement(Analyzer analyzer) throws Exception {
Jar jar = analyzer.getJar();

Expand All @@ -139,16 +137,20 @@ private Element resourcesElement(Analyzer analyzer) throws Exception {
for (Map.Entry<String, Resource> entry : jar.getResources()
.entrySet()) {

String path = entry.getKey();
//
// The manifest and other (signer) files are ignored
// since they are extremely sensitive to time
//

if (META_INF_P.matcher(entry.getKey())
.matches())
if (jar.getManifestName()
.equals(path)
|| METAINF_SIGNING_P.matcher(path)
.matches()) {
continue;
}

if (localIgnore != null && localIgnore.matches(entry.getKey()))
if (localIgnore != null && localIgnore.matches(path))
continue;

//
Expand All @@ -159,8 +161,6 @@ private Element resourcesElement(Analyzer analyzer) throws Exception {
// directory with source code can be found.
//

String path = entry.getKey();

if (path.endsWith(Constants.EMPTY_HEADER))
continue;

Expand Down
3 changes: 2 additions & 1 deletion biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java
Expand Up @@ -24,6 +24,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -1345,7 +1346,7 @@ private boolean addAll(Jar to, Jar sub, Instruction filter, String destination,
boolean dupl = false;
for (String name : sub.getResources()
.keySet()) {
if ("META-INF/MANIFEST.MF".equals(name))
if (JarFile.MANIFEST_NAME.equals(name))
continue;

if (doNotCopy(Strings.getLastSegment(name, '/')))
Expand Down
40 changes: 30 additions & 10 deletions biz.aQute.bndlib/src/aQute/bnd/osgi/Jar.java
Expand Up @@ -41,6 +41,7 @@
import java.util.function.Predicate;
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.regex.Matcher;
Expand Down Expand Up @@ -96,7 +97,6 @@ public enum Compression {
STORE
}

private static final String DEFAULT_MANIFEST_NAME = "META-INF/MANIFEST.MF";
private static final Pattern DEFAULT_DO_NOT_COPY = Pattern
.compile(Constants.DEFAULT_DO_NOT_COPY);

Expand All @@ -106,7 +106,7 @@ public enum Compression {
private Optional<Manifest> manifest;
private Optional<ModuleAttribute> moduleAttribute;
private boolean manifestFirst;
private String manifestName = DEFAULT_MANIFEST_NAME;
private String manifestName = JarFile.MANIFEST_NAME;
private String name;
private File source;
private ZipFile zipFile;
Expand All @@ -122,6 +122,8 @@ public enum Compression {
private boolean calculateFileDigest;
private int fileLength = -1;
private long zipEntryConstantTime = ZIP_ENTRY_CONSTANT_TIME;
public static final Pattern METAINF_SIGNING_P = Pattern
.compile("META-INF/([^/]+\\.(?:DSA|RSA|EC|SF)|SIG-[^/]+)", Pattern.CASE_INSENSITIVE);

public Jar(String name) {
this.name = name;
Expand Down Expand Up @@ -590,6 +592,8 @@ public void write(OutputStream to) throws Exception {
Set<String> done = new HashSet<>();

Set<String> directories = new HashSet<>();

// Write manifest first
if (doNotTouchManifest) {
Resource r = getResource(manifestName);
if (r != null) {
Expand All @@ -601,6 +605,22 @@ public void write(OutputStream to) throws Exception {
done.add(manifestName);
}

// Then write any signature info next since JarInputStream really cares!
Map<String, Resource> metainf = getDirectory("META-INF");
if (metainf != null) {
List<String> signing = metainf.keySet()
.stream()
.filter(path -> METAINF_SIGNING_P.matcher(path)
.matches())
.collect(toList());
for (String path : signing) {
if (done.add(path)) {
writeResource(jout, directories, path, metainf.get(path));
}
}
}

// Write all remaining entries
for (Map.Entry<String, Resource> entry : getResources().entrySet()) {
// Skip metainf contents
if (!done.contains(entry.getKey()))
Expand Down Expand Up @@ -1245,16 +1265,16 @@ public byte[] getTimelessDigest() throws Exception {
return md.digest();
}

private final static Pattern SIGNER_FILES_P = Pattern.compile("(.+\\.(SF|DSA|RSA))|(.*/SIG-.*)",
Pattern.CASE_INSENSITIVE);

public void stripSignatures() {
Map<String, Resource> map = getDirectory("META-INF");
if (map != null) {
for (String file : new HashSet<>(map.keySet())) {
if (SIGNER_FILES_P.matcher(file)
Map<String, Resource> metainf = getDirectory("META-INF");
if (metainf != null) {
List<String> signing = metainf.keySet()
.stream()
.filter(path -> METAINF_SIGNING_P.matcher(path)
.matches())
remove(file);
.collect(toList());
for (String path : signing) {
remove(path);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion biz.aQute.bndlib/src/aQute/bnd/osgi/Verifier.java
Expand Up @@ -16,6 +16,7 @@
import java.util.TreeSet;
import java.util.function.Function;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -1461,7 +1462,7 @@ public void verifyChecksums(boolean all) throws Exception {

for (String path : dot.getResources()
.keySet()) {
if (path.equals("META-INF/MANIFEST.MF"))
if (path.equals(JarFile.MANIFEST_NAME))
continue;

Attributes a = m.getAttributes(path);
Expand Down
13 changes: 9 additions & 4 deletions biz.aQute.bndlib/src/aQute/bnd/signing/JartoolSigner.java
@@ -1,11 +1,13 @@
package aQute.bnd.signing;

import static aQute.bnd.osgi.Jar.METAINF_SIGNING_P;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -101,8 +103,6 @@ public void setRegistry(Registry registry) {
processor = registry.getPlugin(Processor.class);
}

private static Pattern SIGNING_P = Pattern.compile("META-INF/([^/]*\\.(DSA|RSA|EC|SF|MF)|SIG-[^/]*)");

@Override
public void sign(Builder builder, String alias) throws Exception {
File f = builder.getFile(keystore);
Expand All @@ -112,6 +112,11 @@ public void sign(Builder builder, String alias) throws Exception {
}

Jar jar = builder.getJar();
if (!jar.getManifestName()
.equals(JarFile.MANIFEST_NAME)) {
builder.error("Signing requires using the standard manifest name %s", JarFile.MANIFEST_NAME);
return;
}
File tmp = File.createTempFile("signedjar", ".jar");
tmp.deleteOnExit();

Expand Down Expand Up @@ -188,7 +193,7 @@ public void sign(Builder builder, String alias) throws Exception {
builder.addClose(signed);

MapStream.of(signed.getDirectory("META-INF"))
.filterKey(path -> SIGNING_P.matcher(path)
.filterKey(path -> JarFile.MANIFEST_NAME.equals(path) || METAINF_SIGNING_P.matcher(path)
.matches())
.forEachOrdered(jar::putResource);
jar.setDoNotTouchManifest();
Expand Down

0 comments on commit 1e03d93

Please sign in to comment.