function VerifySignature(Index: Integer): Integer;
var
Signer: TElPKCS7Signer;
Certificate: TElX509Certificate;
Lookup: TElCertificateLookup;
I, TagID: Integer;
IncludedDigest, OriginalDigest, DecryptedDigest: string;
MD5: TMessageDigest128;
SHA1: TMessageDigest160;
Data: string;
begin
try
// check for signature index validity
Result := SB_AUTHENTICODE_ERROR_INVALID_INDEX;
if (Index < 0) or (Index >= FMessage.SignedData.SignerCount) then
Exit;
Signer := FMessage.SignedData.Signers[Index];
if Signer = nil then
Exit;
// attempt to find signer's certificate
Result := SB_AUTHENTICODE_ERROR_NO_SIGNER_CERTIFICATE;
Certificate := nil;
Lookup := TElCertificateLookup.Create(nil);
try
Lookup.Criteria := [lcIssuer];
Lookup.Options := [loExactMatch, loMatchAll];
Lookup.IssuerRDN.Assign(Signer.Issuer.Issuer);
I := FMessage.SignedData.Certificates.FindFirst(Lookup);
while I >= 0 do
begin
if FMessage.SignedData.Certificates.Certificates[I].SerialNumber = Signer.Issuer.SerialNumber then
begin
Certificate := FMessage.SignedData.Certificates.Certificates[I];
Break;
end;
I := FMessage.SignedData.Certificates.FindNext(Lookup);
end;
finally
Lookup.Free;
end;
if (Certificate = nil) and (FCertStorage <> nil) then
begin
Lookup := TElCertificateLookup.Create(nil);
try
Lookup.Criteria := [lcIssuer];
Lookup.Options := [loExactMatch, loMatchAll];
Lookup.IssuerRDN.Assign(Signer.Issuer.Issuer);
I := FCertStorage.FindFirst(Lookup);
while I >= 0 do
begin
if FCertStorage.Certificates[I].SerialNumber = Signer.Issuer.SerialNumber then
begin
Certificate := FCertStorage.Certificates[I];
Break;
end;
I := FCertStorage.FindNext(Lookup);
end;
finally
Lookup.Free;
end;
end;
if Certificate = nil then
Exit;
// calculate digest for authenticated attributes
if Signer.DigestAlgorithm = SB_OID_MD5 then
begin
MD5 := HashMD5(Signer.AuthenticatedAttributesPlain);
SetLength(OriginalDigest, SizeOf(MD5));
Move(MD5, OriginalDigest[1], SizeOf(MD5));
end
else
if Signer.DigestAlgorithm = SB_OID_SHA1 then
begin
SHA1 := HashSHA1(Signer.AuthenticatedAttributesPlain);
SetLength(OriginalDigest, SizeOf(SHA1));
Move(SHA1, OriginalDigest[1], SizeOf(SHA1));
end
else
begin
Result := SB_AUTHENTICODE_ERROR_INVALID_ALGORITHM;
Exit;
end;
// check for authenticated attributes digest validity
Result := SB_AUTHENTICODE_ERROR_INVALID_SIGNATURE;
if (Signer.DigestEncryptionAlgorithm = SB_OID_RSAENCRYPTION) and
(Certificate.PublicKeyAlgorithm = SB_CERT_ALGORITHM_ID_RSA_ENCRYPTION) then
begin
DecryptedDigest := DecryptRSA(Signer.EncryptedDigest, Certificate);
if DecryptedDigest = '' then
Exit;
// compare the decrypted digest with calculated one
if DecryptedDigest <> OriginalDigest then
Exit;
end
else
if (Signer.DigestEncryptionAlgorithm = SB_OID_DSA) and
(Certificate.PublicKeyAlgorithm = SB_CERT_ALGORITHM_ID_DSA) then
begin
if not VerifyDSA(Signer.DigestAlgorithm, Signer.EncryptedDigest, OriginalDigest, Certificate) then
Exit;
end
else
begin
Result := SB_AUTHENTICODE_ERROR_INVALID_ALGORITHM;
Exit;
end;
// attempt to find included digest for authenticode data
Result := SB_AUTHENTICODE_ERROR_SIGNATURE_CORRUPTED;
IncludedDigest := '';
if Signer.AuthenticatedAttributes.Count > 0 then
begin
for I := 0 to Signer.AuthenticatedAttributes.Count - 1 do
if (Signer.AuthenticatedAttributes.Attributes[I] = SB_OID_MESSAGE_DIGEST) and
(Signer.AuthenticatedAttributes.Values[I].Count > 0) then
begin
IncludedDigest := UnformatAttributeValue(Signer.AuthenticatedAttributes.Values[I].Strings[0], TagID);
Break;
end;
end;
if IncludedDigest = '' then
Exit;
// calculate digest for authenticode data
Result := SB_AUTHENTICODE_ERROR_SIGNATURE_CORRUPTED;
if Length(FMessage.SignedData.Content) < 2 then
Exit;
if Ord(FMessage.SignedData.Content[1]) <> $30 then
Exit;
case Ord(FMessage.SignedData.Content[2]) of
$81: Data := Copy(FMessage.SignedData.Content, 4, MaxInt);
$82: Data := Copy(FMessage.SignedData.Content, 5, MaxInt);
$83: Data := Copy(FMessage.SignedData.Content, 6, MaxInt);
else
if Ord(FMessage.SignedData.Content[2]) < $81 then
Data := Copy(FMessage.SignedData.Content, 3, MaxInt)
else
Exit;
end;
if Signer.DigestAlgorithm = SB_OID_MD5 then
begin
MD5 := HashMD5(Data);
SetLength(OriginalDigest, SizeOf(MD5));
Move(MD5, OriginalDigest[1], SizeOf(MD5));
end
else
if Signer.DigestAlgorithm = SB_OID_SHA1 then
begin
SHA1 := HashSHA1(Data);
SetLength(OriginalDigest, SizeOf(SHA1));
Move(SHA1, OriginalDigest[1], SizeOf(SHA1));
end
else
begin
Result := SB_AUTHENTICODE_ERROR_INVALID_ALGORITHM;
Exit;
end;
// check for authenticode data digest validity
if OriginalDigest <> IncludedDigest then
begin
Result := SB_AUTHENTICODE_ERROR_INVALID_SIGNATURE;
Exit;
end;
if (FActualDigest <> FDigest) then
Result := SB_AUTHENTICODE_ERROR_INVALID_AUTHENTICODE
else
Result := SB_AUTHENTICODE_ERROR_SUCCESS;
except
Result := SB_AUTHENTICODE_ERROR_UNKNOWN;
end;
end;