
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Drawing.Text
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports System.Security.Cryptography
Imports System.Security.Cryptography.X509Certificates
Imports System.Text
Imports System.Text.RegularExpressions
Imports Org.BouncyCastle.Crypto.Agreement
Imports Org.BouncyCastle.Pkcs
Imports TSpdf
Imports TSpdf.Bouncycastle.Cert
Imports TSpdf.Bouncycastle.Crypto
Imports TSpdf.Commons.Bouncycastle.Cert
Imports TSpdf.Commons.Bouncycastle.Crypto
Imports TSpdf.Forms
Imports TSpdf.Forms.Fields
Imports TSpdf.IO.Font
Imports TSpdf.IO.Font.Constants
Imports TSpdf.Kernel.Font
Imports TSpdf.Kernel.Geom
Imports TSpdf.Kernel.Pdf
Imports TSpdf.Kernel.Pdf.Canvas
Imports TSpdf.Kernel.Pdf.Colorspace.PdfDeviceCs
Imports TSpdf.Kernel.Utils
Imports TSpdf.Layout
Imports TSpdf.Layout.Element
Imports TSpdf.Layout.Properties
Imports TSpdf.Layout.Renderer
Imports TSpdf.Pdfa
Imports TSpdf.Signatures
Imports TSpdf.Signatures.PdfSigner
Imports tsPDFUtilsCore
Imports Rectangle = System.Drawing.Rectangle

Public Class Firmas


    Public Shared Sub AddTimeStamp(ByVal inputPdf As String, ByVal outputPdf As String)
        Dim reader As New PdfReader(inputPdf)
        Dim writer As New PdfWriter(outputPdf)

        Dim signer As New PdfSigner(reader, writer, New StampingProperties())

        ' Configura el cliente TSA
        Dim tsaUrl As String = "http://timestamp.digicert.com" ' Puedes usar otra TSA pública o privada
        Dim tsaClient As New TSAClientBouncyCastle(tsaUrl, Nothing, Nothing, 4096, "SHA-256")

        ' Crear una firma externa basada solo en la marca de tiempo
        Dim external As IExternalSignatureContainer = New ExternalTimestampContainer(tsaClient)

        ' Aplicar la marca de tiempo
        signer.SignExternalContainer(external, 8192)
    End Sub

    Public Shared Function ObtieneFirmantesPDFFirmado(FicheroPdf As String, SoloCertId As Boolean) As List(Of String)
        Try
            Dim pdfReader As New PdfReader(FicheroPdf)
            Dim pdfDoc As New PdfDocument(pdfReader)
            Dim su As New SignatureUtil(pdfDoc)
            Dim firmantes As New List(Of String)
            For Each n In su.GetSignatureNames
                Dim sd = su.ReadSignatureData(n)
                If sd.VerifySignatureIntegrityAndAuthenticity Then
                    Dim cert = sd.GetSigningCertificate
                    Dim b = cert.GetEncoded
                    Dim scertid = SHA1(b)
                    If SoloCertId Then
                        firmantes.Add(scertid)
                    Else
                        Dim sTitulo As String = ""
                        Dim sNombreCompleto As String = ""
                        Dim sNumeroColegiado As String = ""
                        Dim sDI As String = ""
                        Try
                            sTitulo = UtilsCert.ObtenerValorAtributoDN(b, "2.5.4.3")
                            DescomponerCNsuscriptor(sTitulo, sNombreCompleto, sDI, sNumeroColegiado)
                        Catch
                            Try
                            Catch
                                sNombreCompleto = UtilsCert.ObtenerValorAtributoDN(b, "2.5.4.4") & ", " & UtilsCert.ObtenerValorAtributoDN(b, "2.5.4.42")
                                sDI = UtilsCert.ObtenerValorAtributoDN(b, "2.5.4.5")
                                If sDI.StartsWith("IDCES-") Then sDI = sDI.Split("-")(1)
                            End Try
                        End Try
                        firmantes.Add(scertid & "|" & sNombreCompleto & " (" & sDI & ")")
                    End If
                End If
            Next
            Return firmantes
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Shared Function DescomponerCNsuscriptor(ByVal CNsuscriptor As String, ByRef Optional nombre As String = Nothing, ByRef Optional docIdentidad As String = Nothing, ByRef Optional numPersonal As String = Nothing) As Boolean
        nombre = CNsuscriptor
        docIdentidad = Nothing
        numPersonal = Nothing

        If CNsuscriptor = "" Then
            Return False
        End If

        Dim text As String = Nothing
        Dim text2 As String = Nothing
        Dim array As String() = Regex.Split(CNsuscriptor, " DI=")

        If array.Length > 2 Then
            Return False
        End If

        Dim text3 As String

        If array.Length = 2 Then
            text3 = array(0)
            array = Regex.Split(array(1), " N=")

            If array.Length > 2 Then
                Return False
            End If

            text = array(0)

            If array.Length = 2 Then
                text2 = array(1)
            End If
        Else
            array = Regex.Split(CNsuscriptor, " N=")

            If array.Length > 2 Then
                Return False
            End If

            text3 = array(0)

            If array.Length = 2 Then
                text2 = array(1)
            End If
        End If

        If text3 = "" OrElse text3.Trim = "" OrElse text3.IndexOf("=") >= 0 Then
            Return False
        End If

        If text IsNot Nothing AndAlso text.Trim() = "" OrElse text.IndexOf("=") >= 0 Then
            Return False
        End If

        If text2 IsNot Nothing AndAlso (text2.Trim() = "" OrElse text2.IndexOf("=") >= 0) Then
            Return False
        End If

        nombre = text3
        docIdentidad = text
        numPersonal = text2
        Return True
    End Function
    Public Shared Function SHA1(ByVal Datos() As Byte) As String
        Dim sha1Obj As New Security.Cryptography.SHA1CryptoServiceProvider
        Dim bytesToHash() As Byte = Datos
        bytesToHash = sha1Obj.ComputeHash(bytesToHash)
        Dim strResult As String = ""
        For Each b As Byte In bytesToHash
            strResult += b.ToString("x2")
        Next
        Return strResult.ToUpper
    End Function
    'Public Shared Sub FirmaPDF(cert As X509Certificate2, ClavePDF As String, ByVal PdfOrigen As Byte(), ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, RutaTmp As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional SobreescribirCSP As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "")
    '    FirmaPDF(cert, ClavePDF, New MemoryStream(PdfOrigen), pdfDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, SobreescribirCSP, ObviarSeguridad, NombreCampoFirma)
    'End Sub


    ' CREADA POR JAVIER PACIOS LOPEZ



    Public Shared Sub FirmaPDF(ByVal bPfx As Byte(), ByVal ClavePFX As String, ByVal ClavePDF As String, ByRef PdfOrigen As Byte(), ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Dim msOrigen = New MemoryStream(PdfOrigen)
        Dim StreamPFX = New MemoryStream(bPfx)
        FirmaPDF(StreamPFX, ClavePFX, ClavePDF, msOrigen, pdfDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, ConvertirPDFA, PDFAObligatorio)
    End Sub

    Public Shared Sub FirmaPDF(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByRef PdfOrigen As Byte(), ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Dim msOrigen = New MemoryStream(PdfOrigen)

        FirmaPDF(StreamPFX, ClavePFX, ClavePDF, msOrigen, pdfDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, ConvertirPDFA, PDFAObligatorio)
    End Sub

    Public Shared Sub FirmaPDF(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As String, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Dim msOrigen = New MemoryStream(System.IO.File.ReadAllBytes(PdfOrigen))
        FirmaPDF(StreamPFX, ClavePFX, ClavePDF, msOrigen, pdfDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, ConvertirPDFA, PDFAObligatorio)
    End Sub

    Public Shared Sub FirmaPDF(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As String, ByVal pdfDestino As String, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Dim msOrigen = New MemoryStream(System.IO.File.ReadAllBytes(PdfOrigen))
        Dim msDestino As New MemoryStream
        FirmaPDF(StreamPFX, ClavePFX, ClavePDF, msOrigen, msDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, ConvertirPDFA, PDFAObligatorio)
        System.IO.File.WriteAllBytes(pdfDestino, msDestino.ToArray)
    End Sub
    Public Shared Sub FirmaPDF(ByVal bPfx As Byte(), ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Stream, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Dim mscert As New MemoryStream(bPfx)
        FirmaPDF(mscert, ClavePFX, ClavePDF, PdfOrigen, pdfDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, ConvertirPDFA, PDFAObligatorio)
    End Sub
    Public Shared Sub FirmaPDF(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Stream, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Try
            Dim ms As New MemoryStream

            Dim pdfLectura As Stream
            If ConvertirPDFA Then

                Try
                    pdfLectura = Utilidades.crearPDFA(PdfOrigen)
                Catch ex As Exception
                    If PDFAObligatorio Then
                        Throw New Exception(ex.Message, ex)
                    Else
                        PdfOrigen.Position = 0
                        pdfLectura = PdfOrigen
                    End If
                End Try
            Else
                pdfLectura = PdfOrigen
            End If

            Dim reader As New PdfReader(pdfLectura)
            reader.SetUnethicalReading(ObviarSeguridad)



            Dim sp As New StampingProperties()

            If EliminarFirmasAnteriores = False Then
                sp.UseAppendMode()
            End If






            If EliminarFirmasAnteriores = False Then
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    Dim writer As PdfWriter = New PdfWriter(ms, props)
                    Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                    pdfDoc.Close()
                    Dim rp As New ReaderProperties()
                    rp.SetPassword(bc)
                    reader = New PdfReader(New MemoryStream(ms.ToArray), rp)
                    reader.SetUnethicalReading(ObviarSeguridad)
                End If
            Else
                Dim writer As PdfWriter
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    writer = New PdfWriter(ms, props)
                Else
                    writer = New PdfWriter(ms)
                End If


                Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                Dim form = PdfAcroForm.GetAcroForm(pdfDoc, True)
                form.FlattenFields()
                pdfDoc.Close()
                If ClavePDF = "" Then
                    reader = New PdfReader(New MemoryStream(ms.ToArray))
                Else
                    Dim pr As New ReaderProperties()
                    pr.SetPassword(Encoding.ASCII.GetBytes(ClavePDF))
                    reader = New PdfReader(New MemoryStream(ms.ToArray), pr)
                End If
                reader.SetUnethicalReading(ObviarSeguridad)
            End If

            Dim pdfSign As PdfSigner = Nothing


            ' EN CASO DE QUE SEA PDFA COMPRUEBA QUE TENGA LA ANOTACIÓN F

            If PDFAObligatorio AndAlso ConvertirPDFA Then
                If Utilidades.TieneMarcaPdfA(pdfLectura) Then
                    Dim pdfDoc1 As PdfDocument = pdfSign.GetDocument()
                    Utilidades.RepararAnotacionesSinF(pdfDoc1)
                End If
                pdfSign = New PdfSigner(reader, pdfDestino, sp)

            Else
                pdfSign = New PdfSigner(reader, pdfDestino, sp, ConvertirPDFA:=False)
            End If


                If NombreCampoFirma <> "" Then
                pdfSign.SetFieldName(NombreCampoFirma)
            Else
                pdfSign.SetFieldName(pdfSign.GetNewSigFieldName())
            End If
            pdfSign.GetSignatureAppearance().SetReason(Razon).SetLocation(Localizacion).SetContact(Contacto)

            Dim cpassword = ClavePFX.ToCharArray




            Dim [alias] As String = Nothing
            Dim pk12 As Pkcs12Store = New Pkcs12Store(StreamPFX, cpassword)

            For Each a In pk12.Aliases
                [alias] = (CType(a, String))

                If pk12.IsKeyEntry([alias]) Then
                    Exit For
                End If
            Next

            Dim pk As IPrivateKey = New PrivateKeyBC(pk12.GetKey([alias]).Key)
            Dim pks = New PrivateKeySignature(pk, DigestAlgorithms.SHA256)


            Dim ce As X509CertificateEntry() = pk12.GetCertificateChain([alias])
            Dim chain = New IX509Certificate(ce.Length - 1) {}

            For k As Integer = 0 To ce.Length - 1
                chain(k) = New X509CertificateBC(ce(k).Certificate)
            Next

            ' Dim pks = GetPrivateKeySignature(StreamPFX, cpassword)
            '  Dim chain As IX509Certificate() = GetCertificateChain(StreamPFX, cpassword)


            Dim OCSPVerifier = New OCSPVerifier(Nothing, Nothing)
            Dim ocspClient = New OcspClientBouncyCastle(OCSPVerifier)
            Dim crlClients = New List(Of ICrlClient)

            pdfSign.SignDetached(pks, chain, crlClients, ocspClient, Nothing, 0, PdfSigner.CryptoStandard.CMS)
            reader.Close()

        Catch ex As Exception
            Throw New Exception("Error en FirmaPDF ConvertirPDFA= " & ConvertirPDFA.ToString & " PDFAObligatorio=" & PDFAObligatorio.ToString & " " & ex.Message, ex)
        End Try
    End Sub




    Public Shared Sub FirmaPDF(cert As X509Certificate2, ClavePDF As String, ByVal PdfOrigen As String, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional SobreescribirCSP As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Dim fs As New FileStream(PdfOrigen, FileMode.Open)
        FirmaPDF(cert, ClavePDF, fs, pdfDestino, Razon, Contacto, Localizacion, EliminarFirmasAnteriores, SobreescribirCSP, ObviarSeguridad, NombreCampoFirma, ConvertirPDFA, PDFAObligatorio)
        fs.Close()
    End Sub
    ' COMPROBADA
    Public Shared Sub FirmaPDF(cert As X509Certificate2, ClavePDF As String, ByVal PdfOrigen As Stream, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Optional EliminarFirmasAnteriores As Boolean = True, Optional SobreescribirCSP As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional ConvertirPDFA As Boolean = False, Optional PDFAObligatorio As Boolean = False)
        Try
            If SobreescribirCSP Then
                Dim rsa As RSACryptoServiceProvider = CType(cert.PrivateKey, RSACryptoServiceProvider)
                Dim csparams As New CspParameters
                csparams.KeyContainerName = "TECNOSIS-" & Guid.NewGuid.ToString
                Dim rsa2 As New RSACryptoServiceProvider(csparams)
                rsa2.ImportParameters(rsa.ExportParameters(True))
                cert.PrivateKey = rsa2
            End If

            Dim pdfLectura As Stream

            If ConvertirPDFA Then

                Try
                    pdfLectura = Utilidades.crearPDFA(PdfOrigen)
                Catch ex As Exception
                    If PDFAObligatorio Then
                        Throw New Exception(ex.Message, ex)
                    Else
                        PdfOrigen.Position = 0
                        pdfLectura = PdfOrigen
                    End If
                End Try
            Else
                pdfLectura = PdfOrigen
            End If

            Dim reader As New PdfReader(pdfLectura)
            reader.SetUnethicalReading(ObviarSeguridad)

            Dim sp As New StampingProperties()
            If EliminarFirmasAnteriores = False Then
                sp.UseAppendMode()
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    Using ms = New MemoryStream()
                        Dim writer As PdfWriter = New PdfWriter(ms, props)
                        Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                        pdfDoc.Close()
                        reader.Close()
                        writer.Close()
                        Dim rp As New ReaderProperties()
                        rp.SetPassword(bc)
                        reader = New PdfReader(New MemoryStream(ms.ToArray), rp)
                        reader.SetUnethicalReading(ObviarSeguridad)
                    End Using
                End If
            Else
                Using ms = New MemoryStream()
                    Dim writer As PdfWriter = New PdfWriter(ms)
                    Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                    Dim form = PdfAcroForm.GetAcroForm(pdfDoc, True)
                    form.FlattenFields()
                    pdfDoc.Close()
                    reader.Close()
                    writer.Close()
                    If ClavePDF = "" Then
                        reader = New PdfReader(New MemoryStream(ms.ToArray))
                    Else
                        Dim pr As New ReaderProperties()
                        pr.SetPassword(Encoding.ASCII.GetBytes(ClavePDF))
                        reader = New PdfReader(New MemoryStream(ms.ToArray), pr)
                    End If
                    reader.SetUnethicalReading(ObviarSeguridad)
                End Using
            End If



            Dim bccert As Org.BouncyCastle.X509.X509Certificate = New Org.BouncyCastle.X509.X509Certificate(Org.BouncyCastle.Asn1.X509.X509CertificateStructure.GetInstance(cert.RawData))
            Dim chain As IX509Certificate() = {New TSpdf.Bouncycastle.Cert.X509CertificateBC(bccert)}
            Dim signature As X509Certificate2Signature = New X509Certificate2Signature(cert, "SHA256")
            Dim pdfSign As New PdfSigner(reader, pdfDestino, sp)
            If NombreCampoFirma <> "" Then
                pdfSign.SetFieldName(NombreCampoFirma)
            Else
                pdfSign.SetFieldName(pdfSign.GetNewSigFieldName())
            End If
            pdfSign.GetSignatureAppearance().SetReason(Razon).SetLocation(Localizacion).SetContact(Contacto)
            pdfSign.SignDetached(signature, chain, Nothing, Nothing, Nothing, 0, PdfSigner.CryptoStandard.CMS)
            reader.Close()
        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        End Try
    End Sub





    Public Shared Sub FirmaPDFVisible(bPfx As Byte(), ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Byte(), ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, ByVal listadoTextos As List(Of DatosTextos), ByVal listadoImagenes As List(Of DatosImagenFirma), Optional listadoFuentes As List(Of DatosFuente) = Nothing, Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional DatosCampoFirma As DatosNuevoCampoFirma = Nothing, Optional BloquearDocumento As Boolean = False)
        Dim StreamPfx As New MemoryStream(bPfx)
        Dim ms As New MemoryStream
        Dim fso = New MemoryStream(PdfOrigen)
        FirmaPDFVisible(StreamPfx, ClavePFX, ClavePDF, fso, ms, Razon, Contacto, Localizacion, listadoTextos, listadoImagenes, listadoFuentes, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, DatosCampoFirma, BloquearDocumento)
    End Sub



    Public Shared Sub FirmaPDFVisible(bPfx As Byte(), ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As String, ByVal pdfDestino As String, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, ByVal listadoTextos As List(Of DatosTextos), ByVal listadoImagenes As List(Of DatosImagenFirma), Optional listadoFuentes As List(Of DatosFuente) = Nothing, Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional DatosCampoFirma As DatosNuevoCampoFirma = Nothing, Optional BloquearDocumento As Boolean = False)
        Dim StreamPfx As New MemoryStream(bPfx)
        Dim fso = New MemoryStream(System.IO.File.ReadAllBytes(PdfOrigen))
        Dim fs As New FileStream(pdfDestino, FileMode.Create)
        FirmaPDFVisible(StreamPfx, ClavePFX, ClavePDF, fso, fs, Razon, Contacto, Localizacion, listadoTextos, listadoImagenes, listadoFuentes, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, DatosCampoFirma, BloquearDocumento)
        fs.Close()
    End Sub

    Public Shared Sub FirmaPDFVisible(bPfx As Byte(), ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As String, ByVal pdfDestino As String, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Imagen As Byte(), Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional DatosCampoFirma As DatosNuevoCampoFirma = Nothing, Optional BloquearDocumento As Boolean = False)
        Dim StreamPfx As New MemoryStream(bPfx)
        Dim fso = New MemoryStream(System.IO.File.ReadAllBytes(PdfOrigen))
        Dim fs As New FileStream(pdfDestino, FileMode.Create)
        FirmaPDFVisible(StreamPfx, ClavePFX, ClavePDF, fso, fs, Razon, Contacto, Localizacion, Imagen, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, DatosCampoFirma, BloquearDocumento)
        fs.Close()
    End Sub


    Public Shared Sub FirmaPDFVisible(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Stream, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, Imagen As Byte(), Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional DatosCampoFirma As DatosNuevoCampoFirma = Nothing, Optional BloquearDocumento As Boolean = False)
        Try
            Dim ms As New MemoryStream
            Dim reader As New PdfReader(PdfOrigen)
            reader.SetUnethicalReading(ObviarSeguridad)
            Dim sp As New StampingProperties()
            'Dim ListaCampos() As String
            'If NombreCampoFirma = "" Then
            '    If BloquearDocumento Then
            '        Try
            '            Dim pdfDoc As PdfDocument = New PdfDocument(reader)
            '            Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
            '            ListaCampos = pdfAcrof.GetAllFormFields.Select(Function(x) x.Key).ToArray
            '            pdfDoc.Close()
            '        Catch
            '        End Try
            '        PdfOrigen.Seek(0, 0)
            '        reader = New PdfReader(PdfOrigen)
            '    End If
            'Else
            '    Dim pdfDoc As PdfDocument = New PdfDocument(reader)
            '    Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
            '    If BloquearDocumento Then
            '        ListaCampos = pdfAcrof.GetAllFormFields.Select(Function(x) x.Key).ToArray
            '    End If
            '    'medidas = pdfAcrof.GetField(NombreCampoFirma).GetWidgets(0).GetRectangle.ToRectangle
            '    pdfDoc.Close()
            '    PdfOrigen.Seek(0, 0)
            '    reader = New PdfReader(PdfOrigen)
            'End If
            If EliminarFirmasAnteriores = False Then
                sp.UseAppendMode()
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    Dim writer As PdfWriter = New PdfWriter(ms, props)
                    Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)

                    Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                    '      If NombreCampoFirma <> "" Then medidas = pdfAcrof.GetField(NombreCampoFirma).GetWidgets(0).GetRectangle.ToRectangle
                    pdfDoc.Close()
                    Dim rp As New ReaderProperties()
                    rp.SetPassword(bc)
                    reader = New PdfReader(New MemoryStream(ms.ToArray), rp)

                End If
                reader.SetUnethicalReading(ObviarSeguridad)

            Else
                Dim writer As PdfWriter
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    writer = New PdfWriter(ms, props)
                Else
                    writer = New PdfWriter(ms)
                End If
                Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                pdfAcrof.FlattenFields()
                pdfDoc.Close()
                If ClavePDF = "" Then
                    reader = New PdfReader(New MemoryStream(ms.ToArray))
                Else
                    Dim pr As New ReaderProperties()
                    pr.SetPassword(Encoding.ASCII.GetBytes(ClavePDF))
                    reader = New PdfReader(New MemoryStream(ms.ToArray), pr)
                End If
                reader.SetUnethicalReading(ObviarSeguridad)
            End If





            Dim cpassword = ClavePFX.ToCharArray
            Dim [alias] As String = Nothing
            Dim pk12 As Pkcs12Store = New Pkcs12Store(StreamPFX, cpassword)

            For Each a In pk12.Aliases
                [alias] = (CType(a, String))

                If pk12.IsKeyEntry([alias]) Then
                    Exit For
                End If
            Next

            Dim pk As IPrivateKey = New PrivateKeyBC(pk12.GetKey([alias]).Key)
            Dim pks = New PrivateKeySignature(pk, DigestAlgorithms.SHA256)

            Dim ce As X509CertificateEntry() = pk12.GetCertificateChain([alias])
            Dim chain = New IX509Certificate(ce.Length - 1) {}

            For k As Integer = 0 To ce.Length - 1
                chain(k) = New X509CertificateBC(ce(k).Certificate)
            Next



            Dim OCSPVerifier = New OCSPVerifier(Nothing, Nothing)
            Dim ocspClient = New OcspClientBouncyCastle(OCSPVerifier)
            Dim crlClients = New List(Of ICrlClient)
            Dim listadoDatosCertificado = ce(0).Certificate.SubjectDN.GetValueList
            Dim nombre = listadoDatosCertificado(4).ToString


            Dim pdfSign As New PdfSigner(reader, pdfDestino, sp)
            If NombreCampoFirma = "" Then
                pdfSign.SetFieldName(DatosCampoFirma.NombreCampo)
            Else
                pdfSign.SetFieldName(NombreCampoFirma)
            End If
            Dim idata As IO.Image.ImageData = IO.Image.ImageDataFactory.Create(Imagen)
            If NombreCampoFirma = "" Then
                Dim medidas = New Kernel.Geom.Rectangle(DatosCampoFirma.CoordenadaX, DatosCampoFirma.CoordenadaY, DatosCampoFirma.Ancho, DatosCampoFirma.Alto)
                Dim canvas2 As New PdfCanvas(pdfSign.GetDocument.GetFirstPage.NewContentStreamBefore(), pdfSign.GetDocument.GetFirstPage().GetResources(), pdfSign.GetDocument)
                Dim signLayoutCanvas = New Canvas(canvas2, medidas)
                pdfSign.GetSignatureAppearance().SetReason(Razon).SetLocation(Localizacion).SetContact(Contacto).SetPageRect(medidas).SetImage(idata).SetLayer2Text("")
            Else
                pdfSign.GetSignatureAppearance().SetReason(Razon).SetLocation(Localizacion).SetContact(Contacto).SetImage(idata).SetLayer2Text("")
            End If

            If BloquearDocumento Then

                pdfSign.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED)

            End If
            pdfSign.SignDetached(pks, chain, crlClients, ocspClient, Nothing, 0, PdfSigner.CryptoStandard.CADES)


            reader.Close()

        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        End Try
    End Sub


    Public Shared Sub FirmaPDFVisible(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Stream, ByVal pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, ByVal listadoTextos As List(Of DatosTextos), ByVal listadoImagenes As List(Of DatosImagenFirma), Optional listadoFuentes As List(Of DatosFuente) = Nothing, Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional DatosCampoFirma As DatosNuevoCampoFirma = Nothing, Optional BloquearDocumento As Boolean = False)
        Try
            Dim ms As New MemoryStream
            Dim reader As New PdfReader(PdfOrigen)
            reader.SetUnethicalReading(ObviarSeguridad)
            Dim sp As New StampingProperties()
            '  Dim ListaCampos() As String
            Dim medidas As Kernel.Geom.Rectangle
            If NombreCampoFirma = "" Then
                medidas = New Kernel.Geom.Rectangle(DatosCampoFirma.CoordenadaX, DatosCampoFirma.CoordenadaY, DatosCampoFirma.Ancho, DatosCampoFirma.Alto)
                'If BloquearDocumento Then
                '    Try
                '        Dim pdfDoc As PdfDocument = New PdfDocument(reader)
                '        Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                '        ListaCampos = pdfAcrof.GetAllFormFields.Select(Function(x) x.Key).ToArray
                '        pdfDoc.Close()
                '    Catch
                '    End Try
                '    PdfOrigen.Seek(0, 0)
                '    reader = New PdfReader(PdfOrigen)
                'End If
            Else
                Dim pdfDoc As PdfDocument = New PdfDocument(reader)
                Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                Dim cf = pdfAcrof.GetField(NombreCampoFirma)
                If cf Is Nothing Then
                    medidas = New Kernel.Geom.Rectangle(DatosCampoFirma.CoordenadaX, DatosCampoFirma.CoordenadaY, DatosCampoFirma.Ancho, DatosCampoFirma.Alto)
                Else
                    medidas = cf.GetWidgets(0).GetRectangle.ToRectangle
                End If
                pdfDoc.Close()
                PdfOrigen.Seek(0, 0)
                reader = New PdfReader(PdfOrigen)
            End If
            If EliminarFirmasAnteriores = False Then
                sp.UseAppendMode()
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    Dim writer As PdfWriter = New PdfWriter(ms, props)
                    Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)

                    Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                    '      If NombreCampoFirma <> "" Then medidas = pdfAcrof.GetField(NombreCampoFirma).GetWidgets(0).GetRectangle.ToRectangle
                    pdfDoc.Close()
                    Dim rp As New ReaderProperties()
                    rp.SetPassword(bc)
                    reader = New PdfReader(New MemoryStream(ms.ToArray), rp)

                End If
                reader.SetUnethicalReading(ObviarSeguridad)

            Else
                Dim writer As PdfWriter
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    writer = New PdfWriter(ms, props)
                Else
                    writer = New PdfWriter(ms)
                End If
                Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                pdfAcrof.FlattenFields()
                pdfDoc.Close()
                If ClavePDF = "" Then
                    reader = New PdfReader(New MemoryStream(ms.ToArray))
                Else
                    Dim pr As New ReaderProperties()
                    pr.SetPassword(Encoding.ASCII.GetBytes(ClavePDF))
                    reader = New PdfReader(New MemoryStream(ms.ToArray), pr)
                End If
                reader.SetUnethicalReading(ObviarSeguridad)
            End If

            Dim cpassword = ClavePFX.ToCharArray
            Dim [alias] As String = Nothing
            Dim pk12 As Pkcs12Store = New Pkcs12Store(StreamPFX, cpassword)

            For Each a In pk12.Aliases
                [alias] = (CType(a, String))

                If pk12.IsKeyEntry([alias]) Then
                    Exit For
                End If
            Next

            Dim pk As IPrivateKey = New PrivateKeyBC(pk12.GetKey([alias]).Key)
            Dim pks = New PrivateKeySignature(pk, DigestAlgorithms.SHA256)

            Dim ce As X509CertificateEntry() = pk12.GetCertificateChain([alias])
            Dim chain = New IX509Certificate(ce.Length - 1) {}

            For k As Integer = 0 To ce.Length - 1
                chain(k) = New X509CertificateBC(ce(k).Certificate)
            Next

            ' Dim pks = GetPrivateKeySignature(StreamPFX, cpassword)
            '  Dim chain As IX509Certificate() = GetCertificateChain(StreamPFX, cpassword)

            Dim OCSPVerifier = New OCSPVerifier(Nothing, Nothing)
            Dim ocspClient = New OcspClientBouncyCastle(OCSPVerifier)
            Dim crlClients = New List(Of ICrlClient)
            Dim listadoDatosCertificado = ce(0).Certificate.SubjectDN.GetValueList
            Dim nombre = listadoDatosCertificado(4).ToString

            Dim pdfSign As New PdfSigner(reader, pdfDestino, sp)
            If NombreCampoFirma = "" Then
                pdfSign.SetFieldName(DatosCampoFirma.NombreCampo)
            Else
                pdfSign.SetFieldName(NombreCampoFirma)
            End If
            'Dim canvas2 As New PdfCanvas(pdfSign.GetDocument.GetFirstPage.NewContentStreamBefore(), pdfSign.GetDocument.GetFirstPage().GetResources(), pdfSign.GetDocument)

            'Dim signLayoutCanvas = New Canvas(canvas2, medidas)
            '  medidas.DecreaseHeight(30)
            Dim bmp = Imagenes.crearBitMapFirmas(listadoTextos, listadoImagenes, listadoFuentes, medidas)
            '   File.WriteAllBytes("c:\tmp\1.bmp", Imagenes.BitMapAByteArray(bmp))

            '     bmp = New Bitmap(bmp, bmp.Width, bmp.Height - 640)

            Dim imagenUrl = Imagenes.BitMapAByteArray(bmp)
            '     File.WriteAllBytes("c:\tmp\2.bmp", Imagenes.BitMapAByteArray(bmp))


            Dim imagen As IO.Image.ImageData = IO.Image.ImageDataFactory.Create(imagenUrl)
            pdfSign.GetSignatureAppearance().SetReason(Razon).SetLocation(Localizacion).SetContact(Contacto).SetPageRect(medidas).SetImage(imagen).SetLayer2Text("")
            If BloquearDocumento Then
                'Dim sfl = New PdfSigFieldLock
                'sfl.SetDocumentPermissions(PdfSigFieldLock.LockPermissions.NO_CHANGES_ALLOWED)
                'If ListaCampos IsNot Nothing AndAlso ListaCampos.Length > 0 Then
                '    sfl.SetFieldLock(PdfSigFieldLock.LockAction.INCLUDE, ListaCampos)
                '    sfl.GetPdfObject.Remove(PdfName.Fields)
                'End If
                'pdfSign.SetFieldLockDict(sfl)
                pdfSign.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED)
            End If
            pdfSign.SignDetached(pks, chain, crlClients, ocspClient, Nothing, 0, PdfSigner.CryptoStandard.CADES)

            reader.Close()

        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        End Try
    End Sub


    Public Shared Sub FirmaPDFVisibleSimple(bPfx As Byte(), ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Byte(), ByRef pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, TituloFirmante As String, DatosCampoFirma As DatosNuevoCampoFirma, Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional BloquearDocumento As Boolean = False)
        Dim StreamPfx As New MemoryStream(bPfx)
        Dim fso = New MemoryStream(PdfOrigen)
        FirmaPDFVisibleSimple(StreamPfx, ClavePFX, ClavePDF, fso, pdfDestino, Razon, Contacto, Localizacion, TituloFirmante, DatosCampoFirma, EliminarFirmasAnteriores, ObviarSeguridad, NombreCampoFirma, BloquearDocumento)
    End Sub


    Public Shared Sub FirmaPDFVisibleSimple(ByVal StreamPFX As Stream, ByVal ClavePFX As String, ByVal ClavePDF As String, ByVal PdfOrigen As Stream, ByRef pdfDestino As Stream, ByVal Razon As String, ByVal Contacto As String, ByVal Localizacion As String, TituloFirmante As String, DatosCampoFirma As DatosNuevoCampoFirma, Optional EliminarFirmasAnteriores As Boolean = False, Optional ObviarSeguridad As Boolean = True, Optional NombreCampoFirma As String = "", Optional BloquearDocumento As Boolean = False)
        Try
            Dim ms As New MemoryStream
            Dim reader As New PdfReader(PdfOrigen)
            reader.SetUnethicalReading(ObviarSeguridad)
            Dim sp As New StampingProperties()
            '  Dim ListaCampos() As String
            Dim medidas As Kernel.Geom.Rectangle
            If NombreCampoFirma = "" Then
                medidas = New Kernel.Geom.Rectangle(DatosCampoFirma.CoordenadaX, DatosCampoFirma.CoordenadaY, DatosCampoFirma.Ancho, DatosCampoFirma.Alto)
            Else
                Dim pdfDoc As PdfDocument = New PdfDocument(reader)
                Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                Dim cf = pdfAcrof.GetField(NombreCampoFirma)
                If cf Is Nothing Then
                    medidas = New Kernel.Geom.Rectangle(DatosCampoFirma.CoordenadaX, DatosCampoFirma.CoordenadaY, DatosCampoFirma.Ancho, DatosCampoFirma.Alto)
                Else
                    medidas = cf.GetWidgets(0).GetRectangle.ToRectangle
                End If
                pdfDoc.Close()
                PdfOrigen.Seek(0, 0)
                reader = New PdfReader(PdfOrigen)
            End If
            If EliminarFirmasAnteriores = False Then
                sp.UseAppendMode()
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    Dim writer As PdfWriter = New PdfWriter(ms, props)
                    Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)

                    Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                    pdfDoc.Close()
                    Dim rp As New ReaderProperties()
                    rp.SetPassword(bc)
                    reader = New PdfReader(New MemoryStream(ms.ToArray), rp)

                End If
                reader.SetUnethicalReading(ObviarSeguridad)

            Else
                Dim writer As PdfWriter
                If ClavePDF <> "" Then
                    Dim bc = Encoding.ASCII.GetBytes(ClavePDF)
                    Dim props = New WriterProperties().SetStandardEncryption(Nothing, bc, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)
                    writer = New PdfWriter(ms, props)
                Else
                    writer = New PdfWriter(ms)
                End If
                Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
                Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
                pdfAcrof.FlattenFields()
                pdfDoc.Close()
                If ClavePDF = "" Then
                    reader = New PdfReader(New MemoryStream(ms.ToArray))
                Else
                    Dim pr As New ReaderProperties()
                    pr.SetPassword(Encoding.ASCII.GetBytes(ClavePDF))
                    reader = New PdfReader(New MemoryStream(ms.ToArray), pr)
                End If
                reader.SetUnethicalReading(ObviarSeguridad)
            End If

            Dim cpassword = ClavePFX.ToCharArray
            Dim [alias] As String = Nothing
            Dim pk12 As Pkcs12Store = New Pkcs12Store(StreamPFX, cpassword)

            For Each a In pk12.Aliases
                [alias] = (CType(a, String))

                If pk12.IsKeyEntry([alias]) Then
                    Exit For
                End If
            Next

            Dim pk As IPrivateKey = New PrivateKeyBC(pk12.GetKey([alias]).Key)
            Dim pks = New PrivateKeySignature(pk, DigestAlgorithms.SHA256)

            Dim ce As X509CertificateEntry() = pk12.GetCertificateChain([alias])
            Dim chain = New IX509Certificate(ce.Length - 1) {}

            For k As Integer = 0 To ce.Length - 1
                chain(k) = New X509CertificateBC(ce(k).Certificate)
            Next


            Dim OCSPVerifier = New OCSPVerifier(Nothing, Nothing)
            Dim ocspClient = New OcspClientBouncyCastle(OCSPVerifier)
            Dim crlClients = New List(Of ICrlClient)
            Dim listadoDatosCertificado = ce(0).Certificate.SubjectDN.GetValueList
            Dim nombre = listadoDatosCertificado(4).ToString

            Dim pdfSign As New PdfSigner(reader, pdfDestino, sp)
            If NombreCampoFirma = "" Then
                pdfSign.SetFieldName(DatosCampoFirma.NombreCampo)
            Else
                pdfSign.SetFieldName(NombreCampoFirma)
            End If
            Dim pdffh As PdfFont = PdfFontFactory.CreateFont(StandardFonts.HELVETICA, PdfEncodings.UTF8)




            Dim pdfd As PdfDocument = pdfSign.GetDocument()
            Dim appearance As PdfSignatureAppearance = pdfSign.GetSignatureAppearance().SetReason(Razon).SetLocation(Localizacion).SetContact(Contacto).SetPageRect(medidas)
            appearance.SetPageNumber(1)
            appearance.SetReuseAppearance(False)

            Dim layer2 = appearance.GetLayer2()
            Dim canvas As New PdfCanvas(layer2, pdfd)
            Dim layoutCanvas As New Canvas(canvas, medidas)

            Dim font As PdfFont = PdfFontFactory.CreateFont(StandardFonts.HELVETICA)
            Dim f = DateTime.Today.ToString("dd/MM/yyyy")

            layoutCanvas.SetFont(font) _
             .SetFontSize(10) _
             .ShowTextAligned("Firmado Digitalmente Por: " & TituloFirmante, 10, medidas.GetHeight() - 20, TextAlignment.LEFT) _
             .ShowTextAligned("Fecha: " & f, 10, medidas.GetHeight() - 35, TextAlignment.LEFT) _
             .ShowTextAligned("Motivo: " & Razon, 10, medidas.GetHeight() - 50, TextAlignment.LEFT)


            If BloquearDocumento Then
                pdfSign.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED)
            End If
            pdfSign.SignDetached(pks, chain, crlClients, ocspClient, Nothing, 0, PdfSigner.CryptoStandard.CADES)

            reader.Close()

        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        End Try
    End Sub


    Public Shared Function ObtieneMedidasCampo(Fichero As String, NombreCampo As String) As Kernel.Geom.Rectangle
        Dim reader As New PdfReader(Fichero)
        Return ObtieneMedidasCampo(reader, NombreCampo)
    End Function

    Public Shared Function ObtieneMedidasCampo(reader As PdfReader, NombreCampo As String) As Kernel.Geom.Rectangle
        Dim pdfDoc As PdfDocument = New PdfDocument(reader)
        Dim pdfAcrof = PdfAcroForm.GetAcroForm(pdfDoc, False)
        Dim cf = pdfAcrof.GetField(NombreCampo)
        Return cf.GetWidgets(0).GetRectangle.ToRectangle
    End Function

    Public Class DatosNuevoCampoFirma
        Public NombreCampo As String
        Public CoordenadaX As Single
        Public CoordenadaY As Single
        Public Ancho As Single
        Public Alto As Single
    End Class

    Public Shared Sub AseguraPdf(ByVal FicheroPdf As String, ByVal passwordUser As String, ByVal passwordOwner As String, Permisos As Integer)
        Dim srcBytes = System.IO.File.ReadAllBytes(FicheroPdf)
        Dim up As Byte() = Nothing
        Dim op As Byte() = Nothing
        If passwordUser IsNot Nothing AndAlso passwordUser <> "" Then up = Encoding.ASCII.GetBytes(passwordUser)
        If passwordOwner IsNot Nothing AndAlso passwordOwner <> "" Then op = Encoding.ASCII.GetBytes(passwordOwner)
        Dim reader As PdfReader = New PdfReader(New MemoryStream(srcBytes))
        Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(up, op, Permisos, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)

        Using memoryStream = New MemoryStream()
            Dim writer As PdfWriter = New PdfWriter(memoryStream, props)
            Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
            pdfDoc.Close()
            reader.Close()
            System.IO.File.Delete(FicheroPdf)
            System.IO.File.WriteAllBytes(FicheroPdf, memoryStream.ToArray)
        End Using
    End Sub
    Public Shared Sub AseguraPdf(ByVal PdfOrigen As String, ByVal PdfDestino As String, ByVal passwordUser As String, ByVal passwordOwner As String, Permisos As Integer)
        Dim srcBytes = System.IO.File.ReadAllBytes(PdfOrigen)
        Dim up As Byte() = Nothing
        Dim op As Byte() = Nothing
        If passwordUser IsNot Nothing AndAlso passwordUser <> "" Then up = Encoding.ASCII.GetBytes(passwordUser)
        If passwordOwner IsNot Nothing AndAlso passwordOwner <> "" Then op = Encoding.ASCII.GetBytes(passwordOwner)
        Dim reader As PdfReader = New PdfReader(New MemoryStream(srcBytes))
        Dim props As WriterProperties = New WriterProperties().SetStandardEncryption(up, op, Permisos, EncryptionConstants.ENCRYPTION_AES_128 Or EncryptionConstants.DO_NOT_ENCRYPT_METADATA)

        Using memoryStream = New MemoryStream()
            Dim writer As PdfWriter = New PdfWriter(memoryStream, props)
            Dim pdfDoc As PdfDocument = New PdfDocument(reader, writer)
            pdfDoc.Close()
            reader.Close()
            If System.IO.File.Exists(PdfDestino) Then System.IO.File.Delete(PdfDestino)
            System.IO.File.WriteAllBytes(PdfDestino, memoryStream.ToArray)
        End Using
    End Sub
    Public Shared Function CompruebaFirmaPDF(arrayCertsPadresBin As Byte()(), FicheroPdf As String, NIF As String, Optional CompruebaCoberturaFirma As Boolean = False) As Byte()
        Try
            Dim ms = New MemoryStream(System.IO.File.ReadAllBytes(FicheroPdf))
            Return CompruebaFirmaPDF(arrayCertsPadresBin, ms, NIF, CompruebaCoberturaFirma)
        Catch ex As Exception
            Throw New Exception("Error comprobando firma del fichero " & FicheroPdf & ". " & ex.Message, ex)
        End Try
    End Function
    Public Shared Function CompruebaFirmaPDF(arrayCertsPadresBin As Byte()(), pdf As Stream, NIF As String, Optional CompruebaCoberturaFirma As Boolean = False, Optional ByVal CompruebaTodasLasFirmas As Boolean = False) As Byte()
        Try
            Dim bRespuestaOCSP() As Byte = Nothing
            Dim reader = New PdfReader(pdf)
            Dim pdfd = New PdfDocument(reader)
            Dim su = New SignatureUtil(pdfd)
            Dim nombres = su.GetSignatureNames
            If nombres.Count = 0 Then Throw New Exception("El documento no contiene ninguna firma digital")
            Dim CifComprobado As Boolean = False
            Dim Nifencontrado As Boolean = False
            Dim DIEncontrados As String = ""
            For Each n In nombres
                Dim pk = su.ReadSignatureData(n)
                If Not pk.VerifySignatureIntegrityAndAuthenticity Then Throw New Exception("Alguna firma es incorrecta o el documento fue modificado")

                Dim pc = pk.GetSigningCertificate
                Dim certbin = New X509Certificate2(pc.GetEncoded).Export(X509ContentType.Cert)
                Dim iPadre As Integer = UtilsCert.BuscarCertPadre(certbin, arrayCertsPadresBin)
                If iPadre < 0 AndAlso CompruebaTodasLasFirmas Then Throw New Exception("Certificado no admitido")
                Dim dni As String = UtilsCert.ObtenerValorAtributoDN(certbin, "2.5.4.5")
                If dni.StartsWith("IDCES-") Then dni = dni.Split("-"c)(1)
                If CompruebaCoberturaFirma AndAlso dni.ToUpper = NIF.ToUpper AndAlso Not su.SignatureCoversWholeDocument(n) Then Throw New Exception("El documento fue modificado después de alguna firma, aunque esta es correcta")
                DIEncontrados &= dni & ","
                Dim msjInvalidezCert As String = ""
                Dim validoCert As Boolean = UtilsCert.ValidoCertSinRevoc(certbin, arrayCertsPadresBin, DateTime.UtcNow, msjInvalidezCert)
                If Not validoCert Then Throw New Exception("Certificado Inválido: " & msjInvalidezCert)
                Dim infoRev As UtilsCert.InfoRevoc = UtilsCert.ConsultarInfoRevoc(certbin, arrayCertsPadresBin)
                If NIF.ToLower = dni.ToLower Then
                    If infoRev.RespuestaEfectiva AndAlso infoRev.RespuestaOCSPBin IsNot Nothing Then
                        bRespuestaOCSP = infoRev.RespuestaOCSPBin
                    End If
                    Nifencontrado = True
                End If
                If infoRev.EstadoRevoc <> UtilsCert.EstadoRevocEnum.NoRevocado Then
                    Throw New Exception("No se puede confiar en el certificado. Estado de revocación: " & UtilsCert.EstadoRevocToString(infoRev.EstadoRevoc))
                End If
            Next
            If Nifencontrado = False Then Throw New Exception("El documento no ha sido firmado por el mismo nif Requerido. Documentos de identidad encontrados: " & DIEncontrados.TrimEnd(","))
            Return bRespuestaOCSP
        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        End Try
    End Function
    Public Shared Sub CompruebaFirmaPDF(arrayCertsPadresBin As Byte()(), pdf As String, ListaDNIs As List(Of String), Optional IndicesCertPadresRepresentacion As List(Of Integer) = Nothing, Optional CompruebaTodasLasFirmas As Boolean = False, Optional CompruebaCoberturaFirma As Boolean = False)
        Try
            Dim ms As MemoryStream = New MemoryStream(System.IO.File.ReadAllBytes(pdf))
            CompruebaFirmaPDF(arrayCertsPadresBin, ms, ListaDNIs, IndicesCertPadresRepresentacion, CompruebaTodasLasFirmas, CompruebaCoberturaFirma)
        Catch ex As Exception
            Throw New Exception("Error comprobando firma del fichero " & pdf & ". " & ex.Message, ex)
        End Try
    End Sub
    Public Shared Sub CompruebaFirmaPDF(arrayCertsPadresBin As Byte()(), pdf As Stream, ListaDNIs As List(Of String), Optional IndicesCertPadresRepresentacion As List(Of Integer) = Nothing, Optional CompruebaTodasLasFirmas As Boolean = False, Optional CompruebaCoberturaFirma As Boolean = False)
        Dim reader As PdfReader = Nothing
        Try
            Dim bRespuestaOCSP() As Byte = Nothing
            reader = New PdfReader(pdf)
            Dim pdfd = New PdfDocument(reader)
            Dim su = New SignatureUtil(pdfd)
            Dim nombres = su.GetSignatureNames
            If nombres.Count = 0 Then Throw New Exception("El documento no contiene ninguna firma digital")
            Dim CifComprobado As Boolean = False
            Dim Nifencontrado As Boolean = False
            For Each n In nombres
                Dim pk = su.ReadSignatureData(n)
                Dim pc = pk.GetSigningCertificate
                Dim certbin = New X509Certificate2(pc.GetEncoded).Export(X509ContentType.Cert)
                Dim iPadre As Integer = UtilsCert.BuscarCertPadre(certbin, arrayCertsPadresBin)
                Dim dni As String = ""
                If IndicesCertPadresRepresentacion IsNot Nothing AndAlso IndicesCertPadresRepresentacion.Contains(iPadre) Then
                    Try
                        dni = UtilsCert.ObtenerValorAtributoDN(certbin, "2.5.4.97")
                        If dni.StartsWith("VATES-") Then dni = dni.Split("-"c)(1)
                    Catch
                    End Try
                Else
                    Try
                        dni = UtilsCert.ObtenerValorAtributoDN(certbin, "2.5.4.5")
                        If dni.StartsWith("IDCES-") Then dni = dni.Split("-"c)(1)
                    Catch
                    End Try
                End If
                Dim sdniorep = ListaDNIs.FirstOrDefault(Function(x) x.Contains(dni))
                If sdniorep IsNot Nothing Then
                    If Not pk.VerifySignatureIntegrityAndAuthenticity Then Throw New Exception("La firma es incorrecta o el documento fue modificado")
                    If CompruebaCoberturaFirma AndAlso Not su.SignatureCoversWholeDocument(n) Then Throw New Exception("Aunque la firma es correcta, el documento fue modificado después de alguna firma")
                    If iPadre < 0 Then Throw New Exception("Certificado no admitido")
                    ListaDNIs.Remove(sdniorep)
                    Dim msjInvalidezCert As String = ""
                    Dim validoCert As Boolean = UtilsCert.ValidoCertSinRevoc(certbin, arrayCertsPadresBin, DateTime.UtcNow, msjInvalidezCert)
                    If Not validoCert Then Throw New Exception("Certificado Inválido: " & msjInvalidezCert)
                    Dim infoRev As UtilsCert.InfoRevoc = UtilsCert.ConsultarInfoRevoc(certbin, arrayCertsPadresBin)
                    If infoRev.RespuestaEfectiva AndAlso infoRev.RespuestaOCSPBin IsNot Nothing Then
                        bRespuestaOCSP = infoRev.RespuestaOCSPBin
                    End If
                    If infoRev.EstadoRevoc <> UtilsCert.EstadoRevocEnum.NoRevocado Then
                        Throw New Exception("No se puede confiar en el certificado. Estado de revocación: " & UtilsCert.EstadoRevocToString(infoRev.EstadoRevoc))
                    End If
                Else
                    If CompruebaTodasLasFirmas Then
                        If Not pk.VerifySignatureIntegrityAndAuthenticity Then Throw New Exception("La firma es incorrecta o el documento fue modificado")
                        If CompruebaCoberturaFirma AndAlso Not su.SignatureCoversWholeDocument(n) Then Throw New Exception("Aunque la firma es correcta, el documento fue modificado después de alguna firma")
                        If iPadre < 0 Then Throw New Exception("Certificado no admitido")
                    End If
                End If
            Next
            If ListaDNIs.Count > 0 Then Throw New Exception("Falta alguna firma de las exigidas o de sus representantes en el fichero")
        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        Finally
            If reader IsNot Nothing Then
                reader.Close()
            End If
        End Try
    End Sub
    Public Shared Sub ValidarAutoridadesFNMT(ByVal raizFnmtBin As Byte(),
                                          ByVal acFnmtUsuariosBin As Byte(),
                                          ByVal acFnmtRepresentacionBin As Byte())

        '-----------------------------------------------------------------------------------------------
        ' Valida las Autoridades de Certificación de la FNMT permitidas (PASO 1 DEL PROCESO GENERAL).
        ' La validación se realiza en la FECHA ACTUAL.
        ' Eleva EXCEPCIÓN si hay algún problema.
        '-----------------------------------------------------------------------------------------------
        ' 1. Validar las Autoridades de Certificación (ACs) en las que confiamos:
        '     1.1 Validar las Raíces con ellas mismas (sin analizar revocación), y
        '         opcionalmente comprobar que sus hashes SHA-1 coinciden con los precableados
        '         (para evitar que las Raíces sean sustituidas en la Base de Datos).
        '     1.2 Validar las ACs intermedias con sus padres correspondientes, y comprobar su revocación.
        '-----------------------------------------------------------------------------------------------

        Dim fechaActualUTC As Date = DateTime.UtcNow

        Dim msjInvalidezCert As String = ""

        ' Raíz FNMT:

        If Not UtilsCert.ValidoCertSinRevoc(raizFnmtBin, raizFnmtBin, fechaActualUTC, msjInvalidezCert) Then
            Throw New Exception("La Raíz de la FNMT NO es válida." & vbCrLf & msjInvalidezCert)
        End If

        If UtilsCert.CalcularSHA1Str(raizFnmtBin) <> "EC503507B215C4956219E2A89A5B42992C4C2C20" Then
            Throw New Exception("Problema de seguridad encontrado.")
        End If

        ' AC FNMT Usuarios:

        If Not UtilsCert.ValidoCertSinRevoc(acFnmtUsuariosBin, raizFnmtBin, fechaActualUTC, msjInvalidezCert) Then
            Throw New Exception("La AC FNMT Usuarios NO es válida." & vbCrLf & msjInvalidezCert)
        End If

        Dim infoRevACUsuarios As UtilsCert.InfoRevoc = UtilsCert.ConsultarInfoRevoc(acFnmtUsuariosBin, raizFnmtBin)

        If infoRevACUsuarios.EstadoRevoc <> UtilsCert.EstadoRevocEnum.NoRevocado Then
            Throw New Exception("No se puede confiar en la AC FNMT Usuarios." & vbCrLf &
                                "Estado de revocación: " & UtilsCert.EstadoRevocToString(infoRevACUsuarios.EstadoRevoc) & vbCrLf &
                                infoRevACUsuarios.MsjEstadoRevoc)
        End If

        ' AC FNMT Representación:

        If Not UtilsCert.ValidoCertSinRevoc(acFnmtRepresentacionBin, raizFnmtBin, fechaActualUTC, msjInvalidezCert) Then
            Throw New Exception("La AC FNMT Representación NO es válida." & vbCrLf & msjInvalidezCert)
        End If

        Dim infoRevACRepresentacion As UtilsCert.InfoRevoc = UtilsCert.ConsultarInfoRevoc(acFnmtRepresentacionBin, raizFnmtBin)

        If infoRevACRepresentacion.EstadoRevoc <> UtilsCert.EstadoRevocEnum.NoRevocado Then
            Throw New Exception("No se puede confiar en la AC FNMT Representación." & vbCrLf &
                                "Estado de revocación: " & UtilsCert.EstadoRevocToString(infoRevACRepresentacion.EstadoRevoc) & vbCrLf &
                                infoRevACRepresentacion.MsjEstadoRevoc)
        End If

    End Sub
    Public Shared Function ListadoDIFirmantes(arrayCertsPadresBin As Byte()(), pdf As String, Optional IndicesCertPadresRepresentacion As List(Of Integer) = Nothing, Optional CompruebaTodasLasFirmas As Boolean = False, Optional CompruebaCoberturaFirma As Boolean = False, Optional ByRef Advertencias As List(Of tsPDFUtilException) = Nothing) As List(Of String)
        Try
            Dim ms As MemoryStream = New MemoryStream(System.IO.File.ReadAllBytes(pdf))
            Return ListadoDIFirmantes(arrayCertsPadresBin, ms, IndicesCertPadresRepresentacion, CompruebaTodasLasFirmas, CompruebaCoberturaFirma, Advertencias)
        Catch ex As Exception
            Throw New Exception("Error comprobando firma del fichero " & pdf & ". " & ex.Message, ex)
        End Try
    End Function

    Public Shared Function ListadoDIFirmantes(arrayCertsPadresBin As Byte()(), pdf As Stream, Optional IndicesCertPadresRepresentacion As List(Of Integer) = Nothing, Optional CompruebaTodasLasFirmas As Boolean = False, Optional CompruebaCoberturaFirma As Boolean = False, Optional ByRef Advertencias As List(Of tsPDFUtilException) = Nothing) As List(Of String)
        Dim reader As PdfReader = Nothing
        Dim ListaFirmasCorrectas As New List(Of String)
        Try
            Dim bRespuestaOCSP() As Byte = Nothing
            reader = New PdfReader(pdf)
            Dim pdfd = New PdfDocument(reader)
            Dim su = New SignatureUtil(pdfd)
            Dim nombres = su.GetSignatureNames
            If nombres.Count = 0 Then Throw New Exception("El documento no contiene ninguna firma digital")
            Dim CifComprobado As Boolean = False
            Dim Nifencontrado As Boolean = False
            For Each n In nombres
                Dim dni As String = ""
                Try
                    dni = ""
                    Dim pk = su.ReadSignatureData(n)
                    Dim pc = pk.GetSigningCertificate
                    Dim certbin = New X509Certificate2(pc.GetEncoded).Export(X509ContentType.Cert)
                    Dim iPadre As Integer = UtilsCert.BuscarCertPadre(certbin, arrayCertsPadresBin)

                    If IndicesCertPadresRepresentacion IsNot Nothing AndAlso IndicesCertPadresRepresentacion.Contains(iPadre) Then
                        Try
                            dni = UtilsCert.ObtenerValorAtributoDN(certbin, "2.5.4.97")
                            If dni.StartsWith("VATES-") Then dni = dni.Split("-"c)(1)
                        Catch
                        End Try
                    Else
                        Try
                            dni = UtilsCert.ObtenerValorAtributoDN(certbin, "2.5.4.5")
                            If dni.StartsWith("IDCES-") Then dni = dni.Split("-"c)(1)
                        Catch
                        End Try
                    End If
                    If Not pk.VerifySignatureIntegrityAndAuthenticity Then Throw New tsPDFUtilException("La firma es incorrecta o el documento fue modificado", "FIRMA_INCORRECTA")
                    If CompruebaCoberturaFirma AndAlso Not su.SignatureCoversWholeDocument(n) Then Throw New tsPDFUtilException("Aunque la firma es correcta, el documento fue modificado después de alguna firma", "DOCUMENTO_MODIFICADO")
                    If iPadre < 0 Then Throw New tsPDFUtilException("Certificado no admitido", "CERTIFICADO_NO_ADMITIDO")
                    Dim msjInvalidezCert As String = ""
                    Dim validoCert As Boolean = UtilsCert.ValidoCertSinRevoc(certbin, arrayCertsPadresBin, DateTime.UtcNow, msjInvalidezCert)
                    If Not validoCert Then Throw New Exception("Certificado Inválido: " & msjInvalidezCert)
                    Dim infoRev As UtilsCert.InfoRevoc = UtilsCert.ConsultarInfoRevoc(certbin, arrayCertsPadresBin)
                    If infoRev.RespuestaEfectiva AndAlso infoRev.RespuestaOCSPBin IsNot Nothing Then
                        bRespuestaOCSP = infoRev.RespuestaOCSPBin
                    End If
                    If infoRev.EstadoRevoc <> UtilsCert.EstadoRevocEnum.NoRevocado Then
                        Throw New tsPDFUtilException("No se puede confiar en el certificado. Estado de revocación: " & UtilsCert.EstadoRevocToString(infoRev.EstadoRevoc), "CERTIFICADO_REVOCADO")
                    End If
                    ListaFirmasCorrectas.Add(dni)
                Catch ex As tsPDFUtilException
                    If Advertencias IsNot Nothing Then
                        Advertencias.Add(ex)
                    End If
                Catch ex As Exception
                    If Advertencias IsNot Nothing Then
                        Advertencias.Add(New tsPDFUtilException(ex.Message, "DESCONOCIDA"))
                    End If
                End Try
            Next
            Return ListaFirmasCorrectas
        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        Finally
            If reader IsNot Nothing Then
                reader.Close()
            End If
        End Try
    End Function

    Public Shared Function ListadoCamposFirmas(pdf As String) As List(Of String)
        Try
            Dim ms As MemoryStream = New MemoryStream(System.IO.File.ReadAllBytes(pdf))
            Return ListadoCamposFirmas(ms)
        Catch ex As Exception
            Throw New Exception("Error comprobando nombres de campos de firmas " & pdf & ". " & ex.Message, ex)
        End Try
    End Function
    Public Shared Function ListadoCamposFirmas(pdf As Stream) As List(Of String)
        Dim reader As PdfReader = Nothing
        Try
            reader = New PdfReader(pdf)
            Dim pdfd = New PdfDocument(reader)
            Dim su = New SignatureUtil(pdfd)
            Dim nombres = su.GetSignatureNames.ToList
            Return nombres
        Catch ex As Exception
            Throw New Exception(ex.Message, ex)
        Finally
            If reader IsNot Nothing Then
                reader.Close()
            End If
        End Try
    End Function
    Public Shared Function ListadoCampos(pdf As String) As List(Of String)
        Try
            Dim ms As MemoryStream = New MemoryStream(System.IO.File.ReadAllBytes(pdf))
            Return ListadoCampos(ms)
        Catch ex As Exception
            Throw New Exception("Error comprobando nombres de campos " & pdf & ". " & ex.Message, ex)
        End Try
    End Function
    Public Shared Function ListadoCampos(pdf As Stream) As List(Of String)
        Dim reader As PdfReader = Nothing
        Try
            reader = New PdfReader(pdf)
            Dim pdfd = New PdfDocument(reader)
            Dim campos = PdfAcroForm.GetAcroForm(pdfd, False).GetAllFormFields.Select(Function(x) x.Key).ToList
            Return campos
        Catch ex As Exception
            Throw New Exception("Error comprobando nombres de campos. " & ex.Message, ex)
        Finally
            If reader IsNot Nothing Then
                reader.Close()
            End If
        End Try
    End Function
End Class
