Smack 4.4.6: Build Fresh Session With Device on Invalid Key Exception

Below is the detailed observations during aTalk system testing:

a. When an omemo message is sent from swan@atalk.syste.net to swordfish@atalk.sytes.net
b swordfish complains not valid session found.
c. So it proceeds to perform OmemoService#buildFreshSessionWithDevice().
d. However this attempt failed during SignalOmemoService#processBundle(); the
Curve.verifySignature(preKey.getIdentityKey().getPublicKey(), preKey.getSignedPreKey().serialize(), preKey.getSignedPreKeySignature())) return false hence throws an InvalidKeyException.
e. This leads to aTalk get locked in this state unable to recover itself; it is now impossible to exchange omemo messages between swan and swordfish.

However It was found that exchange of omemo messages between leopard@atalk.sytes.net and swan has no problem.

Wonder if the swan bundle on server is ready corrupted, so aTalk forces smack OmemoService#buildFreshSessionWithDevice() to proceed even with InvalidKeyException; by changing the following source i.e. invert Curve.verifySignature check result:

  public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException {
    synchronized (SessionCipher.SESSION_LOCK) {
      if (!identityKeyStore.isTrustedIdentity(remoteAddress, preKey.getIdentityKey(), IdentityKeyStore.Direction.SENDING)) {
        throw new UntrustedIdentityException(remoteAddress.getName(), preKey.getIdentityKey());
      }

      if (preKey.getSignedPreKey() != null &&
          Curve.verifySignature(preKey.getIdentityKey().getPublicKey(),
                                 preKey.getSignedPreKey().serialize(),
                                 preKey.getSignedPreKeySignature()))
      {
        throw new InvalidKeyException("Invalid signature on device key!");
      }

      if (preKey.getSignedPreKey() == null) {
        throw new InvalidKeyException("No signed prekey!");
      }
....
}

After the above changes to temporary allow aTalk to rebuild the session, It is found that aTalk is able to recover form the earlier locked state. The exchange of omemo messages between swan and swordfish is now full working.

No sure why Curve.verifySignature() return false. Any comment?

Hm this is a tricky one.
Since the Curve.verifySignature() call is invoked using only elements from swans prekey bundle, I’d assume that the bundle is somehow corrupted.
Not sure, if this is because of corruption that happened on the server, or during client-side processing of the data structure though.

I believe swan prekey bundle corruption is on swordfish local database.
I have restart aTalk for both swan and swordfish multiple times. I found that aTalk will set/update its prekeys to the server whenever it restarted. But restart of the aTalk swan does not resolve the problem.

Few questions need your clarifications.
a. Does the swan prekey bundle being loaded only once, and when?
b. Or it will be get updated on certain conditions, and which are the conditions?
c. Is there a function call by aTalk app to force reload of the swan prekey bundle?

The same exact problem happen again between swan and swordfish, while doing aTalk system testing. If I can recall, the last thing I do is to erase all the swan chat history messages on swordfish device, but cannot ascertain if this is the real cause.

As mentioned in my first comment.
e. This leads to aTalk get locked in this state unable to recover itself; it is now IMPOSSIBLE to exchange omemo messages between swan and swordfish.

I found that, the only way to get swordfish out of this locked state, is to get swan to regenerate the omemoDevice keys. This will force swordfish to reload the swan new keys. However this is certainly not practical in practice; to request your buddy swan to regenerate its omemoDevice keys, while the problem is on your swordfish device.

We really need to provide a solution for this, as the problems has happened multiple times >4? even during testing; I presume it may be worst in the field.

Since the problem is on swan prekey bundle corruption on swordfish local database; the possible solution is to get swordfish to reload swan prekey bundle from the server.
I appreciate if smack team can give me some hint/guidance on how to implement this for aTalk.