''
'' 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.Text
Imports System.Linq
Imports System.Collections.Generic
Imports System.Security.Cryptography
Imports System.Security.Cryptography.X509Certificates
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 containing
'' an empty signature field with a signature that complies with
'' the various PAdES (PDF Advanced Electronic Signatures) levels.
'' Note that when run online, this sample simply returns an unsigned
'' PDF with an empty signature field. To actually sign the PDF
'' you will need to provide a valid .pfx file (see "JohnDoe.pfx").
'' The sample contains 5 methods that can be used to sign a PDF
'' with the various PAdES levels, the last 3 methods can be
'' used in a chain to incrementally increase the signature strength.
'' To check the signature compliance, open the signed PDF in Acrobat
'' Reader and inspect the signature properties.
''
'' IMPORTANT! The code in this sample WILL NOT work correctly
'' unless DsPdf is licensed with a valid license key.
'' Email us.sales@mescius.com to obtain a trial key.
Public Class PadesLevels
'' Certificate issued by CA Cert Signing Authority, used for verification:
Shared s_caCertRoot As New X509Certificate2(Path.Combine("Resources", "Misc", "CACertRoot.crt"))
'' TODO: replace with a real certificate:
Shared s_cert As New X509Certificate2(Path.Combine("Resources", "Misc", "JohnDoe.pfx"), "secret")
Shared Sub New()
'' TODO: GcPdfDocument MUST BE LICENSED for the signatures to remain valid,
'' as otherwise the license nag text added when saving the PDF invalidates
'' incremental updates. Email us.sales@mescius.com to obtain a trial key.
'' GcPdfDocument.SetLicenseKey("my key")
End Sub
Function CreatePDF(ByVal stream As Stream, Optional paramsIdx As Integer = 0) As Integer
Return CreatePDF(stream, GetSampleParamsList()(paramsIdx))
End Function
'' While this sample includes code that does the actual signing and time stamping,
'' that code is NOT executed by the online demo. So the online sample driver
'' simply returns the PDF that includes info about the selected PAdES level,
'' and can be signed or time stamped using a valid certificate.
'' You can copy the corresponding code and use it in your applications.
Function CreatePDF(ByVal stream As Stream, ByVal sampleParams As String()) As Integer
'' TODO: change to True to actually run the signing/time stamping code:
Dim doSigning = False
'' The unsigned PDF with a signature field to sign:
Dim fn = Path.Combine("Resources", "PDFs", sampleParams(3))
If doSigning Then
'' Running this code will produce 5 PDFs with increasing PAdES levels:
'' PAdES B-B:
Do_B_B(fn)
'' PAdES B-T:
Do_B_T(fn)
'' Note that the next 3 steps use PDFs produced by the previous step,
'' incrementally adding verification info:
'' PAdES B-LT:
Do_B_LT("B-T.pdf")
'' PAdES B-LTA:
Do_B_LTA("B-LT.pdf")
'' LTV Enabled:
Do_B_LTA_LTV("B-LTA.pdf")
End If
'' Copy the source PDF to output stream to provide the demo result:
Using fs = File.OpenRead(fn)
Dim doc = New GcPdfDocument()
doc.Load(fs)
Dim pageCount = doc.Pages.Count
fs.Seek(0, SeekOrigin.Begin)
fs.CopyTo(stream)
Return pageCount
End Using
End Function
'' Signs a PDF with a PAdES B-B Level signature:
Sub Do_B_B(ByVal fn As String)
Using fs As FileStream = File.OpenRead(fn)
Dim doc = New GcPdfDocument()
doc.Load(fs)
Dim signField = doc.AcroForm.Fields.FirstOrDefault(Function(f_) TypeOf f_ Is SignatureField)
If signField Is Nothing Then
Throw New Exception("Could not find a signature field.")
End If
Dim sp = New SignatureProperties() With {
.SignatureField = signField,
.SignatureBuilder = New Pkcs7SignatureBuilder(s_cert) With {
.Format = Pkcs7SignatureBuilder.SignatureFormat.ETSI_CAdES_detached
}
}
'' Sign and save the PDF to a file:
doc.Sign(sp, "B-B.pdf")
End Using
End Sub
'' Signs a PDF with a PAdES B-T Level signature:
Sub Do_B_T(ByVal fn As String)
Using fs As FileStream = File.OpenRead(fn)
Dim doc = New GcPdfDocument()
doc.Load(fs)
Dim signField = doc.AcroForm.Fields.FirstOrDefault(Function(f_) TypeOf f_ Is SignatureField)
If signField Is Nothing Then
Throw New Exception("Could not find a signature field.")
End If
Dim sp = New SignatureProperties() With {
.SignatureField = signField,
.SignatureBuilder = New Pkcs7SignatureBuilder(s_cert) With {
.Format = Pkcs7SignatureBuilder.SignatureFormat.ETSI_CAdES_detached
},
.TimeStamp = New TimeStamp("http://ts.ssl.com")
}
'' Sign and save the PDF to a file:
doc.Sign(sp, "B-T.pdf")
End Using
End Sub
'' Adds LTV information to a B-T level signature (e.g. as created by the Do_B_T method above),
'' which makes the signature compliant with PAdES B-LT:
Sub Do_B_LT(ByVal fn As String)
Using fs As FileStream = File.OpenRead(fn)
Dim doc = New GcPdfDocument()
doc.Load(fs)
Dim signField = doc.AcroForm.Fields.FirstOrDefault(Function(f_) TypeOf f_ Is SignatureField)
If signField Is Nothing Then
Throw New Exception("Could not find a signature field.")
End If
'' Get the signature and add verification information for it:
Dim sig = DirectCast(signField.Value, Signature)
Dim vp = New DocumentSecurityStore.VerificationParams()
vp.Certificates = New X509Certificate2() {s_caCertRoot}
If Not doc.SecurityStore.AddVerification(sig, vp) Then
Throw New Exception($"Could not add verification for {sig.Name}.")
End If
'' Save the PDF to a file using incremental update so that the signature remains valid:
doc.Save("B-LT.pdf", SaveMode.IncrementalUpdate)
End Using
End Sub
'' Adds time stamp to a signed PDF (e.g. as created by the Do_B_LT method above),
'' which makes the document compliant with B-LTA level:
Sub Do_B_LTA(ByVal fn As String)
Using fs As FileStream = File.OpenRead(fn)
Dim doc = New GcPdfDocument()
doc.Load(fs)
Dim ts = New TimeStampProperties() With {
.TimeStamp = New TimeStamp("http://ts.ssl.com")
}
'' Save the PDF to a file adding a time stamp to it:
doc.TimeStamp(ts, "B-LTA.pdf")
End Using
End Sub
'' Adds verification information for a PDF time-stamp (e.g. as created by the Do_B_LTA method above)
'' which makes the signature LTV enabled:
Sub Do_B_LTA_LTV(ByVal fn As String)
Using fs As FileStream = File.OpenRead(fn)
Dim doc = New GcPdfDocument()
doc.Load(fs)
Dim signField = doc.AcroForm.Fields.FirstOrDefault(Function(f_) TypeOf f_ Is SignatureField)
If signField Is Nothing Then
Throw New Exception("Could not find a signature field.")
End If
'' Get the signature and add verification information for it:
Dim sig = DirectCast(signField.Value, Signature)
If Not doc.SecurityStore.AddVerification(sig) Then
Throw New Exception($"Could not add verification for {sig.Name}.")
End If
'' Save the PDF to a file using incremental update so that the signature remains valid:
doc.Save("B-LTA_LTV.pdf", SaveMode.IncrementalUpdate)
End Using
End Sub
Public Shared Function GetSampleParamsList() As List(Of String())
'' Strings are name, description, info, rest are arbitrary strings:
Return New List(Of String())() From {
New String() {"@b-sign/PAdES B-B Level", "How to sign a PDF complying with PAdES B-B level", "",
"PAdES-B-B.pdf"},
New String() {"@b-sign/PAdES B-T Level", "How to sign a PDF complying with PAdES B-T level", "",
"PAdES-B-T.pdf"},
New String() {"@b-sign/PAdES B-LT Level", "How to add LTV information to a signature", "",
"PAdES-B-LT.pdf"},
New String() {"@b-sign/PAdES B-LTA Level", "How to time stamp a signed PDF", "",
"PAdES-B-LTA.pdf"},
New String() {"@b-sign/LTV Enabled Signature", "How to make a signature LTV enabled", "",
"PAdES-B-LTA-LTV.pdf"}
}
End Function
End Class