Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Enterprise signed scripts #21550

Open
SteveL-MSFT opened this issue Apr 29, 2024 · 7 comments
Open

Add support for Enterprise signed scripts #21550

SteveL-MSFT opened this issue Apr 29, 2024 · 7 comments
Labels
Issue-Enhancement the issue is more of a feature request than a bug Needs-Triage The issue is new and needs to be triaged by a work group.

Comments

@SteveL-MSFT
Copy link
Member

SteveL-MSFT commented Apr 29, 2024

Summary of the new feature / enhancement

[Updated based on feedback below]

Azure has a new Trusted Signing service in public preview. One of the features is rotation of the signing cert. This breaks how PowerShell currently validates signed scripts.

PowerShell only trusts the leaf cert in the chain and this cert will be rotated (by Azure or any other cert service). So a customer may initially sign a script and it works, but then after the cert is rotated new scripts won't work since the leaf cert has changed and old certs might have expired so old scripts also stop working in an execution policy that requires signing.

Proposed technical implementation details (optional)

Azure Trust Signing customer signing cert has a customer unique EKU. We would allow storing additional signing metadata in the registry:

  • HKLM\Software\Microsoft\PowerShellCore\TrustedEnterpriseEKU as a string array representing the customer unique EKUs
    • example: 1.3.6.1.4.1.311.97.990309390.766961637.194916062.941502583
    • it will be up to users to properly put here a unique identifying EKU they trust
  • This property is, by default, protected to be read-only except for LocalSystem and Admins

Existing AllSigned and RemoteSigned execution policies will respect the EKU if it has been stored in the registry (this is how the customer opts into this change in behavior):

  • perform standard Authenticode validation (like Get-Authenticode), if valid then:
    • verify that the leaf cert contains the TrustedEnterpriseEKU as stored in the registry

This would allow for alternate signing services to also participate and work with PowerShell.

Cert revocation will continued to be handled by WinTrust and no change for PowerShell.

@SteveL-MSFT SteveL-MSFT added Issue-Enhancement the issue is more of a feature request than a bug Needs-Triage The issue is new and needs to be triaged by a work group. labels Apr 29, 2024
@jborean93
Copy link
Collaborator

old scripts also stop working in an execution policy that requires signing.

Just to expand on this, they do still work it's just that PowerShell prompts whether you trust the new publisher or not.

Do you want to run software from this untrusted publisher?
File C:\temp\cert\ps_ca_signed.ps1 is published by CN=SelfSignedTest-Signed and is not trusted on your system. Only run
 scripts from trusted publishers.
[V] Never run  [D] Do not run  [R] Run once  [A] Always run  [?] Help (default is "D"):

A few questions

  • Should the prompt above have a way to trust the EKU if it has the Azure TS prefix 1.3.6.1.4.1.311.97.?
    • Should this prefix be configurable to potentially allow other services that follow this pattern
  • Should it instead just continue to use the TrustedPublisher store and see if the EKU is present in an existing cert rather than the thumbprint
    • This could be done to check with the Azure well known prefix but might lock out other services if they also use this identifier mechanism
  • Should these be a separate policy from AllSigned and RemoteSigned or some other mechanism to opt into trusted from this reg key
    • Should there even be an option or should it always trust from this key
  • What happens if the permissions for this key has been altered to allow non-admins (like the ssh private key check)
  • How does PSResourceGet factor into this when -AuthenticodeCheck is set
  • Does GPO factor into this at all, can it even set the execution policy for pwsh 7+ on the *Policy scopes like in WinPS

Personally I would not be a fan of having to opt into allowing this check. I would find that it adds a barrier to entry for using these types of certificates and punishes developers for trying to sign their code which is not something we would want to encourage. Instead if there is a desire to have a way to use the existing behaviour maybe that should be opt in rather than the new ay being opt in?

@SteveL-MSFT
Copy link
Member Author

SteveL-MSFT commented Apr 30, 2024

  • If the EKU is trusted, the idea is that you wouldn't be prompted. It doesn't seem like we need to know about the prefix and thus not make it configurable. The prefix seems to only be necessary if we want to restrict it to Azure signed certs, for example.
  • The intent is to use the TrustedPublisher store with the additional EKU check. If other services adopt this pattern, it should work with them as well.
  • The proposal is two new execution policies and AllSigned and RemoteSigned do not change.
  • An ACL check on the reg key to ensure only admin and system have write access seems like a good idea.
  • Good question I hadn't considered, PSResourceGet is using Get-AuthenticodeSignature currently, so it'll pass regardless of the EKU. Maybe it should be enhanced to give a warning if the EKU is set and doesn't match?
  • PS7 has the GPO that allows setting the execution policy https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_group_policy_settings?view=powershell-7.4

The opt-in is necessary as PowerShell would need to know the EKU to check against. If you're concerned about new execution policies, then an alternate option is that if the reg property exists, then PowerShell would run AllSigned and RemoteSigned as effectively EnterpriseSigned and EnterpriseRemoteSigned, but that could be confusing to users.

Describes the Group Policy settings for PowerShell

@jborean93
Copy link
Collaborator

If the EKU is trusted, the idea is that you wouldn't be prompted. It doesn't seem like we need to know about the prefix and thus not make it configurable. The prefix seems to only be necessary if we want to restrict it to Azure signed certs, for example.

Sorry if I wasn't clear, this was more of a way to improve the UX of running an untrusted publisher for the first time. Right now if PowerShell is set to run a signed script with a publisher that is unknown it will prompt you if you wish to trust it. If you do it will add that cert to the TrustedPublisher store for you so you don't have to. The prompt question was whether this should also be implemented for this new check, at least for known EKU prefixes, to trust interactively. It also brings in question whether users can explicitly opt into a user trust level like in HKCU. Right now it seems like PowerShell checks both the CurrentUser and LocalMachine TrustedPublisher store.

The proposal is two new execution policies and AllSigned and RemoteSigned do not change.

The question was whether this new check should be a new policy or a new behaviour for the existing policies.

Good question I hadn't considered, PSResourceGet is using Get-AuthenticodeSignature currently, so it'll pass regardless of the EKU. Maybe it should be enhanced to give a warning if the EKU is set and doesn't match?

While I cannot say how PSResourceGet implemented things I know the PowerShellGet -SkipPublisherCheck was problematic as it scanned the subject of both the leaf and issuer certificates. I know PSResourceGet hasn't implemented this by default but I'm unsure whether the -AuthenticodeCheck is a simple signature check or whether it also does the extra checks that PowerShellGet also added on top. If it's just a simple signature check then it sounds like we don't need to worry about that.

The opt-in is necessary as PowerShell would need to know the EKU to check against.

It sounds like the opt-in is should be populating the registry value rather than opt-ing into checking for the registry value in the first place. My concern is that I publish a module that's signed by Azure TS (or even my own internal mechanism) and users who want to verify the signature now need to explicitly trust my EKU rather than today where PowerShell will at least prompt whether you trust it or not. As mentioned earlier it is also possible for non-admin users to trust a publisher.

One other area I haven't looked into too closely is how do revocations work with certs. Should PowerShell offer the ability to revoke a specific EKU. Does the normal authenticode signature check done by Windows take into account revoked certificates, etc.

@SteveL-MSFT
Copy link
Member Author

Sorry if I wasn't clear, this was more of a way to improve the UX of running an untrusted publisher for the first time. Right now if PowerShell is set to run a signed script with a publisher that is unknown it will prompt you if you wish to trust it. If you do it will add that cert to the TrustedPublisher store for you so you don't have to. The prompt question was whether this should also be implemented for this new check, at least for known EKU prefixes, to trust interactively. It also brings in question whether users can explicitly opt into a user trust level like in HKCU. Right now it seems like PowerShell checks both the CurrentUser and LocalMachine TrustedPublisher store.

Ok, now I see what you are asking. Yes, it makes sense to improve the prompt but the user would need to be elevated to populate the registry.

The proposal is two new execution policies and AllSigned and RemoteSigned do not change.

The question was whether this new check should be a new policy or a new behaviour for the existing policies.

I believe the question was answered?

Good question I hadn't considered, PSResourceGet is using Get-AuthenticodeSignature currently, so it'll pass regardless of the EKU. Maybe it should be enhanced to give a warning if the EKU is set and doesn't match?

While I cannot say how PSResourceGet implemented things I know the PowerShellGet -SkipPublisherCheck was problematic as it scanned the subject of both the leaf and issuer certificates. I know PSResourceGet hasn't implemented this by default but I'm unsure whether the -AuthenticodeCheck is a simple signature check or whether it also does the extra checks that PowerShellGet also added on top. If it's just a simple signature check then it sounds like we don't need to worry about that.

Since PSResourceGet calls out to Get-AuthenticodeSignature, it's a simpler check that PowerShell currently won't necessarily allow as it's a CA check rather than a leaf check. That's a separate issue we should discuss in PSResourceGet repo if any change is needed (I believe intent was to just check it was signed and not whether it would work with an execution policy).

One other area I haven't looked into too closely is how do revocations work with certs. Should PowerShell offer the ability to revoke a specific EKU. Does the normal authenticode signature check done by Windows take into account revoked certificates, etc.

Authenticode (which we call the WinTrust APIs) should automatically take care of cert revocation.

@jborean93
Copy link
Collaborator

jborean93 commented Apr 30, 2024

I believe the question was answered?

To be clear I'm suggesting that instead of adding two completely new policies you either just add this new EKU registry checking behaviour by default with no opt in or out option or add in an opt out option instead of having people explicitly have to use a new policy. This would be in lieu of explicit execution policies to control things.

Authenticode (which we call the WinTrust APIs) should automatically take care of cert revocation.

To revoke a single cert, what happens if you want to distrust a specific publisher altogether. You would have to find every single cert they used to sign and add them to get that to work.

@SteveL-MSFT
Copy link
Member Author

@jborean93 I see. So the fact that the registry property exists would be an indicator that the user has opted into the change in behavior. That seems reasonable to me.

Get-ExecutionPolicy currently returns the ExecutionPolicy enum value, but it can have a note property added that is the list of EKUs and FormatData can present it.

Set-ExecutionPolicy would need new parameters to set (replace) the EKUs.

Need to think more about revocation.

@SteveL-MSFT
Copy link
Member Author

SteveL-MSFT commented May 7, 2024

It seems like PowerShell just relies on the current system for cert revocation: https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-cert-revocation

This means that customers can either revoke individual certs (yes, can be laborious), or revoke all the certs.

How-to revoke a Trusted Signing certificate from Azure portal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Enhancement the issue is more of a feature request than a bug Needs-Triage The issue is new and needs to be triaged by a work group.
Projects
None yet
Development

No branches or pull requests

2 participants