У меня проблемы с проверкой подписи на машине, на которой не установлен сертификат.
Это имеет смысл!
Основой для проверки подписи с открытым ключом является ... ну, открытый ключ часть любого ключа, который использовался для подписи чего-либо - и сертификаты являются супер распространенным способом аутентификации и распространения открытых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
}
Здесь следует обратить внимание на две вещи:
- Второй параметр теперь принимает
X509Certificate2
объект вместо контейнера необработанных ключей - Мы добавляем предложение
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