How to export certs with SAN extensions? - powershell

I have this PowerShell command that exports for me all issued certificates into a .csv file:
$Local = "$PSScriptRoot"
$File = "$Local\IssuedCerts.csv"
$Header = "Request ID,Requester Name,Certificate Template,Serial Number,Certificate Effective Date,Certificate Expiration Date,Issued Country/Region,Issued Organization,Issued Organization Unit,Issued Common Name,Issued City,Issued State,Issued Email Address"
certutil -view -out $Header csv > $File
This works fine, by the way I would like to format the output in a more readable manner, if its somehow possible, please let me know, too.
The point is I need to export all certificates which will expire soon, but I also need data from SAN Extensions from each certificate too be exported with.

Perhaps getting the certificates directly from the CertificateAuthority X509Store and reading the certificate extensions (one of which is the Subject Alt Names) using the ASNEncodedData class would do the trick?
Example code below on reading certificates from the given store and printing out their extensions:
using namespace System.Security.Cryptography.X509Certificates
$caStore = [X509Store]::new([StoreName]::CertificateAuthority, [StoreLocation]::LocalMachine)
$caStore.Open([OpenFlags]::ReadOnly)
foreach ($certificate in $caStore.Certificates) {
foreach ($extension in $certificate.Extensions) {
$asnData = [System.Security.Cryptography.AsnEncodedData]::new($extension.Oid, $extension.RawData)
Write-Host "Extension Friendly Name: $($extension.Oid.FriendlyName)"
Write-Host "Extension OID: $($asnData.Oid.Value)"
Write-Host "Extension Value: $($asnData.Format($true))"
}
}
$caStore.Close()
You can specify a different store to open by specifying a different value for the [StoreName]::CertificateAuthority section.
Disclaimer, I haven't been able to test this code in production, so I'm not 100% certain that all the fields you require are exposed, but may serve as a good starting point

Related

Using PowerShell created self signed certs

I am trying to create a new self signed cert and then use it to sign an EXE, to address the fact that idiot Autodesk is using an installer that ignores the time stamp and refuses to install something with an expired cert, even their own installer. It's a bug, they know it, and they fixed their installer. But addressing that when you have 30+ deployments that use the old buggy one is a PITA. Anyway...
I expected this would produce a certificate that I would find in the Personal tab.
$certParameters = #{
'DnsName' = 'PxTools'
'Type' = 'CodeSigningCert'
'CertStoreLocation' = 'Cert:\LocalMachine\My'
'NotAfter' = (Get-Date).AddMonths(12)
'KeyAlgorithm' = 'RSA'
'KeyLength' = '4096'
}
$cert = New-SelfSignedCertificate #certParameters
and that I would then be able to use it for signing. But it doesn't populate the $cert variable as expected, and it puts the cert in Intermediate Certification Authorities, and I have yet to figure out how to use
Get-ChildItem cert:\LocalMachine\?? -codesign
To get certs in that location. I have used ??=My to get a cert in Personal, but not sure
A: Why the cert isn't created in Personal as expected
B: How to get the cert from where it IS created

How would I generate the Identity Server signing certificate

In the identity server samples we find code like this in Startup.cs
var certFile = env.ApplicationBasePath + "\\idsrv3test.pfx";
var signingCertificate = new X509Certificate2(certFile, "idsrv3test");
How would I go about replacing this for production scenarios?
For the record, the code proposed in the image posted by RuSs:
options.SigningCertificate = LoadCertificate();
public X509Certificate2 LoadCertificate()
{
string thumbPrint = "104A19DB7AEA7B438F553461D8155C65BBD6E2C0";
// Starting with the .NET Framework 4.6, X509Store implements IDisposable.
// On older .NET, store.Close should be called.
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbPrint, validOnly: false);
if (certCollection.Count == 0)
throw new Exception("No certificate found containing the specified thumbprint.");
return certCollection[0];
}
}
Get a dedicated cert - either via your PKI or self-generate one:
http://brockallen.com/2015/06/01/makecert-and-creating-ssl-or-signing-certificates/
Import the key pair into the Windows certificate store, and load it from there at runtime.
To step up security, some people deploy the keys to a dedicated device (called an HSM) or to a dedicated machine (e.g. behind a firewall). The ITokenSigningService allows moving the actual token signing to that separate machine.
Recently I decided to revamp my token signing issuing process. If you're running Windows 10, you can use the awesome powershell cmdlet called New-SelfSignedCertificate.
Here is my example usage:
New-SelfSignedCertificate -Type Custom
-Subject "CN=TokenSigningForIdServer"
-TextExtension #("2.5.29.37={text}1.3.6.1.5.5.7.3.3")
-KeyUsage DigitalSignature
-KeyAlgorithm RSA
-KeyLength 2048
-CertStoreLocation "Cert:\LocalMachine\My"
Make sure you are running the command as an admin. You can obtain the certificate details by opening certlm.msc. It should be stored below Personal\Certificates.
Most of the flags should be obvious, apart from the -TextExtention one. It specifies that an Enhaced Key Usage field is set to the "Code Signing" value. You can play around with the algorithm used, key length, even add extentisons by refering to the following documentation page.
Here is how I load it from a thumbprint in my config:
Click here to see image

Configuration file transformation in ASP .NET 5

We are building a web-application using the new ASP .NET 5 platform. I am configuring the build and deployment automation tools and I want to have the ability to change the application settings during deployment (like changing the web-service url). In ASP .NET 5 we don't have web.config files anymore, only the new json configuration files. Is there a mechanism in ASP .NET 5 similar to web.config transformation in the previous versions of ASP .NET?
I know that web.configs are not really supported, but they are still used in ASP.Net under IIS.
I had a desire to apply transforms as well as I wanted to control the environment variable from the config like so:
<aspNetCore>
<environmentVariables xdt:Transform="Replace">
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>
</aspNetCore>
If you really want to transform them in ASP.Net core / 5 you can use the following method:
Add as many different web.config transform files as you want to your
project. For example, you can add Web.Development.config,
Web.Staging.config, and Web.Production.config, etc... Name them however you like.
Modify your project.json file to output the files by adding this
line to the publishoptions right below your current web.config line:
"web.*.config"
Create a publish profile and modify your powershell script for your
publish profile (located at Web Project\Properties\PublishProperties\profilename-publish.ps1) to add the below modifications:
Add this function above the try catch (I found this function here Web.Config transforms outside of Microsoft MSBuild?, slightly modified.) :
function XmlDocTransform($xml, $xdt)
{
if (!$xml -or !(Test-Path -path $xml -PathType Leaf)) {
throw "File not found. $xml";
}
if (!$xdt -or !(Test-Path -path $xdt -PathType Leaf)) {
throw "File not found. $xdt";
}
"Transforming $xml using $xdt";
$scriptPath = (Get-Variable MyInvocation -Scope 1).Value.InvocationName | split-path -parent
#C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll
Add-Type -LiteralPath "${Env:ProgramFiles(x86)}\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.XmlTransform.dll"
$xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmldoc.PreserveWhitespace = $true
$xmldoc.Load($xml);
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdt);
if ($transf.Apply($xmldoc) -eq $false)
{
throw "Transformation failed."
}
$xmldoc.Save($xml);
}
Add these lines ABOVE the Publish-AspNet call:
$xdtFiles = Get-ChildItem $packOutput | Where-Object {$_.Name -match "^web\..*\.config$"};
$webConfig = $packOutput + "web.config";
foreach($xdtFile in $xdtFiles) {
XmlDocTransform -xml $webConfig -xdt "$packOutput$xdtFile"
}
You don't really need config transforms in ASP.NET 5 as it has out of the box support for chained configuration sources. For example, take this sample:
public class Startup
{
private readonly IConfiguration _configuration;
public Startup(IApplicationEnvironment appEnv, IHostingEnvironment env)
{
_configuration = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddEnvironmentVariables()
.Build();
}
// ...
}
We add two config sources and building the configuration our of them. if I ask for a config key, it will try to get a value for that key by looking at the sources from last to first order. In the above case, I can work with a config.json file during development and I can ovveride the that by providing the proper configuration from environment variables.
Look at the Configuration docs for more information.
As indicated by #tugberk, you can use environment variables instead which is a much better way of handling this situation. If you are running in a development environment and want to store passwords or connection strings you can also use user secrets to add them. After all that you can also still use environment specific config files like so (This is a ASP.NET 5 Beta 5 Sample):
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(
applicationEnvironment.ApplicationBasePath);
// Add configuration from the config.json file.
configurationBuilder.AddJsonFile("config.json");
// Add configuration from an optional config.development.json, config.staging.json or
// config.production.json file, depending on the environment. These settings override the ones in the
// config.json file.
configurationBuilder.AddJsonFile($"config.{hostingEnvironment.EnvironmentName}.json", optional: true);
if (hostingEnvironment.IsEnvironment(EnvironmentName.Development))
{
// This reads the configuration keys from the secret store. This allows you to store connection strings
// and other sensitive settings on your development environment, so you don't have to check them into
// your source control provider. See http://go.microsoft.com/fwlink/?LinkID=532709 and
// http://docs.asp.net/en/latest/security/app-secrets.html
configurationBuilder.AddUserSecrets();
}
// Add configuration specific to the Development, Staging or Production environments. This config can
// be stored on the machine being deployed to or if you are using Azure, in the cloud. These settings
// override the ones in all of the above config files.
// Note: To set environment variables for debugging navigate to:
// Project Properties -> Debug Tab -> Environment Variables
// Note: To get environment variables for the machine use the following command in PowerShell:
// $env:[VARIABLE_NAME]
// Note: To set environment variables for the machine use the following command in PowerShell:
// $env:[VARIABLE_NAME]="[VARIABLE_VALUE]"
// Note: Environment variables use a colon separator e.g. You can override the site title by creating a
// variable named AppSettings:SiteTitle. See
// http://docs.asp.net/en/latest/security/app-secrets.html
configurationBuilder.AddEnvironmentVariables();
IConfiguration configuration = configurationBuilder.Build();

From Msi , how to get the list of files packed in each feature?

We have used wix to create Msi. Each Msi will be having 1 or 2 or 3 features such as Appserver feature, Webserver feature and DB server feature.
Now i was asked to get the list of config files presented in each feature.
It is tough to find the list of web.config files associated with each feature through wxs file.
Is it possible find the list of files associated with a feature with particular search pattern?
For ex. Find all the web.config files packed in Appserver feature.
Is there any way easy way ( querying or some other automated script such as powershell) to get the list?
Wix comes with a .NET SDK referred to as the DTF ("deployment tools foundation"). It wraps the windows msi.dll among other things. You can find these .NET Microsoft.Deployment.*.dll assemblies in the SDK subdirectory of the Wix Toolset installation directory. The documentation is in dtf.chm and dtfapi.chm in the doc subdirectory.
As shown in the documentation, you can use this SDK to write code which queries the msi database with SQL. You will be interested in the Feature, FeatureComponents and File tables.
If you haven't explored the internals of an MSI before, you can open it with orca to get a feel for it.
You can do it by making slight modifications to the Get-MsiProperties function described in this PowerShell article.
Please read the original article and create the prescribed comObject.types.ps1xml file.
function global:Get-MsiFeatures {
PARAM (
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,HelpMessage="MSI Database Filename",ValueFromPipeline=$true)]
[Alias("Filename","Path","Database","Msi")]
$msiDbName
)
# A quick check to see if the file exist
if(!(Test-Path $msiDbName)){
throw "Could not find " + $msiDbName
}
# Create an empty hashtable to store properties in
$msiFeatures = #{}
# Creating WI object and load MSI database
$wiObject = New-Object -com WindowsInstaller.Installer
$wiDatabase = $wiObject.InvokeMethod("OpenDatabase", (Resolve-Path $msiDbName).Path, 0)
# Open the Property-view
$view = $wiDatabase.InvokeMethod("OpenView", "SELECT * FROM Feature")
$view.InvokeMethod("Execute")
# Loop thru the table
$r = $view.InvokeMethod("Fetch")
while($r -ne $null) {
# Add property and value to hash table
$msiFeatures[$r.InvokeParamProperty("StringData",1)] = $r.InvokeParamProperty("StringData",2)
# Fetch the next row
$r = $view.InvokeMethod("Fetch")
}
$view.InvokeMethod("Close")
# Return the hash table
return $msiFeatures
}

How to check if a file has a digital signature

I'd like to check programatically if a file has been digitally signed or not.
For the moment, I found a rather obscure Microsoft code, that doesn't compile...
Any idea on the subject?
An external tool with command line would also be great, by the way.
The important missing part of the answer mentioning signtool is:
Yes, with the well known signtool.exe you can also find out, if a file is signed. No need to download another tool!
E.g. with the simple line:
signtool verify /pa myfile.exe
if %ERRORLEVEL% GEQ 1 echo This file is not signed.
(For verbose output, add a /v after /pa.)
One may ask: Why this is important? I just sign the files (again) which shall be signed and it works.
My objective is to keep builds clean, and don't sign files a second time because not only the date is changed, but the is binary different after that.
Business example:
My client has a streamlined automated "dev ops" kind build and post build process. There are multiple sources for different file sets, and at the end all is build, tested and bundled to distribution- and for that some files have to be signed. To guarantee that some files don't leave the unit without being signed, we used to sign all important files found on the media, even if they were already signed.
But this hasnĀ“t been clean enough ! Generally:
If we sign a file again, which is already signed, the file date and binary fingerprint changes, and the file looses comparability with it's sources, if it was simply copied.
(At least if you sign with a timestamp, which we always do and I think is highly recommended.)
This is a severe quality loss, because this file is no longer identical to it's predecessors although the file itself has not changed.
If we sign a file again, this also could be a fault when it is a third party file which shouldn't be signed by our company.
You can avoid both by making the signing itself conditional depending on the return code of the preceding signtool verify call mentioned.
Download Sigcheck and use the following command.
sigcheck.exe -a -u -e
An example of a signed dll
File version: 0.0.0.0
Strong Name: Signed
An example of an unsigned dll
File version: 0.0.0.0
Strong Name: Unsigned
Sigcheck is a command-line utility that shows file version number. Good Luck
I found another option (pure .NET code) on the web here.
The code is very simple and works.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
internal class Program
{
private static void Main(string[] args)
{
string filePath = args[0];
if (!File.Exists(filePath))
{
Console.WriteLine("File not found");
return;
}
X509Certificate2 theCertificate;
try
{
X509Certificate theSigner = X509Certificate.CreateFromSignedFile(filePath);
theCertificate = new X509Certificate2(theSigner);
}
catch (Exception ex)
{
Console.WriteLine("No digital signature found: " + ex.Message);
return;
}
bool chainIsValid = false;
/*
*
* This section will check that the certificate is from a trusted authority IE
* not self-signed.
*
*/
var theCertificateChain = new X509Chain();
theCertificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
/*
*
* Using .Online here means that the validation WILL CALL OUT TO THE INTERNET
* to check the revocation status of the certificate. Change to .Offline if you
* don't want that to happen.
*/
theCertificateChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
theCertificateChain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
theCertificateChain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
chainIsValid = theCertificateChain.Build(theCertificate);
if (chainIsValid)
{
Console.WriteLine("Publisher Information : " + theCertificate.SubjectName.Name);
Console.WriteLine("Valid From: " + theCertificate.GetEffectiveDateString());
Console.WriteLine("Valid To: " + theCertificate.GetExpirationDateString());
Console.WriteLine("Issued By: " + theCertificate.Issuer);
}
else
{
Console.WriteLine("Chain Not Valid (certificate is self-signed)");
}
}
}
Since PowerShell 5.1, you can use Get-AuthenticodeSignature to verify the signature of a binary or a PowerShell script.
> Get-AuthenticodeSignature -FilePath .\MyFile.exe
SignerCertificate Status Path
----------------- ------ ----
A59E92E31475F813DDAF41C3CCBC8B78 Valid MyFile.exe
Or
> (Get-AuthenticodeSignature -FilePath .\MyFile.exe).Status
Valid
If you need an external tool, you can use signtool.exe. It is part of the Windows SDK, it takes command line arguments, and you can find out more about it here, http://msdn.microsoft.com/en-us/library/aa387764.aspx
Also you can try to use npm package sign-check for that purposes.
This package implements WinVerifyTrust API and has simple usage:
npm install -g sign-check
sign-check 'path/to/file'
Select the <*>.exe rightclick >properties. if the file is signed then you will get this tab on the property windows of that file.