Konwersja PKI-Expiration-Period

W związku z moimi ostatnimi zainteresowaniami dotyczącymi obsługi szablonów certyfikatów z poziomu PowerShella, zrodził się problem dotyczący zdekodowania okresu ważności certyfikatu. W przypadku narzędzi graficznych nie ma problemów okres ważności wybieramy z listy natomiast samą wartość wpisujemy w formie liczby. Problem rodzi się gdy chcemy tego dokonać z poziomu PowerShella.

$ConfigContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext
$ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"
$ADSI.psbase.children | Where-Object {$_.displayName -eq "My Code Signing"} | Select-Object pKIExpirationPeriod, pKIOverlapPeriod

Jak widzimy nie ma już tak różowo. Sama wartość zapisana jest w formie ciągu bajtów, z pozoru nie wyglądających na jakiś uporządkowany schemat.

W dokumentacji tego standardu możemy znaleźć takie wzmianki:

  • pKIExpirationPeriod – Validity period. Negative FILETIME value.
  • pKIOverlapPeriod – Renewal period. Negative FILETIME value.

OK, ale zapewne stwierdzenie „Negative FILETIME” samo w sobie nie wiele mówi. Z bardziej szczegółowej dokumentacji dotyczącej protokołów Windows Server ([MS -CRTD]: Certificate Templates Structure) możemy dowiedzieć się, iż jest to ciąg ośmiu bajtów zapisanych w formacie little-endian. Wartość ta stanowi całkowitą liczbę dziesietną reprezentującą czas w odstępach 100 nanosekund.

Zanim przejdę dalej wyjaśnię tylko co oznacza zapis w formacie Little/Big-Endian.

  • Zapis Big-Endian to standardowy sposób zapisu liczb, czyli od lewej do prawej, np. liczbę 004039872EE1FEFF zapisaną w systemie szestnastkowym odczytujemy normalnie w formie poszczególnych bajtów 00 40 39 87 2E E1 FE FF.
  • Natomiast odczyt zapisu Little-Endian polega na odwrotnym odczytaniu poszczeglnych bajtów, czyli dla w/w przykładu, będzie to FF FE E1 2E 87 39 40 00.

Przystąpmy zatem do dekodowania okresu ważności certyfikatu. Do tego pobierzmy tą wartoś do zmiennej:

$ConfigContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext 
$ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext" 
$MyCertPeriod = $ADSI.psbase.children | Where-Object {$_.displayName -eq "My Code Signing"} | Select-Object pKIExpirationPeriod, pKIOverlapPeriod

Następnie zacznijmy odczytywać tą wartość w formacie Little-Endian, tzn. od końca. Do tego celu posłużymy się pętla for.

$ByteArray = $MyCertPeriod.pKIExpirationPeriod[0]
$LittleEndianByte = ""
For ($($i = 0; $j = $ByteArray.count - 1) ; $i -lt $ByteArray.count ; $($i++; $j--)) { ... }

Podczas tego procesu następować będzie również konwersja bajtów z formy dziesiętnej na szesnastkową, z jednoczesnym uzupełnieniem niskich wartości początkowym „0” w celu zachowania odpowiedniego formatu.

If($ByteArray[$j] -lt 16)
{
	$LittleEndianByte += "0{0:X}" -f [Int]$ByteArray[$j]
}
Else
{
	$LittleEndianByte += "{0:X}" -f [Int]$ByteArray[$j]
}

Ostatecznie tak spreparowaną liczbę konwertujemy na system dziesiętny.

[Convert]::ToInt64($LittleEndianByte,16)

Jak widzimy powstała liczba szestnastkowa stanowi tak naprawdę ujemną liczbę dziesiętną stąd notacja „Negative FILETIME”. Powstały wynik reprezentuje okres liczony w 100 nanosekundach. By jednak wartość tą przedstawić w sposób bardziej przyjazny dla użytkownika, wystarczy pomnożyć ją razy -100 * 10^-9, czyli -0.0000001. Będzie to przedstawiać liczbę sekund po których wygaśnie certyfikat.

([Convert]::ToInt64($LittleEndianByte,16))*(-0.0000001)

Całość możemy zapisać w formie funkcji:

Function Convert-pKIPeriod
{
	Param
	(
		[parameter(Mandatory=$true)]
		[Byte[]]$ByteArray
	)

	Process
	{
		$LittleEndianByte = ""
		For ($($i = 0; $j = $ByteArray.count - 1) ; $i -lt $ByteArray.count ; $($i++; $j--))
		{
			If($ByteArray[$j] -lt 16)
			{
				$LittleEndianByte += "0{0:X}" -f [Int]$ByteArray[$j]
			}
			Else
			{
				$LittleEndianByte += "{0:X}" -f [Int]$ByteArray[$j]
			}
		}
		$Period = ([Convert]::ToInt64($LittleEndianByte,16))*(-0.0000001)
		Return $Period
	}
}

$Period = Convert-pKIPeriod -ByteArray 0,152,59,158,247,255,255,255
$Period
$Period/(60*60) #1 godzina

$Period = Convert-pKIPeriod -ByteArray 0,64,150,213,54,255,255,255
$Period
$Period/(24*60*60) #1 dzień

$Period = Convert-pKIPeriod -ByteArray 0,192,27,215,127,250,255,255
$Period
$Period/(24*7*60*60) #1 tydzień

$Period = Convert-pKIPeriod -ByteArray 0,128,155,7,109,232,255,255
$Period
$Period/(24*30*60*60) #1 miesiąc

$Period = Convert-pKIPeriod -ByteArray 0,64,57,135,46,225,254,255
$Period
$Period/(24*365*60*60) #1 rok

Reklamy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s