Felix
  1. Felix
  2. FELIX-3610

Bundle signatures should be checked when the framework is restarted

    Details

      Description

      Signed bundles are only checked when installed, but the goal of signed bundles is to make sure no one has changed the jar. This is not ensured unless bundle entries are verified when loaded.

        Activity

        Hide
        Guillaume Nodet added a comment -

        Note that the benefit of signing is that those bundles are actually secured. In my case, only signed bundles can be accessed at runtime – this can be checked using Bundle#getSignerCertificates(). So the verification is important to ensure that only signed code can be accessed at runtime.

        Show
        Guillaume Nodet added a comment - Note that the benefit of signing is that those bundles are actually secured. In my case, only signed bundles can be accessed at runtime – this can be checked using Bundle#getSignerCertificates(). So the verification is important to ensure that only signed code can be accessed at runtime.
        Hide
        Guillaume Nodet added a comment -

        I initially tried using a JarInputStream instead of a ZipInputStream, which would only partially work, as it won't handle the Bundle-ClassPath correctly wrt to signatures.
        I guess the only way is to do the same as Equinox, i.e. wrap the InputStream of the content entry and perform the check against the digest stored in the manifest when the end of the stream is reached.

        Show
        Guillaume Nodet added a comment - I initially tried using a JarInputStream instead of a ZipInputStream, which would only partially work, as it won't handle the Bundle-ClassPath correctly wrt to signatures. I guess the only way is to do the same as Equinox, i.e. wrap the InputStream of the content entry and perform the check against the digest stored in the manifest when the end of the stream is reached.
        Hide
        Karl Pauls added a comment -

        I guess I'm not sure what you are saying. Basically, everytime a bundle is installed or reloaded we verify its signatures on all its entries.  Not only when it is installed the first time.

        Doing a check everytime an entry is loaded from the jar doesn't make much sense to me. We verified the entries already - why do it again?

        The only reason I can see would be that you don't trust your own cache (i.e., somebody could manipulate entries inside the cache while the framework is running) and in that case, all bets are off anyways. Besides, It'd be teribble slow too, I imagine.

        Show
        Karl Pauls added a comment - I guess I'm not sure what you are saying. Basically, everytime a bundle is installed or reloaded we verify its signatures on all its entries.  Not only when it is installed the first time. Doing a check everytime an entry is loaded from the jar doesn't make much sense to me. We verified the entries already - why do it again? The only reason I can see would be that you don't trust your own cache (i.e., somebody could manipulate entries inside the cache while the framework is running) and in that case, all bets are off anyways. Besides, It'd be teribble slow too, I imagine.
        Hide
        Guillaume Nodet added a comment - - edited

        That's exactly the reason, to make sure bundles are not modified.

        I don't think all bets are off because you can verify the signatures. Signatures of trusted sources can't be changed unless you know the private key to sign those. So either you unsign the bundle (and it will be known because the bundle won't return signatures) or you sign it with a different source which you'll know too.

        The cpu consumption would only be there for signed bundles, and that's only about computing the checksum of the zip entry, which is quite fast, there's no real cryptography involved here, so I don't think that's a problem. Besides, that's a decision for the user to take.

        The use case, to give a bit more background, is to give a trusted framework to a third party so that it will use it, but we need to ensure some stuff can't be modified by this third party. We don't trust the third party to not hack with our framework, so we need to secure it.

        Imagine a payment application where you provide a service that will do some billing. You don't want the third party to start hacking the bundle in order to bypass the billing for example

        Show
        Guillaume Nodet added a comment - - edited That's exactly the reason, to make sure bundles are not modified. I don't think all bets are off because you can verify the signatures. Signatures of trusted sources can't be changed unless you know the private key to sign those. So either you unsign the bundle (and it will be known because the bundle won't return signatures) or you sign it with a different source which you'll know too. The cpu consumption would only be there for signed bundles, and that's only about computing the checksum of the zip entry, which is quite fast, there's no real cryptography involved here, so I don't think that's a problem. Besides, that's a decision for the user to take. The use case, to give a bit more background, is to give a trusted framework to a third party so that it will use it, but we need to ensure some stuff can't be modified by this third party. We don't trust the third party to not hack with our framework, so we need to secure it. Imagine a payment application where you provide a service that will do some billing. You don't want the third party to start hacking the bundle in order to bypass the billing for example
        Hide
        Guillaume Nodet added a comment -

        One question though, did the check changed from 3.x to 4.x ?
        Could that be the case that in 3.x the check was only done at installation time and not when reloaded ?

        Show
        Guillaume Nodet added a comment - One question though, did the check changed from 3.x to 4.x ? Could that be the case that in 3.x the check was only done at installation time and not when reloaded ?
        Hide
        Richard S. Hall added a comment -

        If you assume that they can modify the bundles at run time, then you can't assume they are not modifying the framework JAR at run time too. So, they could just modify away any checks that we do.

        Show
        Richard S. Hall added a comment - If you assume that they can modify the bundles at run time, then you can't assume they are not modifying the framework JAR at run time too. So, they could just modify away any checks that we do.
        Hide
        Guillaume Nodet added a comment -

        Here's the problem I have.

        #1 I install a signed bundle. Signatures are verified, all good.
        #2 Stop Felix
        #3 Tamper with the jar (change a class in the jar without changing the signatures)
        #4 Restart

        The restart happen with no exceptions. It may be a timing issue because the activator of the security stuff isn't started yet or something else, but that happens.
        I thought it was because the check was only done at installation time, which is not the case according to what you say (as it should be done when restarting too).

        Still, there's a problem.

        Show
        Guillaume Nodet added a comment - Here's the problem I have. #1 I install a signed bundle. Signatures are verified, all good. #2 Stop Felix #3 Tamper with the jar (change a class in the jar without changing the signatures) #4 Restart The restart happen with no exceptions. It may be a timing issue because the activator of the security stuff isn't started yet or something else, but that happens. I thought it was because the check was only done at installation time, which is not the case according to what you say (as it should be done when restarting too). Still, there's a problem.
        Hide
        Karl Pauls added a comment -

        How are you verifying the signatures? I assume you have a BundleSignerCondition or something?

        Show
        Karl Pauls added a comment - How are you verifying the signatures? I assume you have a BundleSignerCondition or something?
        Hide
        Guillaume Nodet added a comment - - edited

        Not sure, I'm not designing this myself, I can ask.

        I guess if bundles were actually verified when restarting, that would really help at least, though, it looks to me that in terms of performance doing the check at runtime instead would be more efficient (and more secured obviously).

        Show
        Guillaume Nodet added a comment - - edited Not sure, I'm not designing this myself, I can ask. I guess if bundles were actually verified when restarting, that would really help at least, though, it looks to me that in terms of performance doing the check at runtime instead would be more efficient (and more secured obviously).
        Hide
        Guillaume Nodet added a comment -

        Also, if the signatures are checked when the revision is created, only, I think there's still a hole: I could stop and refresh the bundle (signature check when refreshing). At this point, the bundle is unresolved and I can tamper with it easily. Then I restart the bundle, there's a good change I can change the contents without being noticed.

        Show
        Guillaume Nodet added a comment - Also, if the signatures are checked when the revision is created, only, I think there's still a hole: I could stop and refresh the bundle (signature check when refreshing). At this point, the bundle is unresolved and I can tamper with it easily. Then I restart the bundle, there's a good change I can change the contents without being noticed.
        Hide
        Richard S. Hall added a comment -

        I think the way it is supposed to work is like this:

        1. The framework assigns signer certificates to a bundle when it is installed or reloaded.
        1.a) If the bundle is improperly signed then no certificates will be granted to it.
        2. Permissions are granted to the bundle based on its signer certificates.
        2.a) Properly signed bundles will get their correct permissions assigned to them since they have the correct certificates.
        2.b) Improperly signed bundles will get default/no permissions assigned to them since they do not have the correct certificates.

        The only case that might be an issue is if you have a condition that says only bundles signed by Foo can be installed. In this case, if the cache was messed with, you might see bundles with no Foo certificate installed. The framework won't delete these bundles, but it doesn't give them certificates either. In that case, you can delete them yourself or make sure their permissions are empty.

        Show
        Richard S. Hall added a comment - I think the way it is supposed to work is like this: 1. The framework assigns signer certificates to a bundle when it is installed or reloaded. 1.a) If the bundle is improperly signed then no certificates will be granted to it. 2. Permissions are granted to the bundle based on its signer certificates. 2.a) Properly signed bundles will get their correct permissions assigned to them since they have the correct certificates. 2.b) Improperly signed bundles will get default/no permissions assigned to them since they do not have the correct certificates. The only case that might be an issue is if you have a condition that says only bundles signed by Foo can be installed. In this case, if the cache was messed with, you might see bundles with no Foo certificate installed. The framework won't delete these bundles, but it doesn't give them certificates either. In that case, you can delete them yourself or make sure their permissions are empty.
        Hide
        Guillaume Nodet added a comment -

        Bundle permissions are not really the concern here.

        I think there are two problems here:

        • the fact that bundles are not checked when the framework restarts (the security provider is registered too late), so they should, but they're not
        • the fact that after a bundle has been verified successfully, it can be tampered in the cache before resources are actually loaded (especially while in the installed state, before being resolved)

        In terms of security and performances, I still think that checking the signatures lazily at runtime when resources are loaded instead of at installation time would be better imho.

        Show
        Guillaume Nodet added a comment - Bundle permissions are not really the concern here. I think there are two problems here: the fact that bundles are not checked when the framework restarts (the security provider is registered too late), so they should, but they're not the fact that after a bundle has been verified successfully, it can be tampered in the cache before resources are actually loaded (especially while in the installed state, before being resolved) In terms of security and performances, I still think that checking the signatures lazily at runtime when resources are loaded instead of at installation time would be better imho.
        Hide
        Karl Pauls added a comment -

        Regarding the theory, I can see that there are bigger or smaller attack windows depending on what we do.

        However, if you give the framework to an untrusted third party which has full access to the framework cache there is no way you can guaranty anything. This is not the only point of attack, there are tons of others and I don't even see a way to eliminate them completely no matter how hard we would try.

        If you can trust your cache then our approach is fine.

        I guess it would really help if you could figure out what it is they do exactly. Let's try to figure out if we can address their concrete problem first.

        Show
        Karl Pauls added a comment - Regarding the theory, I can see that there are bigger or smaller attack windows depending on what we do. However, if you give the framework to an untrusted third party which has full access to the framework cache there is no way you can guaranty anything. This is not the only point of attack, there are tons of others and I don't even see a way to eliminate them completely no matter how hard we would try. If you can trust your cache then our approach is fine. I guess it would really help if you could figure out what it is they do exactly. Let's try to figure out if we can address their concrete problem first.
        Hide
        Karl Pauls added a comment -

        The security provider it not installed too late.

        I don't know why you think that - are you assuming the framwork would somehow reject bundles that are not signed correctly by itself? That is not the case no matter what.

        Show
        Karl Pauls added a comment - The security provider it not installed too late. I don't know why you think that - are you assuming the framwork would somehow reject bundles that are not signed correctly by itself? That is not the case no matter what.
        Hide
        Karl Pauls added a comment -

        Ok, after talking about this via skype some more I think we identfied a bug that is involved in all of this. I'll try to get to it asap and report back. Hopefully, it will address this issue somewhat (although, it will not fix the underlying issue which is that we can't have an untrusted cache).

        Show
        Karl Pauls added a comment - Ok, after talking about this via skype some more I think we identfied a bug that is involved in all of this. I'll try to get to it asap and report back. Hopefully, it will address this issue somewhat (although, it will not fix the underlying issue which is that we can't have an untrusted cache).
        Hide
        Karl Pauls added a comment -

        I commited a patch to trunk in r1366063. Can you try whether that helps you any? Thanks.

        Show
        Karl Pauls added a comment - I commited a patch to trunk in r1366063. Can you try whether that helps you any? Thanks.
        Hide
        Guillaume Nodet added a comment -

        It seems to work from my first tests, though a spurious exception is printed when the security provider checks its own bundle.
        I think the reason is that the Module associated is the one from the host (i.e. system bundle) which has no content. Not really sure though.
        I suppose that one needs to be bypassed somehow.

        java.io.IOException: Missing entry
        at org.apache.felix.framework.security.util.BundleInputStream.readNext(BundleInputStream.java:160)
        at org.apache.felix.framework.security.util.BundleInputStream.<init>(BundleInputStream.java:89)
        at org.apache.felix.framework.security.verifier.BundleDNParser._getDNChains(BundleDNParser.java:240)
        at org.apache.felix.framework.security.verifier.BundleDNParser.getDNChains(BundleDNParser.java:209)
        at org.apache.felix.framework.SecurityProviderImpl.getSignerMatcher(SecurityProviderImpl.java:74)
        at org.apache.felix.framework.Felix.setBundleProtectionDomain(Felix.java:851)
        at org.apache.felix.framework.Felix.init(Felix.java:801)
        at org.apache.karaf.main.Main.launch(Main.java:277)
        at org.apache.karaf.main.Main.main(Main.java:480)

        The exception itself is harmless but it really looks bad

        I'll do more thorough checks later.

        Show
        Guillaume Nodet added a comment - It seems to work from my first tests, though a spurious exception is printed when the security provider checks its own bundle. I think the reason is that the Module associated is the one from the host (i.e. system bundle) which has no content. Not really sure though. I suppose that one needs to be bypassed somehow. java.io.IOException: Missing entry at org.apache.felix.framework.security.util.BundleInputStream.readNext(BundleInputStream.java:160) at org.apache.felix.framework.security.util.BundleInputStream.<init>(BundleInputStream.java:89) at org.apache.felix.framework.security.verifier.BundleDNParser._getDNChains(BundleDNParser.java:240) at org.apache.felix.framework.security.verifier.BundleDNParser.getDNChains(BundleDNParser.java:209) at org.apache.felix.framework.SecurityProviderImpl.getSignerMatcher(SecurityProviderImpl.java:74) at org.apache.felix.framework.Felix.setBundleProtectionDomain(Felix.java:851) at org.apache.felix.framework.Felix.init(Felix.java:801) at org.apache.karaf.main.Main.launch(Main.java:277) at org.apache.karaf.main.Main.main(Main.java:480) The exception itself is harmless but it really looks bad I'll do more thorough checks later.
        Hide
        Guillaume Nodet added a comment -
        Show
        Guillaume Nodet added a comment - I've fixed the exception in http://svn.apache.org/viewvc?rev=1366177&view=rev
        Hide
        Karl Pauls added a comment -

        Good catch, last minute refactoring where i was moving the creation from the bundleimpl to felix. Thanks.

        Show
        Karl Pauls added a comment - Good catch, last minute refactoring where i was moving the creation from the bundleimpl to felix. Thanks.

          People

          • Assignee:
            Karl Pauls
            Reporter:
            Guillaume Nodet
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development