airsdk / Adobe-Runtime-Support

Report, track and discuss issues in Adobe AIR. Monitored by Adobe - and HARMAN - and maintained by the AIR community.
201 stars 11 forks source link

[macOS] Not signed/notarized app EncryptedLocalStore.setItem() call cause internal error #2253

Open itlancer opened 1 year ago

itlancer commented 1 year ago

Problem Description

Not signed/notarized macOS app EncryptedLocalStore.setItem() call cause Error: EncryptedLocalStore internal error.

It has been tested with multiple AIR versions, even latest AIR 50.0.1.1 with multiple macOS devices with different AIR applications with different OS versions (BigSur/Monterey) with different CPUs (Intel-based and M1). Same issue in all cases. There is no such issue with Animate/VSCode/ADL launching. There is no such issue with properly signed/notarized app (but still exists another issue https://github.com/airsdk/Adobe-Runtime-Support/discussions/2197#discussioncomment-3858609). There is no such issues with Windows/Linux/Android/iOS.

Related issues: https://github.com/airsdk/Adobe-Runtime-Support/issues/2011 https://github.com/airsdk/Adobe-Runtime-Support/discussions/2197 https://github.com/airsdk/Adobe-Runtime-Support/issues/781 https://github.com/airsdk/Adobe-Runtime-Support/issues/508 https://github.com/airsdk/Adobe-Runtime-Support/discussions/1225

Steps to Reproduce

Launch AIR application with code below for macOS device. It just call EncryptedLocalStore.setItem().

Application example with sources attached. macos_encrypted_local_store_bug.zip

package {
    import flash.display.Sprite;
    import flash.data.EncryptedLocalStore;
    import flash.utils.ByteArray;

    public class MacOEncryptedLocalStoreBug extends Sprite {

        public function MacOEncryptedLocalStoreBug() {
            var ba:ByteArray = new ByteArray();
            ba.writeBoolean(true);
            EncryptedLocalStore.setItem("test", ba);
        }

    }
}

Actual Result: Exception:

Error: EncryptedLocalStore internal error
Exception: flash.errors::IOError
flash.data::EncryptedLocalStore$/processErrorCode
flash.data::EncryptedLocalStore$/setItem

Expected Result: Successful EncryptedLocalStore.setItem() call. Or EncryptedLocalStore internal error should be expected and properly documented https://airsdk.dev/reference/actionscript/3.0/flash/data/EncryptedLocalStore.html#setItem(). May be EncryptedLocalStore.isSupported should return false if ELS could not work at all (but why?). If AIR app necessary to be properly signed/notarized - then adt should take care about it I think.

Known Workarounds

Manually sign and notarize application. https://github.com/airsdk/Adobe-Runtime-Support/discussions/2088#discussioncomment-3622583

barisyild commented 1 year ago

I am having the problem myself.

pis0 commented 4 months ago

same here.. 51.0.1.1

itlancer commented 2 months ago

@ajwfrost With AIR 51.0.1.4 all even worse for macOS (tested with multiple different devices, architectures and AIR applications). Right now with ADL and bundled/signed app results the same. Any first EncryptedLocalStore.getItem() or EncryptedLocalStore.setItem() call after application launch cause dialog window similar to https://github.com/airsdk/Adobe-Runtime-Support/issues/2011#issuecomment-1178141032 "My AIR App" wants to use your confidentional information stored in "Adobe_AIR_ELS" in your keychain. If Deny - you will get EncryptedLocalStore internal error for any further ELS call. If Allow - ELS calls works until next app launch. If Always Allow - all seems works fine with ELS. But sometimes additional similar window also appeared and empty password should be entered and also "Always Allow" should be clicked to work.

There shouldn't be any such windows. We can't force our users to enter their passwords in "strange windows". With AIR 50 and earlier such dialog windows appears only sometimes, very rare. There is no such issues with Windows/Android/iOS. Didn't test with Linux yet.

ajwfrost commented 2 months ago

So .. after some investigations here, it looks like the documentation may be slightly misleading for the attribute "kSecUseAuthenticationUI, kSecUseAuthenticationUISkip" which is what was meant to ensure that no pop-up happened. Apparently when trying to decrypt a generic password from a user, the pop-up will always happen, except for the app that created this in the first place... and we're trying here to access a user-specific key rather than an application-specific one.

So the options would be: 1) we could just use file storage within the user's "private" (application support) folders, which should mean no other user on the system can access this key. (ELS is meant for user-specific data, not for data you're trying to keep from the user). 2) or we could look at using the old/deprecated APIs which are meant to allow you to modify the access control lists to allow all applications to access an item... (not sure this is a great idea though, as it would break if Apple moved the APIs from 'deprecated' to 'removed'..) 3) or we could ask them to manually adjust the key in their Keychain Access file to allow access to all apps without prompting. Not a good idea but there is no longer a supported way to do this programmatically, from what we've seen. 4) or .. the way Apple want you to do it .. we could use keychain access groups. Although all of their documentation points to the fact this should only work within applications that are signed by the same team. It requires an entitlement to be set, which likely means it would only work for apps that are signed (and running via ADL should count, as we sign that..)

FYI the old code used APIs that were deprecated in macOS 10.10.. I suspect you might get a pop-up on first use after a logon, although as you mention, there's an empty password so just clicking "Always Allow" would then get around that. To avoid any pop-ups coming from this code though, we would have to remove the fallback mechanism where currently if we are asked to find an item in the ELS store, if we don't find it in the "new" store then we look in the "old" one.

Given the current restrictions and where we are with things, I think for 51.0 we are stuck with the ELS key being stored in the user's keychain and applications needing the login password to be entered in order to access this, unless the manually go into Keychain Access, click the "login" keychain on the left, click on "Passwords" and then find and right-click on "Adobe_AIR_ELS", choose "Get Info", and then change the "Access Control" section of the pop-up so that it has "Allow all applications to access this item" selected.

For AIR 51.1 onwards we can adjust things to use user-specific file storage, and we can also add a flag via the app descriptor settings to determine whether or not we should try the fallback mechanism. So then we could be sure that no pop-ups would be required.. it could cause issues with migration of data i.e. an old ELS file would not be readable by the new mechanism - allthough perhaps we could have this "els fallback" flag have a "once" setting so that the first time it's tried, we do have to prompt the user for that login password, and can then migrate everything so it would never be needed again.

Of course .. the alternative to all of this on macOS would actually be to store different keys for different applications. Which maybe we should just go with (having written all the above! I'll leave it there for feedback...) - so in other words (from AIR 51.1 onwards) we would just create/store passwords for each application that uses ELS, individually. The only real drawback to this is that it could mean a lot of passwords created for a user, but probably no one really looks at these..!

Would be grateful for any feedback for any of these ideas!

itlancer commented 2 months ago
  1. we could just use file storage within the user's "private" (application support) folders, which should mean no other user on the system can access this key. (ELS is meant for user-specific data, not for data you're trying to keep from the user).

@ajwfrost, I think this one the best for now. It will work similar to Windows.

  1. or .. the way Apple want you to do it .. we could use keychain access groups. Although all of their documentation points to the fact this should only work within applications that are signed by the same team. It requires an entitlement to be set, which likely means it would only work for apps that are signed (and running via ADL should count, as we sign that..)

Or this one.

  1. or we could look at using the old/deprecated APIs which are meant to allow you to modify the access control lists to allow all applications to access an item... (not sure this is a great idea though, as it would break if Apple moved the APIs from 'deprecated' to 'removed'..)

I don't think we should use deprecated APIs with encrypted data)

  1. or we could ask them to manually adjust the key in their Keychain Access file to allow access to all apps without prompting. Not a good idea but there is no longer a supported way to do this programmatically, from what we've seen.

You mean ask user? Via similar pop-up? In future I think it would be a good idea. Something like permission request. Ideally it will be great to have an option to choose - should application use "user data" (by default, how ELS works right now with Windows) or "all users data". That's why I think Windows applications installers (Inno Setup for example) could ask "does install for all users or one user": image It could be implemented as application manifest setting or new EncryptedLocalStore methods/parameters for all platforms where it possible.

FYI the old code used APIs that were deprecated in macOS 10.10.. I suspect you might get a pop-up on first use after a logon, although as you mention, there's an empty password so just clicking "Always Allow" would then get around that. To avoid any pop-ups coming from this code though, we would have to remove the fallback mechanism where currently if we are asked to find an item in the ELS store, if we don't find it in the "new" store then we look in the "old" one.

Given the current restrictions and where we are with things, I think for 51.0 we are stuck with the ELS key being stored in the user's keychain and applications needing the login password to be entered in order to access this, unless the manually go into Keychain Access, click the "login" keychain on the left, click on "Passwords" and then find and right-click on "Adobe_AIR_ELS", choose "Get Info", and then change the "Access Control" section of the pop-up so that it has "Allow all applications to access this item" selected.

One time password request for data migration could be acceptable I think. Just not to lose data.

Of course .. the alternative to all of this on macOS would actually be to store different keys for different applications. Which maybe we should just go with (having written all the above! I'll leave it there for feedback...) - so in other words (from AIR 51.1 onwards) we would just create/store passwords for each application that uses ELS, individually. The only real drawback to this is that it could mean a lot of passwords created for a user, but probably no one really looks at these..!

Also good option.

It will be great to have some patch or update in closest days just to avoid pop-ups (or may be have only one time pop-up for migration). Without such option we stuck at AIR 50.2 and cannot upgrade to AIR 51.0. Or AIR 51.1 should be released soon?

ajwfrost commented 2 months ago

or we could ask them to manually adjust the key in their Keychain Access file to allow access to all apps without prompting. Not a good idea but there is no longer a supported way to do this programmatically, from what we've seen.

You mean ask user? Via similar pop-up?

Sadly, not like that .. there is no (valid) programmatic way for us to make that change. So it would literally be to ask the users and maybe describe the steps they would need to take. Not a good plan, especially for any careful or non-tech-savvy users.

The install mode - for all users vs just one user - is a Windows thing that wouldn't actually impact ELS. ELS would always have a per-user setting, we use the credential manager to store a key that is specific to the user.

Updating the EncryptedLocalStore API would be nice but would mean a new AS3 version code etc, so not something we would do for a patch. Adding a mechanism via the app descriptor settings is something we can do for AIR 51.1, there are a couple of outstanding changes left for this but it should be out by the end of this month. If you wanted a more urgent patch, we could potentially do a configuration mechanism via a special handler within EncryptedLocalStore.setItem() i.e. with a custom item name such as:

var fallbackMode : ByteArray = new ByteArray();
fallbackMode.writeUTFBytes("once"); // or "never" or "always"?
EncryptedLocalStore.setItem("com.harman.air.els.fallback", fallbackMode);

var storageMode : ByteArray = new ByteArray();
storageMode.writeUTFBytes("file"); // or "os_store"
EncryptedLocalStore.setItem("com.harman.air.els.storage", storageMode);

Bit of a hack but it would be a bit quicker and something we could do without changing any APIs/files etc.. Let me know if you'd want something like this or whether you could wait for month-end to use AIR 51.1 with configuration items like that in the app descriptor file...

<encryptedLocalStorage>
  <fallbackMode>never</fallbackMode>
  <storageMode>file</storageMode>
</encryptedLocalStorage>

etc

itlancer commented 2 months ago

@ajwfrost Thank you very much! We will wait for a proper solution with AIR 51.1 at the end of month.