Wie wird der Dateiname des Windows MachineKey-Containers abgeleitet?

7

Im C:\ProgramData\Microsoft\Crypto\RSA\MachineKeysVerzeichnis gibt es eine Aufzählung der Schlüsselcontainer. Die Namenskonvention ist <uniqueGUID>_<staticGUID>und ich nehme <staticGUID>an, dass es sich um eine Maschinenkennung handelt. Letztendlich möchte ich in der Lage sein, den Schlüsselcontainer mit dem entsprechenden Zertifikat zu koppeln, damit ich auf bestimmte Schlüsseldateien für ACLs abzielen kann. Dazu muss ich wissen, wie das <uniqueGUID>abgeleitet wird und wie es sich auf Zertifikate bezieht.

Die Microsoft-Ressourcen, die ich bisher überprüft habe, haben keine Antwort geklärt, eignen sich jedoch hervorragend als Referenz:

Grundlegendes zu RSA-Schlüsselcontainern auf Maschinenebene und Benutzerebene (IIS-Referenz)

Gewusst wie: Ändern Sie die Sicherheitsberechtigungen für das MachineKeys-Verzeichnis

Colyn1337
quelle

Antworten:

13

Verwenden Sie Folgendes, um das Problem zu lösen, welches Zertifikat zu welcher Schlüsseldatei gehört, um Dateisystem-ACLs für die privaten Schlüsseldateien zu ändern:

PS C:\Users\Ryan> $Cert = Get-Item Cert:\LocalMachine\My\2F6CB7D56BAA752BCCC0829DD829C0E2662FA1C6    

PS C:\Users\Ryan> $Cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName

fad662b360941f26a1193357aab3c12d_03f917b5-cb8b-45bd-b884-41c139a66ff7

Die Dateinamenskonvention lautet x_y, wobei x eine zufällige GUID zur eindeutigen Identifizierung des Schlüssels ist und y die Maschinen-GUID ist, unter der gefunden wird HKLM\SOFTWARE\Microsoft\Cryptography.

Einige dieser eindeutigen Kennungen sind bekannt, z. B. einige dieser IIS-Kennungen:

6de9cb26d2b98c01ec4e9e8b34824aa2_GUID      iisConfigurationKey

d6d986f09a1ee04e24c949879fdb506c_GUID      NetFrameworkConfigurationKey

76944fb33636aeddb9590521c2e8815a_GUID      iisWasKey

Andere werden jedoch zufällig generiert.

Beachten Sie, dass diese Informationen nur für Zertifikate / Schlüssel "Lokaler Computer" oder "Computer" gelten. Benutzerzertifikate werden an den entsprechenden benutzerspezifischen Speicherorten im Dateisystem und in der Registrierung gespeichert.

Ryan Ries
quelle
6

Ryan Ries lieferte nur eine Teillösung, da dies bei CNG-Schlüsseln nicht funktioniert. Der folgende Code ruft den Containernamen (daher auch den Dateinamen) für CNG-Schlüssel ab:

$signature = @"
[DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CertGetCertificateContextProperty(
    IntPtr pCertContext,
    uint dwPropId,
    IntPtr pvData,
    ref uint pcbData
);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CRYPT_KEY_PROV_INFO {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string pwszContainerName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string pwszProvName;
    public uint dwProvType;
    public uint dwFlags;
    public uint cProvParam;
    public IntPtr rgProvParam;
    public uint dwKeySpec;
}
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptOpenStorageProvider(
    ref IntPtr phProvider,
    [MarshalAs(UnmanagedType.LPWStr)]
    string pszProviderName,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptOpenKey(
    IntPtr hProvider,
    ref IntPtr phKey,
    [MarshalAs(UnmanagedType.LPWStr)]
    string pszKeyName,
    uint dwLegacyKeySpec,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptGetProperty(
    IntPtr hObject,
    [MarshalAs(UnmanagedType.LPWStr)]
    string pszProperty,
    byte[] pbOutput,
    int cbOutput,
    ref int pcbResult,
    int dwFlags
);
[DllImport("ncrypt.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int NCryptFreeObject(
    IntPtr hObject
);
"@
Add-Type -MemberDefinition $signature -Namespace PKI -Name Tools

$CERT_KEY_PROV_INFO_PROP_ID = 0x2 # from Wincrypt.h header file
$cert = dir cert:\currentuser\my\C541C66F490413302C845A440AFA24E98A231C3C
$pcbData = 0
[void][PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,[IntPtr]::Zero,[ref]$pcbData)
$pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbData)
[PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,$pvData,[ref]$pcbData)
$keyProv = [Runtime.InteropServices.Marshal]::PtrToStructure($pvData,[type][PKI.Tools+CRYPT_KEY_PROV_INFO])
[Runtime.InteropServices.Marshal]::FreeHGlobal($pvData)
$phProvider = [IntPtr]::Zero
[void][PKI.Tools]::NCryptOpenStorageProvider([ref]$phProvider,$keyProv.pwszProvName,0)
$phKey = [IntPtr]::Zero
[void][PKI.Tools]::NCryptOpenKey($phProvider,[ref]$phKey,$keyProv.pwszContainerName,0,0)
$pcbResult = 0
[void][PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$null,0,[ref]$pcbResult,0)
$pbOutput = New-Object byte[] -ArgumentList $pcbResult
[void][PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$pbOutput,$pbOutput.length,[ref]$pcbResult,0)
[Text.Encoding]::Unicode.GetString($pbOutput)
[void][PKI.Tools]::NCryptFreeObject($phProvider)
[void][PKI.Tools]::NCryptFreeObject($phKey)
Crypt32
quelle
1
+1. Meinetwegen. Meine Antwort bezieht sich nur auf eine CryptoAPI-Perspektive und nicht auf CNG. Andererseits fragte OP nicht nach CNG. Hätte OP in seiner Frage etwas über% ALLUSERSPROFILE% \ Anwendungsdaten \ Microsoft \ Crypto \ RSA \ S-1-5-18 \ gesagt, wäre meine Antwort anders gewesen. Vollständigkeit ist jedoch immer willkommen! Für OP, msdn.microsoft.com/en-us/library/windows/desktop/…
Ryan Ries
0

Ich habe den Code von CryptoGuy verwendet, ihn erheblich erweitert und in eine Funktion umgewandelt. Es gibt jedoch noch Raum für Verbesserungen. Danke, CryptoGuy!

function Get-KeyContainer {
  [CmdletBinding()]
  Param([Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [string]$Thumbprint,
        [Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$false)] [switch]$MachineStore)

  $MemberDefinition=@"
  [DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  public static extern bool CertGetCertificateContextProperty(
    IntPtr pCertContext,
    uint dwPropId,
    IntPtr pvData,
    ref uint pcbData);

  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
  public struct CRYPT_KEY_PROV_INFO {
    [MarshalAs(UnmanagedType.LPWStr)] public string pwszContainerName;
    [MarshalAs(UnmanagedType.LPWStr)] public string pwszProvName;
    public uint dwProvType;
    public uint dwFlags;
    public uint cProvParam;
    public IntPtr rgProvParam;
    public uint dwKeySpec;}

  [DllImport("ncrypt.dll", SetLastError = true)]
  public static extern int NCryptOpenStorageProvider(
    ref IntPtr phProvider,
    [MarshalAs(UnmanagedType.LPWStr)] string pszProviderName,
    uint dwFlags);

  [DllImport("ncrypt.dll", SetLastError = true)]
  public static extern int NCryptOpenKey(
    IntPtr hProvider,
    ref IntPtr phKey,
    [MarshalAs(UnmanagedType.LPWStr)] string pszKeyName,
    uint dwLegacyKeySpec,
    uint dwFlags);

  [DllImport("ncrypt.dll", SetLastError = true)]
  public static extern int NCryptGetProperty(
    IntPtr hObject,
    [MarshalAs(UnmanagedType.LPWStr)] string pszProperty,
    byte[] pbOutput,
    int cbOutput,
    ref int pcbResult,
    int dwFlags);

  [DllImport("ncrypt.dll", CharSet=CharSet.Auto, SetLastError=true)]
  public static extern int NCryptFreeObject(IntPtr hObject);
"@
  Add-Type -MemberDefinition $MemberDefinition -Namespace PKI -Name Tools

  $CERT_KEY_PROV_INFO_PROP_ID = 0x2 # from Wincrypt.h header file
  # from Ncrypt.h header file
  if ($MachineStore.IsPresent) { $NCRYPT_MACHINE_KEY_FLAG = 0x20 }
  else { $NCRYPT_MACHINE_KEY_FLAG = 0 }

  $cert=Get-Item -Path ("Cert:\LocalMachine\My\"+$Thumbprint)
  $pcbData = 0
  $result=[PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,[IntPtr]::Zero,[ref]$pcbData)
  if ($result -ne $true) {
    switch ($result) {
      -2146885628 { Write-Error "ERROR:  CRYPT_E_NOT_FOUND 0x80092004 (-2146885628)`r`nThe certificate does not have the specified property." }
      -2005270525 { Write-Error "ERROR:  ERROR_MORE_DATA 0x887A0003 (-2005270525)`r`nIf the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbData." }
    }
    exit
  }
  $pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbData)
  $result=[PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,$pvData,[ref]$pcbData)
  if ($result -ne $true) {
    switch ($result) {
      -2146885628 { Write-Error "ERROR:  CRYPT_E_NOT_FOUND 0x80092004 (-2146885628)`r`nThe certificate does not have the specified property." }
      -2005270525 { Write-Error "ERROR:  ERROR_MORE_DATA 0x887A0003 (-2005270525)`r`nIf the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbData." }
    }
    exit
  }
  $keyProv = [Runtime.InteropServices.Marshal]::PtrToStructure($pvData,[type][PKI.Tools+CRYPT_KEY_PROV_INFO])
  [Runtime.InteropServices.Marshal]::FreeHGlobal($pvData)
  $phProvider = [IntPtr]::Zero
  $result=[PKI.Tools]::NCryptOpenStorageProvider([ref]$phProvider,$keyProv.pwszProvName,0)
  if ($result -ne 0) {
    switch ($result) {
      -2146893815 { Write-Error "ERROR:  NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nInvalid flags specified" }
      -2146893785 { Write-Error "ERROR:  NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" }
      -2146893810 { Write-Error "ERROR:  NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" }
    }
    exit
  }
  $phKey = [IntPtr]::Zero
  $result=[PKI.Tools]::NCryptOpenKey($phProvider,[ref]$phKey,$keyProv.pwszContainerName,0,$NCRYPT_MACHINE_KEY_FLAG)
  if ($result -ne 0) {
    switch ($result) {
      -2146893815 { Write-Error "ERROR:  NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nThe dwFlags parameter contains a value that is not valid." }
      -2146893802 { Write-Error "ERROR:  NTE_BAD_KEYSET 0x80090016 (-2146893802)`r`nThe specified key was not found.  Try using the -MachineKey flag to look in the Machine's store instead of the User's store." }
      -2146893786 { Write-Error "ERROR:  NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid." }
      -2146893785 { Write-Error "ERROR:  NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" }
      -2146893810 { Write-Error "ERROR:  NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" }
    }
    exit
  }
  $pcbResult = 0
  $result=[PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$null,0,[ref]$pcbResult,0)
  if ($result -ne 0) {
    switch ($result) {
      -2146893815 { Write-Error "ERROR:  NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nThe dwFlags parameter contains a value that is not valid." }
      -2146893786 { Write-Error "ERROR:  NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid." }
      -2146893785 { Write-Error "ERROR:  NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" }
      -2146893810 { Write-Error "ERROR:  NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" }
      -2146893783 { Write-Error "ERROR:  NTE_NOT_SUPPORTED 0x80090029 (-2146893783)`r`nThe specified property is not supported for the object." }
    }
    exit
  }
  $pbOutput = New-Object byte[] -ArgumentList $pcbResult
  $result=[PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$pbOutput,$pbOutput.length,[ref]$pcbResult,0)
  if ($result -ne 0) {
    switch ($result) {
      -2146893815 { Write-Error "ERROR:  NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nThe dwFlags parameter contains a value that is not valid." }
      -2146893786 { Write-Error "ERROR:  NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid." }
      -2146893785 { Write-Error "ERROR:  NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" }
      -2146893810 { Write-Error "ERROR:  NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" }
      -2146893783 { Write-Error "ERROR:  NTE_NOT_SUPPORTED 0x80090029 (-2146893783)`r`nThe specified property is not supported for the object." }
    }
    exit
  }
  [Text.Encoding]::Unicode.GetString($pbOutput)
  $result=[PKI.Tools]::NCryptFreeObject($phProvider)
  if ($result -ne 0) { Write-Error "ERROR:  NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid."; exit }
  [void][PKI.Tools]::NCryptFreeObject($phKey)
  if ($result -ne 0) { Write-Error "ERROR:  NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid."; exit }
}

Get-KeyContainer -Thumbprint "xxxxxxxxx" -MachineStore
Slogmeister Extraordinaire
quelle