Thursday, March 30, 2006

Hunting down invalid signatures

I have spent the last few days trying to hunt down an archive problem in a notes mail file. In doing this, I wrote a small lotusscript button to verify signatures that I can share here.

This could be written in the C API. However, keeping it in a button makes it easy to email out to users for them to test.

Const MAXUSERNAME =256
Declare Function NSFNoteVerifySignature Lib "nnotes.dll" Alias "NSFNoteVerifySignature" ( Byval hNote As Long, Byval null1 As Long, Byval null2 As Long, Byval retSigner As String, Byval retCertifier As String) As Integer
Declare Function NSFNoteUnsign Lib "nnotes.dll" Alias "NSFNoteUnsign" ( Byval hNote As Long) As Integer
Const NOERROR = 0
Const PKG_NSF = 512
Const ERR_NOTE_NOT_SIGNED = PKG_NSF+89 'Document is not signed
Const ERR_NOTE_INVSIG2 = PKG_NSF+91 'Document has been modified or corrupted since signed! (data)

Sub Click(Source As Button)
Dim ses As New NotesSession, irc As Integer
Dim retSigner As String, retCertifier As String
Dim doc As notesdocument, vw As NotesView
Dim db As notesdatabase
Dim dc As notesdocumentcollection
Dim fileNum%
Dim i As Integer, count As Integer

Set vw = ses.currentdatabase.views(0)
Set db = ses.currentdatabase

fileNum% = Freefile
Open "c:\temp\signatures.txt" For Output As fileNum%


Set dc = db.GetProfileDocCollection()
Set doc = dc.GetFirstDocument
count = dc.Count
i = 1
Print "Check profile Notes: " &Cstr(count)
While Not doc Is Nothing
Call fix_signature(doc, fileNum, i, count)
i = i + 1
Set doc = dc.GetNextDocument(doc)
Wend

Set dc = db.AllDocuments
Set doc = dc.GetFirstDocument
count = dc.Count
i = 1
Print "Check data Notes: " &Cstr(count)
While Not doc Is Nothing
Call fix_signature(doc, fileNum, i, count)
i = i + 1
Set doc = dc.GetNextDocument(doc)
Wend

Close fileNum%
End Sub

Sub fix_signature(doc As notesdocument, fileNum%, i, count)
Dim textline As String
retSigner = String$(MAXUSERNAME ,Chr(0))
retCertifier = String$(MAXUSERNAME ,Chr(0))

irc%= NSFNoteVerifySignature (doc.handle, 0, 0, retSigner, retCertifier)
Print Cstr(i) &"/" &Str(count)
If irc% = NOERROR Then
textline = "SIGNED: " &Cstr(doc.NoteID) &" " &Left(retSigner, Instr(retSigner,Chr(0))-1)
Write #fileNum%, textline
Elseif irc% = ERR_NOTE_NOT_SIGNED Then
textline = "NO SIGNATURE: " &Cstr(doc.NoteID)
Write #fileNum%, textline
Elseif irc% = ERR_NOTE_INVSIG2 Then
textline = "INVALID_SIGNATURE: " &Cstr(doc.NoteID)
irc% = NSFNoteUnsign(doc.handle)
If (irc% = NO_ERROR) Then
Call doc.Save(True, False)
textline = "REMOVED SIGNATURE: " &Cstr(doc.NoteID)
Else
textline = "COULD NOT REMOVE SIGNATURE: " &Cstr(doc.NoteID)
End If
Write #fileNum%, textline
Else
textline = "ERR: " &Cstr(irc%) &" " &Cstr(doc.NoteID)
Write #fileNum%, textline
End If
End Sub

1 comment:

Anonymous said...

Verifying eSign in the controlled acces section:

SignatureItemName - Specify NULL to verify the signature of a note. Specify the SignatureItemName to verify a signature of a field that resides in a section of a note. The SignatureItemName is a zero-terminated LMBCS string of the form $Sig_sectionname, where sectionname is the name of a section to verify.

here`s the sample:

Declare Function NSFNoteVerifySignature Lib "nnotes.dll" Alias "NSFNoteVerifySignature" ( Byval hNote As Long, Byval szName As String, Byval null2 As Long, Byval retSigner As String, Byval retCertifier As String) As Integer
Declare Function NSFNoteUnsign Lib "nnotes.dll" Alias "NSFNoteUnsign" ( Byval hNote As Long) As Integer

Sub Click(Source As Button)
Const MAXUSERNAME =256
Const NOERROR = 0
Const PKG_NSF = 512
Const ERR_NOTE_NOT_SIGNED = PKG_NSF+89 'Document is not signed
Const ERR_NOTE_INVSIG2 = PKG_NSF+91 'Document has been modified or corrupted since signed! (data)


Dim ses As New NotesSession, irc As Integer
Dim retSigner As String, retCertifier As String, szName As String
Dim doc As notesdocument, vw As NotesView
Dim db As notesdatabase
Dim vc As NotesViewEntryCollection, entry As NotesViewEntry

Dim i As Integer, count As Integer

Set vw = ses.currentdatabase.GetView("YOUR_VIEW")
Set db = ses.currentdatabase
Set vc = vw.AllEntries

Set entry = vc.GetFirstEntry

count = vc.Count
i = 1

While Not entry Is Nothing
Set doc=entry.Document
Call fix_signature(doc, i, count)
i = i + 1

Set entry = vc.GetNextEntry(entry)
Wend


End Sub

Sub fix_signature(doc As notesdocument, i, count)

retSigner = String$(MAXUSERNAME ,Chr(0))
retCertifier = String$(MAXUSERNAME ,Chr(0))


irc%= NSFNoteVerifySignature (doc.handle,"$Sig_Sign", 0, retSigner, retCertifier)
Print Cstr(i) &"/" &Str(count)
If irc% = NOERROR Then
textline = "SIGNED: " &Cstr(doc.NoteID)

Else
textline = "Corrupted eSign: NOTEID = " & Cstr(doc.NoteID)
If irc% = 603 Then
Messagebox textline
End If

End If
End Sub