在签名的XML上验证签名

时间:2019-07-11 09:47:26

标签: xml powershell signed

我已成功修改this code以便在XML文件上签名并验证签名。但是我在没有安装证书的计算机上验证签名时遇到麻烦。我发现this是在C#中进行此操作的Microsoft参考,但这似乎也需要安装Cert。还是“密钥容器”只是使用同一证书签名的可执行文件?因为我的C#技能很弱,所以有人可以使用PowerShell而不是C#指向我的资源吗! 似乎无需安装证书即可验证XML上的签名。手指交叉。

1 个答案:

答案 0 :(得分:1)

  

然后在未安装证书的计算机上验证签名时遇到麻烦。

这很有道理!

公钥签名验证的基础是……好吧,用于签名的任何密钥的公钥部分-证书是认证和分发公钥的一种超通用方式!

因此,您要么需要公开提供证书(没有私钥),要么将公钥材料导出并发送到签名的文档旁边。

我们可以更新Sign-XML例程,将证书本身复制到xml文档中的签名blob中,如下所示:

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()的第二个参数意味着,如果用户指定-Force