Windows PKI team always knows how to make our live harder :). Yesterday Shay Levy pointed me to one interesting thread: http://www.powergui.org/thread.jspa?messageID=47514

Basic intro: this attribute is used by Credential Roaming Service. By default if user uses roaming profile, credentials (and personal certificates) don’t roam! This means that user can use the same profile on other computers, but will not able to use certificates (i.e. decrypt files, mails, sign documents and so on). Though if certificate autoenrollment is enabled, user will enroll new certificates. But they will remain on that computer only. The one possible way to work around this issue is to use smart cards. But this is quite expensive solution. With Credential Roaming Service all certificates will roam with user. However this is not pretty secure solution, because domain administrators will have an access to user private keys. However at certain point domain users must trust administrators, so this solution is enough for many scenarios with roaming profiles.

Right now, return to initial task. Timestamp attribute value is stored as a simple hex string and defined as described here: http://msdn.microsoft.com/en-us/library/cc220501(PROT.13).aspx. However there is no any additional info about value structure and encoding/decoding rules. Let’s explore it now:

In a given example, attribute value is: A04BB369755ACB01AC0F92564AB6CB01. I’ve tried various methods to decode, but with no success. However I’ve noticed that there are 2 repeating bytes: CB 01 at the middle and the end of the string. Split this string to 2 substrings and you will get Created and Modified dates:

  • A04BB369755ACB01
  • AC0F92564AB6CB01

Split each string to a byte array as follows:

  • A0,4B,B3,69,75,5A,CB,01
  • AC,0F,92,56,4A,B6,CB,01

Due of cryptography history, it uses little-endian encoding, therefore you must reverse these arrays and concatenate reversed bytes to a hex string:

  • 0x01cb5a7569b34ba0
  • 0x01cbb64a56920fac

Decimal value of each string will represent ticks count starting with 1600 year. Active Directory uses this year as a base for any date/time values. I wrote a little script that will convert ms-PKI-Roaming-TimeStamp attribute value to a common DateTime objects:

#####################################################################
# Decode ms-PKI-Roaming-TimeStamp.ps1
# Version 1.0
#
# Decode ms-PKI-Roaming-TimeStamp attribute value to a generic DateTime objects
#
# Vadims Podans (c) 2011
# http://en-us.sysadmins.lv/
#####################################################################
#requires -Version 2.0

function Decode-msPKIRoamingTimeStamp {
[OutputType('DateTime[]')]
[CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateLength(32,32)]
        [string]$msPKIRoamingTimeStamp
    )
    # convert string to a byte array
    $Full = $msPKIRoamingTimeStamp -split "([a-f0-9]{2})" | ?{$_}
    # property value contains both Creation and Modified time values, so we
    # divide array to two sub arrays
    $Created = $Full[0..($Full.Count / 2 - 1)]
    $Modified = $Full[($Full.Count / 2)..($Full.Count - 1)]
    # since values are stored in little-endian encoding, reverse both sub arrays
    [array]::Reverse($Created)
    [array]::Reverse($Modified)
    # concatenate each byte (now in reversed form) to a hex string
    $hexCreated = -join $Created
    $hexModified = -join $Modified
    # now we retrieve each hex string numerical value that will represent ticks count
    # starting with 1600 year
    $ticksCreated = Invoke-Expression 0x$($hexCreated)
    $ticksModified = Invoke-Expression 0x$($hexModified)
    # create empty DateTime object
    $DateTime = New-Object DateTime
    # in order to get initial DateTime value append 1600 years
    $DateTime = $DateTime.AddYears(1600)
    # and now append ticks to get familiar DateTime objects that represent msPKIRoamingTimeStamp
    # actual values
    $DateTime.AddTicks($ticksCreated)
    $DateTime.AddTicks($ticksModified)
}

The first returned value is Created date and the second is Modified.


Share this article:

Comments:


Post your comment:

Please, solve this little equation and enter result below. Captcha