PoshCode Archive  Artifact [eea299f101]

Artifact eea299f1019bc2f9ebd0ecd36f45f78bfd257b8d029d999c62aaa7b36de8dd76:

  • File New-CodeSigningCertifica.ps1 — part of check-in [84a95785d5] at 2018-06-10 13:14:37 on branch trunk — Creates new self-signed code signing certificate and installs it to current user’s personal store. Supports Windows XP and higher. (user: vpodans size: 10652)

# encoding: ascii
# api: powershell
# title: New-CodeSigningCertifica
# description: Creates new self-signed code signing certificate and installs it to current user’s personal store. Supports Windows XP and higher.
# version: 1.0
# type: script
# author: vpodans
# license: CC0
# function: New-CodeSigningCertificate
# x-poshcode-id: 2700
# x-archived: 2016-10-29T09:24:59
# x-published: 2011-05-28T10:35:00
#
# Initially script was developed for Quest PowerGUI ScriptEditor add-on.
#
#####################################################################
# New-CodeSigningCertificate.ps1
# Version 1.0
#
# Creates new self-signed code signing certificate and installs it to
# current user's personal store. Supports Windows XP and higher.
#
# Initially script was developed for Quest PowerGUI ScriptEditor add-on.
#
# Vadims Podans (c) 2011
# http://en-us.sysadmins.lv/
#####################################################################
#requires -Version 2.0

function New-CodeSigningCertificate {
[CmdletBinding()]
	param(
		[Security.Cryptography.X509Certificates.X500DistinguishedName]$Subject = "CN=PowerGUI User",
		[ValidateSet(1024,2048)]
		[int]$KeyLength = 2048,
		[DateTime]$ValidFrom = [datetime]::Now,
		[DateTime]$ValidTo = [datetime]::Now.AddYears(1)
	)
$signature = @"
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CryptAcquireContext(
   ref IntPtr phProv,
   string pszContainer,
   string pszProvider,
   uint dwProvType,
   Int64 dwFlags
);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CryptReleaseContext(
	IntPtr phProv,
	int flags
);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CryptGenKey(
	IntPtr phProv,
	int Algid,
	int dwFlags,
	ref IntPtr phKey
);
[DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CryptExportPublicKeyInfo(
	IntPtr phProv,
	int dwKeySpec,
	int dwCertEncodingType,
	IntPtr pbInfo,
	ref int pcbInfo
);
[DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CryptHashPublicKeyInfo(
	IntPtr phProv,
	int Algid,
	int dwFlags,
	int dwCertEncodingType,
	IntPtr pInfo,
	IntPtr pbComputedHash,
	ref int pcbComputedHash
);
[DllImport("Crypt32.dll", SetLastError=true)]
public static extern bool CryptEncodeObject(
	int dwCertEncodingType,
	[MarshalAs(UnmanagedType.LPStr)]string lpszStructType,
	ref CRYPTOAPI_BLOB pvStructInfo,
	byte[] pbEncoded,
	ref int pcbEncoded
);

[DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr CertCreateSelfSignCertificate(
	IntPtr phProv,
	CRYPTOAPI_BLOB pSubjectIssuerBlob,
	int flags,
	CRYPT_KEY_PROV_INFO pKeyProvInfo,
	IntPtr pSignatureAlgorithm,
	SystemTime pStartTime,
	SystemTime pEndTime,
	CERT_EXTENSIONS pExtensions
);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CryptDestroyKey(
	IntPtr cryptKeyHandle
);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool FileTimeToSystemTime(
	[In] ref long fileTime,
	out SystemTime SystemTime
);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_KEY_PROV_INFO {
	public string pwszContainerName;
	public string pwszProvName;
	public int dwProvType;
	public int dwFlags;
	public int cProvParam;
	public IntPtr rgProvParam;
	public int dwKeySpec;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CERT_EXTENSIONS {
	public int cExtension;
	public IntPtr rgExtension;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CERT_EXTENSION {
	[MarshalAs(UnmanagedType.LPStr)]public String pszObjId;
	public Boolean fCritical;
	public CRYPTOAPI_BLOB Value;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CERT_BASIC_CONSTRAINTS2_INFO {
	public Boolean fCA;
	public Boolean fPathLenConstraint;
	public int dwPathLenConstraint;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPTOAPI_BLOB {
	public int cbData;
	public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_BIT_BLOB {
	public uint cbData;
	public IntPtr pbData;
	public uint cUnusedBits;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CERT_PUBLIC_KEY_INFO {
	public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
	public CRYPT_BIT_BLOB PublicKey;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_ALGORITHM_IDENTIFIER {
	[MarshalAs(UnmanagedType.LPStr)]public String pszObjId;
	public CRYPTOAPI_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SystemTime {
	public short Year;
	public short Month;
	public short DayOfWeek;
	public short Day;
	public short Hour;
	public short Minute;
	public short Second;
	public short Milliseconds;
}
"@
	Add-Type -MemberDefinition $signature -Namespace Quest -Name PowerGUI
	$pszContainer = [Guid]::NewGuid().ToString()
	[IntPtr]$phProv = [IntPtr]::Zero
	$Provider = "Microsoft Base Cryptographic Provider v1.0"
	$Result = [Quest.PowerGUI]::CryptAcquireContext([ref]$phProv,$pszContainer,$Provider,0x1,0x8)
	if (!$Result) {Write-Warning "Unable to create provider context!"; return}
	[IntPtr]$phKey = [IntPtr]::Zero
	if ($KeyLength -eq 2048) {
		$Result = [Quest.PowerGUI]::CryptGenKey($phProv,2,0x08000001,[ref]$phKey)
	} else {
		$Result = [Quest.PowerGUI]::CryptGenKey($phProv,2,0x04000001,[ref]$phKey)
	}
	if (!$Result) {Write-Warning "Unable to create key context!"; return}
	$dataHandle = [Runtime.InteropServices.GCHandle]::Alloc($Subject.RawData,"pinned")
	$ptrName = New-Object Quest.PowerGUI+CRYPTOAPI_BLOB -Property @{
		cbData = $Subject.RawData.Count;
		pbData = $dataHandle.AddrOfPinnedObject()
	}
	$PrivateKey = New-Object Quest.PowerGUI+CRYPT_KEY_PROV_INFO -Property @{
		pwszContainerName = $pszContainer;
		pwszProvName = $Provider;
		dwProvType = 1;
		dwKeySpec = 2
	}
	$Extensions = New-Object Security.Cryptography.X509Certificates.X509ExtensionCollection
	# add Basic Constraints extension
	[void]$Extensions.Add((New-Object Security.Cryptography.X509Certificates.X509BasicConstraintsExtension $false,$false,0,$false))
	# add Code Signing EKU
	$OIDs = New-Object Security.Cryptography.OidCollection
	[void]$OIDs.Add("code signing")
	[void]$Extensions.Add((New-Object Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension -ArgumentList $OIDs, $false))
	# add SKI extension
	$pcbInfo = 0
	if (([Quest.PowerGUI]::CryptExportPublicKeyInfo($phProv,2,1,[IntPtr]::Zero,[ref]$pcbInfo))) {
		$pbInfo = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbInfo)
		$Return = [Quest.PowerGUI]::CryptExportPublicKeyInfo($phProv,2,1,$pbInfo,[ref]$pcbInfo)
		$pcbComputedHash = 0
		if (([Quest.PowerGUI]::CryptHashPublicKeyInfo([IntPtr]::Zero,0x00008004,0,1,$pbInfo,[IntPtr]::Zero,[ref]$pcbComputedHash))) {
			$pbComputedHash = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbComputedHash)
			[void][Quest.PowerGUI]::CryptHashPublicKeyInfo([IntPtr]::Zero,0x00008004,0,1,$pbInfo,$pbComputedHash,[ref]$pcbComputedHash)
			$pcbEncoded = 0
			$uSKI = New-Object Quest.PowerGUI+CRYPTOAPI_BLOB -Property @{
				cbData = $pcbComputedHash;
				pbData = $pbComputedHash
			}
			$pcbEncoded = 0
			if (([Quest.PowerGUI]::CryptEncodeObject(1,"2.5.29.14",[ref]$uSKI,$null,[ref]$pcbEncoded))) {
				$pbEncoded = New-Object byte[] -ArgumentList $pcbEncoded
				$Return = [Quest.PowerGUI]::CryptEncodeObject(1,"2.5.29.14",[ref]$uSKI,$pbEncoded,[ref]$pcbEncoded)
				$AsnEncodedData = New-Object Security.Cryptography.AsnEncodedData -ArgumentList "2.5.29.14", $pbEncoded
				[void]$Extensions.Add((New-Object Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension -ArgumentList $AsnEncodedData, $false))
			}
		}
	}
	# add KeyUsages extension
	[void]$Extensions.Add((New-Object Security.Cryptography.X509Certificates.X509KeyUsageExtension -ArgumentList "DigitalSignature", $true))
	# transform managed extensions to unmanaged structures
	$uExtensionCollection = @()
	foreach ($mExt in $Extensions) {
		$uExtension = New-Object Quest.PowerGUI+CERT_EXTENSION
		$uExtension.pszObjId = $mExt.Oid.Value
		$uExtension.fCritical = $mExt.Critical
		$value = New-Object Quest.PowerGUI+CRYPTOAPI_BLOB
		$value.cbData = $mExt.RawData.Length
		$value.pbData = [Runtime.InteropServices.Marshal]::AllocHGlobal($value.cbData)
		[Runtime.InteropServices.Marshal]::Copy($mExt.RawData,0,$Value.pbData,$Value.cbData)
		$uExtension.Value = $value
		$uExtensionCollection += $uExtension
	}
	$uExtensions = New-Object Quest.PowerGUI+CERT_EXTENSIONS
	$ExtensionSize = [Runtime.InteropServices.Marshal]::SizeOf([Quest.PowerGUI+CERT_EXTENSION]) * $Extensions.Count
	$uExtensions.cExtension = $Extensions.Count
	$uExtensions.rgExtension = [Runtime.InteropServices.Marshal]::AllocHGlobal($ExtensionSize)
	for ($n = 0; $n -lt $Extensions.Count; ++$n) {
		$offset = $n * [Runtime.InteropServices.Marshal]::SizeOf([Quest.PowerGUI+CERT_EXTENSION])
		$next = $offset + $uExtensions.rgExtension.ToInt64()
		[IntPtr]$NextAddress = New-Object IntPtr $next
		[Runtime.InteropServices.Marshal]::StructureToPtr($uExtensionCollection[$n],$NextAddress,$false)
	}
	$pStartTime = New-Object Quest.PowerGUI+SystemTime
	[void][Quest.PowerGUI]::FileTimeToSystemTime([ref]$ValidFrom.ToFileTime(),[ref]$pStartTime)
	$pEndTime = New-Object Quest.PowerGUI+SystemTime
	[void][Quest.PowerGUI]::FileTimeToSystemTime([ref]$ValidTo.ToFileTime(),[ref]$pEndTime)
	$pvContext = [Quest.PowerGUI]::CertCreateSelfSignCertificate($phProv,$ptrName,0,$PrivateKey,[IntPtr]::Zero,$pStartTime,$pEndTime,$uExtensions)
	if (!$pvContext.Equals([IntPtr]::Zero)) {
		New-Object Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $pvContext
	}
	# release memory
	foreach ($uExt in $uExtensionCollection) {
		[void][Runtime.InteropServices.Marshal]::FreeHGlobal($uExt.Value.pbData)
	}
	[void][Runtime.InteropServices.Marshal]::FreeHGlobal($uExtensions.rgExtension)
	[void][Runtime.InteropServices.Marshal]::FreeHGlobal($pbInfo)
	[void][Runtime.InteropServices.Marshal]::FreeHGlobal($pbComputedHash)
	[void]$dataHandle.Free()
	[void][Quest.PowerGUI]::CryptDestroyKey($phKey)
	[void][Quest.PowerGUI]::CryptReleaseContext($phProv,0)
}