'************************************************************************* ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED ' TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A ' PARTICULAR PURPOSE. ' ' Copyright (C) 2001. Microsoft Corporation. All rights reserved. ' ' VerifyPKCS7 CAPICOM 2 sample script to verify either ' included or detached-content CMS/pkcs7 signature data files. ' Signature file can be either binary DER or base64-encoded DER format. ' Can verify content signed as UNICODE-encoded or ASCII-encoded, or ' raw (binary data) byte encoded. ' Can verify content signed with Netscape Formsigning crypto.signText() ' For binary-file usage (ADODB.Stream), requires MDAC 2.5: ' http://support.microsoft.com/default.aspx?scid=kb;EN-US;q231943 ' ' Verifies signature alone and then signature with certificate validity ' ' M. Gallant May 18, 2007 '************************************************************************* ' ' VerifyAll.vbs ' ' This script runs from the command prompt and takes one or two arguments. ' For single argument, assumes that content is included in signature. ' ' 1) filename of a signed/cosigned message to be verified ' 2) filename containing the detached content, required to verify detached signature ' ' Note: For Win95, Win98, WinME, and NT 4.0, this script may sometime ' trigger a known deadlock situation in CRYPT32.DLL, and thus ' not exit completely. ' Please see Q238934 for more information about this problem. ' Option Explicit Const Title = "VerifyPKCS7" Const CAPICOM_VERIFY_SIGNATURE_ONLY = 0 Const CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE = 1 Const CAPICOM_LOCAL_MACHINE_STORE = 1 Const CAPICOM_STORE_OPEN_READ_ONLY = 0 Const ForReading = 1, ForWriting = 2 Const ContentFileOut = "contentout.txt" Const CAPICOMdnld = "http://www.microsoft.com/downloads/release.asp?ReleaseID=39546" Dim Verbose :Verbose = TRUE Dim ValidSig :ValidSig = False Dim ValidCert :ValidCert = False Dim Verifytype :Verifytype = CAPICOM_VERIFY_SIGNATURE_ONLY ' Check syntax. If Wscript.Arguments.Count <1 OR Wscript.Arguments.Count > 2 Then MsgBox "Usage: VerifyPKCS7.vbs SignedFileName [ContentFileName] ", _ vbInformation, Title WScript.Quit(1) End If If NOT isCapicomAvailable Then MsgBox "CAPICOM is not installed." & vbCrLf & _ "Install capicom first via: " & vbCrLf & _ CAPICOMdnld, vbCritical, Title WScript.Quit(1) End If '----- Call main signature verification routines -------------- ReDim SignerNames(0) If WScript.Arguments.Count = 1 Then 'Assume we have included-content case DoesFileExist(Wscript.Arguments(0)) Verifytype = CAPICOM_VERIFY_SIGNATURE_ONLY ValidSig = VerifyIncludedFile(WScript.Arguments(0), ContentFileOut, SignerNames, Verifytype) If NOT ValidSig Then MsgBox "Could not verify """ & WScript.Arguments(0) & """ as a pkcs7 signature file with included content. " & _ VBCrLf & ErrInfo(Err), vbCritical, Title WScript.Quit(1) End If Verifytype = CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE VerifyCert = VerifyIncludedFile(WScript.Arguments(0), ContentFileOut, SignerNames, Verifytype) Else 'Assume we have detached-content case DoesFileExist(Wscript.Arguments(0)) DoesFileExist(Wscript.Arguments(1)) Verifytype = CAPICOM_VERIFY_SIGNATURE_ONLY ValidSig = VerifyDetachedFile(Wscript.Arguments(0), Wscript.Arguments(1), SignerNames, Verifytype) If NOT ValidSig Then MsgBox "Could not verify """ & WScript.Arguments(0) & _ """ as a pkcs7 signature file " & vbCrLf & _ "with detached content file """ & Wscript.Arguments(1) & """. " _ , vbCritical, Title WScript.Quit(1) End If Verifytype = CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE ValidCert = VerifyDetachedFile(Wscript.Arguments(0), Wscript.Arguments(1), SignerNames, Verifytype) End If ' Format signer names. Dim Index Dim Names For Index = 0 to UBound(SignerNames) If Index > 0 Then Names = Names + ", " End If If UBound(SignerNames) > 0 And Index = UBound(SignerNames) Then Names = Names + "and " End If Names = Names + SignerNames(Index) Next Names = Names + "." '--- At this stage, we have a valid signature but the certificate might not be valid if it was '--- was issued by an unknown CA or if the certificate has expired and there is no timestamp If WScript.Arguments.Count = 2 AND ValidCert Then MsgBox "The signed message of """ & Wscript.Arguments(0) & """ has been " & _ "successfully verified," & vbCrLf & "as a pkcs7 signature file " & _ "using the detached content file """ & _ Wscript.Arguments(1) & """." & vbCrLf & vbCrLf & _ "The message was signed by " & Names & vbCrLf & vbCrLf & "The certificate is valid.", vbInformation, Title ElseIf WScript.Arguments.Count = 2 AND NOT ValidCert Then MsgBox "The signed message of """ & Wscript.Arguments(0) & """ has been " & _ "successfully verified," & vbCrLf & "as a pkcs7 signature file " & _ "using the detached content file """ & _ Wscript.Arguments(1) & """." & vbCrLf & vbCrLf & _ "The message was signed by " & Names & vbCrLf & vbCrLf & _ "The certificate is NOT valid because the root certificate of the signer's certificate chain is not trusted, " & vbCrLf & _ "OR because the current system time or timestamp time is not within the certificate validity period!", vbExclamation, Title ElseIf WScript.Arguments.Count = 1 AND ValidCert Then MsgBox "The signed message of """ & Wscript.Arguments(0) & """ has been " & _ "successfully verified," & vbCrLf & "as a pkcs7 signature file " & _ "using the INCLUDED content " & _ "." & vbCrLf & vbCrLf & _ "The message was signed by " & Names & vbCrLf & vbCrLf & "The certificate is valid.", vbInformation, Title ElseIf WScript.Arguments.Count = 1 AND NOT ValidCert Then MsgBox "The signed message of """ & Wscript.Arguments(0) & """ has been " & _ "successfully verified," & vbCrLf & "as a pkcs7 signature file " & _ "using the INCLUDED content " & _ "." & vbCrLf & vbCrLf & _ "The message was signed by " & Names & vbCrLf & vbCrLf & _ "The certificate is NOT valid because the root certificate of the signer's certificate chain is not trusted, " & vbCrLf & _ "OR because the current system time or timestamp time is not within the certificate validity period!", vbExclamation, Title End If ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' isCapicomAvailable ' ' Checks if CAPICOM is installed ' Function isCapicomAvailable() Dim oStore On Error Resume Next Set oStore = CreateObject("CAPICOM.Store") oStore.Open CAPICOM_LOCAL_MACHINE_STORE, "Root", CAPICOM_STORE_OPEN_READ_ONLY If Err.Number <> 0 Then isCapicomAvailable = False Exit Function End If isCapicomAvailable = True Set oStore = Nothing On Error GoTo 0 End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' DoesFileExist ' ' Checks if content file to sign exists ' Sub DoesFileExist(FileName) Dim fso Set fso = CreateObject("Scripting.FileSystemObject") If Not fso.FileExists(FileName) Then MsgBox """" & FileName & """ file not found. ", vbCritical, Title WScript.Quit(1) End If Set fso = nothing End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' ErrInfo ' ' Return error number (hex) and information ' Function ErrInfo(Error) ErrInfo = "Error: " & Hex(Error.Number) & " " & Error.Description End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' VerifyIncludedFile ' ' Verify signed message (with included content) of InFile. Try reading InFile ' as text file and if fails, try readint as binary file. ' [Optionally] Save verified content to OutFile, ' and return the list of signer's names to SignerNames. ' Function VerifyIncludedFile (InFile, OutFile, SignerNames, Verifyflag) Dim SignedData, Utils Dim bMessage, Message ' Verify signed message. Set SignedData = CreateObject("CAPICOM.SignedData") LoadFile InFile, Message 'Try loading pkcs7 as text file On Error Resume Next If Verbose Then WScript.Echo "Trying signature file as text file .." End If SignedData.Verify Message, FALSE, Verifyflag If Err.Number <> 0 Then ' If error then try reading as binary pkcs7 'WScript.Echo "Reading pkcs7 file as binary ..." If Verbose Then WScript.Echo ErrInfo(Err) & vbCrLf & "Trying signature file as binary .." End If Err.Clear Set Utils = CreateObject("CAPICOM.Utilities") LoadBinFile InFile, bMessage Message = Utils.ByteArrayToBinaryString(bMessage)'convert from byte array to binary-packed string SignedData.Verify Message, FALSE, Verifyflag If Err.Number <> 0 Then VerifyIncludedFile = False ' If included signature not verified, set status and return. Exit Function End If Set Utils = nothing End If On Error GoTo 0 'SaveFile OutFile, SignedData.Content ' Retrieve signer's names. Dim Signer Dim Index : Index = 0 ReDim SignerNames(SignedData.Signers.Count - 1) For Each Signer In SignedData.Signers SignerNames(Index) = Signer.Certificate.GetInfo(0) Index = Index + 1 Next VerifyIncludedFile = True End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' VerifyDetachedFile ' ' Verify detached signed message of InFile using detached content file, ' and return the list of signer's names to SignerNames. ' Function VerifyDetachedFile (SigFile, ContentFile, SignerNames, Verifyflag) Dim SignedData, Utils Dim bMessage, Message Dim bContent, Content ' Verify signed message. Set SignedData = CreateObject("CAPICOM.SignedData") '----- First try reading pkcs7 and content files as text ---- 'Load signature from SigFile to Message buffer 'Load message text from ContentFile to Content buffer LoadFile SigFile, Message LoadFile ContentFile, Content On Error Resume Next If Verbose Then WScript.Echo "Trying UNICODE byte-encoding .." End If SignedData.Content = Content ' Try default vbs UNICODE string SignedData.Verify Message, TRUE, Verifyflag ' Detached signature If Err.Number <> 0 Then ' If error, see if data signed was ASCII byte-encoded If Verbose Then WScript.Echo ErrInfo(Err) & vbCrLf & "Trying ASCII byte-encoding .." End If Err.Clear SignedData.Content = MyStrConv(Content) 'UNICODE to ASCII string SignedData.Verify Message, TRUE, Verifyflag ' Try verifying ASCII byte-encoded signature '---- If fails, try reading pkcs7 and content as binary files ---- If Err.Number <> 0 Then If Verbose Then WScript.Echo ErrInfo(Err) & vbCrLf & "Trying reading as binary files ..." End If Err.Clear Set Utils = CreateObject("CAPICOM.Utilities") LoadBinFile SigFile, bMessage LoadBinFile ContentFile, bContent Message = Utils.ByteArrayToBinaryString(bMessage)'byte array to binary-packed string Content = Utils.ByteArrayToBinaryString(bContent) SignedData.Content = Content SignedData.Verify Message, TRUE, Verifyflag If Err.Number <> 0 Then If Verbose Then WScript.Echo ErrInfo(Err) & vbCrLf & "Signature Verification failed!" End If VerifyDetachedFile = False 'If detached signature not verified, set status and return. Exit Function End If Set Utils = nothing End If End If On Error Goto 0 ' Retrieve signer's names. Dim Signer Dim Index : Index = 0 ReDim SignerNames(SignedData.Signers.Count - 1) For Each Signer In SignedData.Signers SignerNames(Index) = Signer.Certificate.GetInfo(0) Index = Index + 1 Next VerifyDetachedFile = True 'If here, then detached signature is verified End Function ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' LoadFile ' ' Read content of FileName and assign to Buffer as string. ' Sub LoadFile (FileName, Buffer) Dim fso Set fso = CreateObject("Scripting.FileSystemObject") If Not fso.FileExists(FileName) Then MsgBox "Error: " & FileName & " file not found." Exit Sub End If Dim ts Set ts = fso.OpenTextFile(FileName, ForReading) Buffer = ts.ReadAll End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' LoadBinFile ' ' Read content of FileName and return as byte array. ' Sub LoadBinFile (FileName, bBuffer) Const adReadAll = -1 Dim oStream, bFileData Set oStream = WScript.CreateObject("ADODB.Stream") oStream.Open oStream.Type = 1 ' adTypeBinary oStream.LoadFromFile FileName bBuffer = oStream.Read(adReadAll) oStream.Close Set oStream = nothing End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' SaveFile ' ' Save string Buffer to FileName. ' Sub SaveFile (FileName, Buffer) Dim fso Set fso = CreateObject("Scripting.FileSystemObject") Dim ts Set ts = fso.OpenTextFile(FileName, ForWriting, True) ts.Write Buffer End Sub ' --- Convert from UNICODE string to ASCII byte buffer -------- Function MyStrConv(Ustr) Dim i Dim ch MyStrConv = "" For i = 1 to Len(Ustr) ch = Mid(Ustr, i, 1) MyStrConv = MyStrConv & ChrB(AscB(ch)) Next End Function