0

I have a webserver that serves OSGI bundles as self-signed jar files. These are downloaded and installed using the OSGI API on my devices. I have enabled security in knopflerfish OSGI and pointed it to a keystore with my public key. I want to verify that the code I download can not be tampered with in a MITM attack or otherwise.

To test this I tried to slightly change and recompile one of my bundles that I had previously signed and verified, unpacked the old, signed jar and the newly compiled jar using 7zip, and copied over the contents of META-INF folder, overwriting the still unsigned MANIFEST.MF and providing .SF and .RSA files. When I tried to download and install this jar file I indeed got an error:

[stderr] org.osgi.framework.BundleException: Failed to install bundle: java.io.IOException: MANIFEST.MF must be first in archive when using signatures.
[stderr]        at org.knopflerfish.framework.Bundles.install0(Bundles.java:178)
[stderr]        at org.knopflerfish.framework.SecurePermissionOps$14.run(SecurePermissionOps.java:727)
[stderr]        at org.knopflerfish.framework.SecurePermissionOps$14.run(SecurePermissionOps.java:723)
[stderr]        at java.security.AccessController.doPrivileged(Native Method)
[stderr]        at org.knopflerfish.framework.SecurePermissionOps.callInstall0(SecurePermissionOps.java:722)
[stderr]        at org.knopflerfish.framework.Bundles.install(Bundles.java:118)
[stderr]        at org.knopflerfish.framework.BundleContextImpl.installBundle(BundleContextImpl.java:109)
[stderr]        at no.aventi.sam.Activator.handleEvent(Activator.java:190)
[stderr]        at org.knopflerfish.bundle.event.TrackedEventHandler.handleEventSubjectToFilter(TrackedEventHandler.java:71)
[stderr]        at org.knopflerfish.bundle.event.InternalAdminEvent.deliverToHandles(InternalAdminEvent.java:153)
[stderr]        at org.knopflerfish.bundle.event.InternalAdminEvent.deliver(InternalAdminEvent.java:114)
[stderr]        at org.knopflerfish.bundle.event.QueueHandler.run(QueueHandler.java:120)
[stderr] Caused by: java.io.IOException: MANIFEST.MF must be first in archive when using signatures.
[stderr]        at org.knopflerfish.framework.bundlestorage.file.Archive.downloadArchive(Archive.java:271)
[stderr]        at org.knopflerfish.framework.bundlestorage.file.BundleArchiveImpl.<init>(BundleArchiveImpl.java:133)

[stderr]        at org.knopflerfish.framework.bundlestorage.file.BundleStorageImpl.insertBundleJar(BundleStorageImpl.java:219)
[stderr]        at org.knopflerfish.framework.Bundles.install0(Bundles.java:161)
[stderr]        ... 11 more

I also tried the other way around, to copy the new .class files into the correctly signed jar, and got the same error.

I'm not sure what output to expect for actual verification of the security scheme. Does the error I got mean that java detected the wrongful signature and rejected it because of that? Or does it simply mean that 7zip did not keep the structure intact when I manually wrote to the jar file, and a better hacker than me could still easily tamper with my jar files?

jarsigner -verify on the tampered jar files gives me java.lang.SecurityException: SHA-256 digest error which makes much more sense, can I expect this if I tamper with the jars 'correctly'?

karlsvan
  • 11
  • 5

3 Answers3

1

The exception tells you that the jar file is invalid. So it did not even try to validate the signature.

7zip is not suitable for creating / editing jar files. You should use the java jar tool. See https://www.webucator.com/how-to/how-create-jar-file-java.cfm

Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
1

The other answers were correct in that my jar file was invalidated by using 7zip without regard for file order, and thus security was not the issue I encountered when I got the error in the question. They did not directly answer how I should do it instead, so I will show how I got it working and accept my own answer.

I updated the signed jar with an edited .class file using the jar program in jdk instead of using 7zip:

jar.exe -uvf <jarfile.jar> </path/to/classfile.class>

this resulted in this error from java:

[stderr] java.lang.SecurityException: SHA-256 digest error for ****.class
[stderr]         at sun.security.util.ManifestEntryVerifier.verify(ManifestEntryVerifier.java:223)

which seems like a reasonable error for a class file which differs from the signature, and matches that of jarsigner -verify

karlsvan
  • 11
  • 5
0

One of the requirements of (signed) JARs is that the manifest is the first entry in the ZIP file. The reason is that the manifest contains the digests for the resources in the JAR in the Name section of the manifest.

 Name: foo/bar/Xyz.class
 Digest-SHA-1: 2A345C6D7890F2A345C6D7890F2A345C6D7890F
 Digest-MD5: 7890F2A345C6D789

These digests are necessary to load other resources and verify them. The signer file (.SF) contains a digest for this Name section also in manifest format. The .DSA or .RSA file then contains a signature for this .SF file.

If the manifest was not first, you could not stream the JAR, you would always have to copy it to disk and then open it from a File so you have random access. by forcing the Manifest first, the JarInputStream can load the resources when they arrive and verify them immediately. Unfortunately, the Jar signer tool is not based on the standard JDK cryptography library and is kind of odd in other ways. The reason you get a different error that it likely opens the JAR as a File and therefore can randomly access the Manifest, so it does not care that the manifest is not first.

The model is extremely flexible but also hard to understand. It allows for multiple signers that each can partially sign the bundle. OSGi added an extra requirement that partial signing is not used. Without this requirement, there was some security issue I recall.

Notice that anybody can add resources to your bundle and this will not be detected if they are not also added to the Name section in the manifest. However, any resource listed in the manifest must match the given digests.

Peter Kriens
  • 15,196
  • 1
  • 37
  • 55
  • This is interesting, would it be possible for attackers to execute such added resources in OSGI? for example by editing the Bundle-Activator field in the manifest to point to an added, hidden resource? or is the manifest 'digested' in the SF file and thus not possible to tamper with? I guess I could test this too – karlsvan Apr 23 '19 at 14:53
  • It is actually secure, also the manifest is a signed resource. – Peter Kriens May 06 '19 at 11:21