How Can I Prevent Needing to Re-sign My Code Every 1 or 2 Years? - powershell

I was reading What happens when a code signing certificate expires - Stack Overflow and wondering about a more solid answer. The answer provided was more about setting up your own CA. Even with your own CA you will still need to deal with expiring code certificates.
If you signed the code without using a time stamping service, after the certificate expires your code will no longer be trusted, and depending on security settings it may not be allowed to run. You will need to re-sign all of your code with a new certificate, or with a renewed certificate, every 1 or 2 years.
Trusted (digital) timestamping allows the digital signature to be valid even after the certificate itself has expired. You would need to re-sign code with the new certificate only if you have made changes.
Does this all sound correct? If so, I need recommendations on what timestamping service to use, preferably from someone who has actually used one. I'd also like to know if there are any in-house solutions, similar to being your own CA.
Right now this applies to PowerShell scripts, but I will eventually have the same issue with other code.
Update: Sample of how to sign a PS script with a timestamp (you can make a script for this):
Set-AuthenticodeSignature -filepath "D:\Projects\A Sample\MyFile.ps1"
-cert gci cert:\CurrentUser\My -codesigning
| where -Filter {$_.FriendlyName -eq "Thawte Code Signing"}
-IncludeChain All
-TimeStampServer "http://timestamp.verisign.com/scripts/timstamp.dll"
Then, to see the Signer Certificate and TimeStamper Certificate, you can do this:
Get-AuthenticodeSignature MyFile.ps1 | fl *
It gives you the Subject (CN, OU, etc.), Issuer, Before/After Dates, and Thumbprints for both your cert and the timestamper's cert. You also get a message indicating the status of the signature.

You're better off selecting one of the trusted certificate providers (Verisign, Thawte, Comodo, etc.). This allows you to sign your software without the user explicitly trusting your private root CA. We've used both Verisign and Thawte, Comodo even GoDaddy with timestamping without any issues with the software becoming invalid even years after the certificate expires.

Time stamping is a free service -- it's really only a trusted provider verifying that you signed the file at a given time. Verisign's timestamp service is the standard one. The final example in the help for Set-AuthenticodeSignature demonstrates how to use it.
Lee Holmes [MSFT]
Windows PowerShell Development
Microsoft Corporation

You can't really escape having to resign code eventually. The advantage to running your own CA is that you could choose to issue your code-signing certs with longer lifetimes than the default, thereby allowing you to wait longer before having to resign anything. The downside is of course having another service or server (your CA) to deal with.

Related

How to sign correctly a Powershell script for AllSigned ExecutionPolicy?

We have an application where we use several PowerShell scripts. We received a complain regarding about they aren't signed and unable to run them if they have the strictest Execution Policy - AllSigned.
I signed with our certificate issued by well-known issuer via signtool as we do it for dlls and exe app but even after that there is an issue if I try running the script I'm getting warning:
Do you want to run software from this untrusted publisher?
It's signed by a certificate issued by know CA (Sectigo). Only how can I get rid of this warning is to add the certificate to Trusted Publishers. It's not good for customers to do those steps (but maybe it's necessary security step). Note: With the same certificate, we sign exe app and it works fine and Windows doesn't complain. (Look like PowerShell policies are stricter.)
Is it possible somehow avoid getting this warning on a customer side without manually adding our certificate into Trusted Publishers? Looks to me that it is not possible.
What I've found out so far:
I've searched across internet and it looks like there is no solution for that. Even if I used PowerShell script signed by Microsoft Corporation I get the same warning unless I add to the Trusted Publishers folder.
Also e.g. HP directly recommends to add the certificate manually to the cert store.
In a documenation about execution policies is written in AllSigned section: Prompts you before running scripts from publishers that you haven't yet classified as trusted or untrusted.
From those all information, I got it as there is no way how to avoid getting this warning on a customer side without adding to the cert store. I want just to assure myself I'm right.

Signing certificates with an existing Root Certificate Authority

I am trying to setup some certificates for different hostnames (aliases) for SQL Server Reporting Services so that I can secure connections on my own machine for testing purposes. My understanding is that these certificates need to be signed by a trusted Root Certificate Authority (explained here). After doing some research, I've found a lot of helpful information that can generally be summarized by this post; the information I've found tells me how to create new certificates using Powershells New-SelfSignedCertificate cmdlet.
So now I know how to create a new Root CA, and I know how to create an SSL certificate for a given hostname which is signed by the new Root CA. However, I can't find anywhere that explains how to re-use an existing Root CA. I want the code to work like this:
$rootCA = <# What goes here? #>
$TestSigned = New-SelfSignedCertificate -subjectName "CN=TestSignedByRoot" -Signer $rootCA
Am I supposed to just create a new Root CA every time I want to create a certificate? That seems insane so I sure hope that's not the case. If any of you could provide some explanation and sample code it would be greatly appreciated.
To get a certificate from the certificate store with known hash:
$rootCa = ( Get-ChildItem -Path cert:\LocalMachine\My\EEDEF61D4FF6EDBAAD538BB08CCAADDC3EE28FF )
To see what certificates there are in the My store:
Get-ChildItem -Path cert:\LocalMachine\My
To get a certificate by subject name, use Where-Object to check the Subject property:
$rootCa = Get-ChildItem -Path cert:\LocalMachine\My | Where-Object {$_.Subject -eq "CN=My Awesome Root CA"}
You are missing a key word here: Trusted. Not just by you, but by any computer that tries to verify the validity of the certificate. Most companies will have a PKI solution to be able to issue certificates internally, and will have the certificate for the Root CA pushed out via GPO into the Trusted Roots folder of the local machine certificate store. The Root CA should be something that is already established, and trusted by the computers that will be connecting to your SQL server. I would recommend contacting your IT or Security department to ask about if the company has a Trusted Root CA that you can get your certificate signed by, or if they can issue you a certificate that chains to the trusted root.
Edit: Ok, I missed the point. My understanding was 'my machine' being the SQL server that you support vs other computers that would connect to it. If the only computer that you are concerned with is your own, then this comes down to:
Create a Certificate Signing Certificate (Certificate A)
Add Certificate A to the Trusted Root folder of your LocalMachine
certificate store
Create a self signed certificate (Certificate B)
using Certificate A as the signing certificate
Once you have completed steps 1 & 2 you can repeat step 3 as many times as needed to make additional certificates. You should only need 1 Root cert ever. The important part is that the Root certificate is trusted by the 'client', so that when it connects to the SQL reporting service and sees the certificate it can establish a chain of trust to the root certificate that initiated the chain.
To use an existing trusted certificate, you will need a copy of the trusted certificate in the Personal Certificates folder (cert:\LocalMachine\My) I used CertMgr. Else when you finally run your command to create the self signed certificate, you get an error
New-SelfSignedCertificate: CertEnroll::CSignerCertificate::Initialize: Cannot find object or property. 0x80092004 (-2146885628 CRYPT_E_NOT_FOUND)

When .net says "certificate valid", what is it checking?

I'm using the SignedXml.CheckSignature(X509Certificate2, boolean) method. I would like to know what checks are performed when deciding the validity of the certificate. I have verified that the Current User/Not Trusted list is checked. The documentation says it will use the "address book" store, searching by subject key identifier, to build the certificate chain. I imagine this means the Local Machine and Current User certificate stores?
Am I right to think that certificate revocation and signature timestamp are not checked? To do an OCSP check for certificate revocation, am I obliged to use Bouncy Castle?
In the remarks in the msdn article you link to one finds:
In version 1.1 of the .NET Framework, the X.509 certificate is not verified.
In version 2.0 and later, the X.509 certificate is verified.
In version 2.0 and later of the .NET Framework, the CheckSignature method will search the "AddressBook" store for certificates suitable for the verification. For example, if the certificate is referenced by a Subject Key Identifier (SKI), the CheckSignature method will select certificates with this SKI and try them one after another until it can verify the certificate.
Thus, first of all the behavior of that method has changed in different .NET framework versions. So for reproducible results, you had better not count on that method even check the certificate at all.
Furthermore, the formulation try them one after another until it can verify the certificate sounds like there just might be the mathematical test whether or not the certificate is signed by its alleged issuer.
https://referencesource.microsoft.com/#System.Security/system/security/cryptography/xml/signedxml.cs,b9518cc2212419a2
It checks
The certificate has no Key Usage extension, or the Key Usage extension has either Digital Signature or Non Repudiation usages enabled
The certificate chains up to a trusted root authority
The certificate has not been revoked
The certificate was not expired when you called this method
It doesn't know when the document was signed, so it doesn't answer that question.
That none of the certificates in the chain are explicitly prohibited by the user or system configuration.

Using self-signed certificate for code signing software

Currently our company uses a digital certificate from Versign/Symtanec for code signing our software.
We have someone in our company attempting to persuade us to use a self-signed certificate instead of one purchased from Verisign/Symantec. Partially as a "cost-down" procedure (even though they're pretty damn cheap for a 2-3 year renewal), and partially to make things easier in a patching sense, as the systems our software runs on (industrial machines) has installed software with a non-Windows certificate store in which our certificate also needs to be managed. Apparently they want use to use the Windows Root CA in order to generate our certificate so we don't have to keep patching new certificates on and our certificate will essentially last as long as the Windows Root CA is valid ...
Everywhere I've been looking, I've found that some people use self-signed certificates for things like website identity verification over the net, but when used in a code-signing context, there are a lot of examples for certificate generation and people saying that you can use them for testing in an environment that's closer to a production environment (which I have done in the past), but I can't find any hard reasons as to why not to use a self-signed certificate for code-signing production software.
It's been a while since I've had to look a the certificate side of things, but this just feels wrong.
It's possible that just I'm not experienced enough with certificates to see why this is a good idea. Does anyone have any input to help me understand the full implications of this?
Using a self-signed certificate should not work. The idea is that "someone trustable" (not you; but Verisign or some other party that should check your credentials) confirms that something is certified.
I'm not sure exactly how this works in Windows. Might be that they didn't implement something properly.
There is no problem using a self signed certificate in windows. Just put the root CA certificate and the signing cert in the Windows cert store of the client machines that will run the signed application and/or driver.
Managing self signed certs within an organization is a PITA. Hence why people pay good money to get somebody else to do it.
If you are going to distribute your signed code outside your organization it is even more painful as you will need to persuade your customers to accept your CA certificate, and nobody should ever accept a root certificate from an unknown source or sent via an insecure or unverifiable means.
See this answer for instructions on creating a self signed CA and signing certificates using it.
The same is possible (but in my opinion more complicated) using Windows PowerShell, The sequence is he same but the commands change.

Can I request a client certificate from Active Directory CA with Powershell?

I'd like to automate the task of requesting client certificates from the CA attached to our Active Directory. Currently, I use certmgr and click "Request New Certificate" from the menu and do several other selections, including selecting an appropriate policy.
Surely, Powershell can help me with this, as I already use it to get rid of old certificates. Is there a module which can be used for this or does Powershell 3 cover this out-of-the-box?
I think certreq could be what you are looking for.
Certreq can be used to request certificates from a certification authority (CA), to retrieve a response to a previous request from a CA, to create a new request from an .inf file, to accept and install a response to a request, to construct a cross-certification or qualified subordination request from an existing CA certificate or request, and to sign a cross-certification or qualified subordination request.
Then there is another useful utility when dealing with certificates in windows - certutil