''
'' This code is part of Document Solutions for PDF .NET demos.
'' Copyright (c) MESCIUS inc. All rights reserved.
''
Imports System
Imports System.IO
Imports System.Drawing
Imports System.Security.Cryptography.X509Certificates
Imports Org.BouncyCastle.Crypto
Imports Org.BouncyCastle.Crypto.Digests
Imports Org.BouncyCastle.Asn1
Imports Org.BouncyCastle.Asn1.X509
Imports Azure.Core
Imports Azure.Identity
Imports Azure.Security.KeyVault.Certificates
Imports Azure.Security.KeyVault.Keys
Imports Azure.Security.KeyVault.Keys.Cryptography
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.Security
Imports GrapeCity.Documents.Pdf.AcroForms
Imports GrapeCity.Documents.Text
'' This sample shows how to sign an existing PDF file that contains
'' an empty signature field with a certificate that is stored
'' in an Azure Key Vault.
''
'' The sample includes a ready to use utility class AzureSignatureGenerator
'' that implements the GrapeCity.Documents.Pdf.IPkcs7SignatureGenerator interface,
'' and can be used to sign PDFs with certificates stored in Azure Key Vault.
''
'' Please note that when run directly off the DsPdf demo site,
'' this sample will NOT sign the PDF, as it passes dummy Azure credentials
'' to the AzureSignatureGenerator's ctor. You will need to download the sample
'' and provide your own credentials for the sample code to actually sign a PDF.
Public Class SignAzureKeyVault
Function CreatePDF(ByVal stream As Stream) As Integer
Dim doc = New GcPdfDocument()
Using s = File.OpenRead(Path.Combine("Resources", "PDFs", "SignAzureKeyVault.pdf"))
doc.Load(s)
Try
'' This WILL NOT WORK due to dummy Azure credentials.
'' Supply valid credentials to actually sign the PDF.
Using sg = New AzureSignatureGenerator(
"keyVaultName",
"tenantId",
"clientId",
"clientSecret",
"certificateName")
Dim sp = New SignatureProperties() With {
.SignatureBuilder = New Pkcs7SignatureBuilder() With {
.SignatureGenerator = sg,
.CertificateChain = New X509Certificate2() {sg.Certificate}
},
.SignatureField = doc.AcroForm.Fields(0)
}
doc.Sign(sp, stream)
End Using
Catch e As Exception
Dim page = doc.Pages(0)
Dim r = doc.AcroForm.Fields(0).Widgets(0).Rect
Util.AddNote(
"Signing failed because dummy Azure credentials were used." & vbLf &
"Use valid Azure Key Vault credentials to sign the PDF.",
page,
New RectangleF(r.Left, r.Bottom + 24, page.Size.Width - r.Left * 2, 0))
doc.Save(stream)
End Try
End Using
'' Done.
Return doc.Pages.Count
End Function
End Class
''' <summary>
''' Implements IPkcs7SignatureGenerator
''' and allows generating a digital signature using
''' a certificate stored in Azure Key Vault.
''' </summary>
Public Class AzureSignatureGenerator
Implements IPkcs7SignatureGenerator
Implements IDisposable
Private _certificateClient As CertificateClient
Private _certificate As X509Certificate2
Private _cryptographyClient As CryptographyClient
''' <summary>
''' Initializes a new instance of the AzureSignatureGenerator class.
''' </summary>
Public Sub New(
ByVal keyVaultName As String,
ByVal tenantId As String,
ByVal clientId As String,
ByVal clientSecret As String,
ByVal certificateName As String)
Dim keyVaultUri = New Uri($"https://{keyVaultName}.vault.azure.net/")
Dim credential As TokenCredential = New ClientSecretCredential(tenantId, clientId, clientSecret)
_certificateClient = New CertificateClient(keyVaultUri, credential)
Dim c = _certificateClient.GetCertificate(certificateName)
_certificate = New X509Certificate2(c.Value.Cer)
_cryptographyClient = New CryptographyClient(c.Value.KeyId, credential)
End Sub
''' <summary>
''' Gets the ID of the hash algorithm.
''' </summary>
Public ReadOnly Property HashAlgorithm As OID Implements IPkcs7SignatureGenerator.HashAlgorithm
Get
Return OID.HashAlgorithms.SHA256
End Get
End Property
''' <summary>
''' Gets the ID of the encryption algorithm.
''' </summary>
Public ReadOnly Property DigestEncryptionAlgorithm As OID Implements IPkcs7SignatureGenerator.DigestEncryptionAlgorithm
Get
Return OID.EncryptionAlgorithms.RSA
End Get
End Property
''' <summary>
''' Gets the certificate.
''' </summary>
Public ReadOnly Property Certificate As X509Certificate2
Get
Return _certificate
End Get
End Property
''' <summary>
''' Signs data.
''' </summary>
Public Function SignData(ByVal input As Byte()) As Byte() Implements IPkcs7SignatureGenerator.SignData
Dim hashDigest = New Sha256Digest()
Dim hash = New Byte(hashDigest.GetDigestSize() - 1) {}
hashDigest.Reset()
hashDigest.BlockUpdate(input, 0, input.Length)
hashDigest.DoFinal(hash, 0)
Dim result As Byte() = _cryptographyClient.Sign(SignatureAlgorithm.RS256, hash).Signature
Return result
End Function
''' <summary>
''' Releases resources used by this object.
''' </summary>
Public Sub Dispose() Implements IDisposable.Dispose
_certificateClient = Nothing
If _certificate IsNot Nothing Then
_certificate.Dispose()
_certificate = Nothing
End If
_cryptographyClient = Nothing
End Sub
End Class