Reputation: 73
I know how to sign a XML document using SignedXml (https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.xml.signedxml?view=dotnet-plat-ext-6.0)
I know how to sign data using Azure KeyVault API so the private key keeps secured (https://learn.microsoft.com/en-us/dotnet/api/azure.security.keyvault.keys.cryptography.cryptographyclient.signdata?view=azure-dotnet)
Now I want to combine both, use SignedXml (or creating same result), using the key in the vault without extracting the private key.
Trying to set both values as displayed below does not seem to be correct
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>...</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>...</SignatureValue>
</Signature>
var digestValue = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(xmlDoc.OuterXml));
var signatureValue = new CryptographyClient().SignData(SignatureAlgorithm.RS256, digestValue);
Upvotes: 1
Views: 511
Reputation: 73
SignedXml signedXml = new SignedXml(tokenDoc);
var reference = new Reference("");
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
signedXml.AddReference(reference);
signedXml.SigningKey = new KeyVaultRsa();
signedXml.ComputeSignature();
var xmlDigitalSignature = signedXml.GetXml();
internal class KeyVaultRsa : RSA
{
public override RSAParameters ExportParameters(bool includePrivateParameters)
{
throw new NotImplementedException();
}
public override void ImportParameters(RSAParameters parameters)
{
throw new NotImplementedException();
}
public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
{
var keyId = new Uri("https://xxx.vault.azure.net/keys/xxx");
var rsaCryptoClient = new Azure.Security.KeyVault.Keys.Cryptography.CryptographyClient(keyId, new Azure.Identity.DefaultAzureCredential());
var result = rsaCryptoClient.Sign(Azure.Security.KeyVault.Keys.Cryptography.SignatureAlgorithm.RS256, hash);
return result.Signature;
}
}
Upvotes: 0
Reputation: 12108
You need to implement custom class inherited from System.Security.Cryptography.RSA
class, use KeyVault API in its implementation and then use instance of your custom class as a SigningKey
.
You can implement it yourself or you can use RSAKeyVaultProvider library.
Upvotes: 1