Проверить подпись на подписанном XML - PullRequest
0 голосов
/ 11 июля 2019

Я успешно изменил этот код , чтобы подписать и проверить подпись в файле XML.Но у меня возникают проблемы при проверке подписи на компьютере, на котором не установлен сертификат.Я нашел этот справочник Microsoft по выполнению этого в C #, но для этого также требуется установить сертификат.Или «Контейнер ключей» - это просто исполняемый файл, подписанный тем же сертификатом?Может кто-то указать мне на ресурс для этого, используя PowerShell, а не C #, так как мои навыки в C # СЛАБЫЕ!Похоже, что проверка подписи на XML без установки сертификата должна быть возможной.Скрестив пальцы.

1 Ответ

1 голос
/ 11 июля 2019

У меня проблемы с проверкой подписи на машине, на которой не установлен сертификат.

Это имеет смысл!

Основой для проверки подписи с открытым ключом является ... ну, открытый ключ часть любого ключа, который использовался для подписи чего-либо - и сертификаты являются супер распространенным способом аутентификации и распространения открытыхkeys!

Таким образом, необходимо либо сделать сертификат (без секретного ключа) общедоступным, либо экспортировать и отправить материал с открытым ключом вместе с подписанным документом.

Мы можем обновить Sign-XML процедура копирования самого сертификата в бланк подписи в XML-документе, например так:

function Sign-XML {
    param(
      [xml]$xml, 
      [System.Security.Cryptography.X509Certificates.X509Certificate2]$certificate
    )

    [System.Security.Cryptography.xml.SignedXml]$signedXml = $NULL
    $signedXml = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $xml

    # Grab the PrivateKey from the cert - fail if not present
    if(-not $certificate.HasPrivateKey){
        throw 'Private Key not passed to Sign-XML, cannot sign document'
        return
    }
    $signedXml.SigningKey = $certificate.PrivateKey

    # Add a KeyInfo blob to the SignedXml element
    # KeyInfo blob will hold the certificate and therefore the public key
    $keyInfo = New-Object System.Security.Cryptography.Xml.KeyInfo
    $keyInfo.AddClause((New-Object System.Security.Cryptography.Xml.KeyInfoX509Data -ArgumentList $certificate))
    $signedXml.KeyInfo = $keyInfo

    $Reference = New-Object System.Security.Cryptography.Xml.Reference
    $Reference.Uri = ""

    $env = New-Object System.Security.Cryptography.Xml.XmlDsigEnvelopedSignatureTransform

    $Reference.AddTransform($env);
    $signedXml.AddReference($Reference)
    $signedXml.ComputeSignature()

    [System.Xml.XmlElement]$xmlSignature = $signedXml.GetXml()
    #Add signature to end of xml file
    [void]$xml.DocumentElement.AppendChild($xml.ImportNode($xmlSignature, $true))

    if ($xml.FirstChild -is [system.xml.XmlDeclaration]) {
        [void]$xml.RemoveChild($xml.FirstChild);
    }
    $xml
}

Здесь следует обратить внимание на две вещи:

  1. Второй параметр теперь принимает X509Certificate2объект вместо контейнера необработанных ключей
  2. Мы добавляем предложение KeyInfoX509Data к информации о подписи в документе, содержащем сертификат

Теперь, когда сертификат является частью подписанного документа,получатель может легко проверить подпись и открытый ключ программно:

function Verify-XmlSignature {
    Param (
        [xml]$checkxml,
        [switch]$Force
    )

    # Grab signing certificate from document
    $rawCertBase64 = $signed.DocumentElement.Signature.KeyInfo.X509Data.X509Certificate

    if(-not $rawCertBase64){
        throw 'Unable to locate signing certificate in signed document'
        return
    }

    $rawCert = [convert]::FromBase64String($rawCertBase64)
    $signingCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @(,$rawCert)

    [System.Security.Cryptography.Xml.SignedXml]$signedXml = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $checkxml
    $XmlNodeList = $checkxml.GetElementsByTagName("Signature")
    $signedXml.LoadXml([System.Xml.XmlElement] ($XmlNodeList[0]))
    return $signedXml.CheckSignature($signingCertificate, $Force)
}

Передача $Force во второй аргумент CheckSignature() meи что проверка доверия к самому сертификату не повлияет на результат процедуры проверки, если пользователь укажет -Force

...