38 const ushort IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
39 const ushort IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
40 const int WIN_CERT_REVISION_2_0 = 0x0200;
41 const int WIN_CERT_TYPE_PKCS_SIGNED_DATA = 0x0002;
43 internal static X509Certificate GetSignerCertificate(Stream stream)
45 stream.Seek(60, SeekOrigin.Begin);
46 var br =
new BinaryReader(stream);
47 var peSignatureOffset = br.ReadInt32();
48 var checksumOffset = peSignatureOffset + 24 + 64;
51 stream.Seek(peSignatureOffset + 24, SeekOrigin.Begin);
52 var certificateTableDataDirectoryOffset = br.ReadUInt16()
switch
54 IMAGE_NT_OPTIONAL_HDR32_MAGIC => peSignatureOffset + 24 + (64 + 4 * 8) + 8 * 4,
55 IMAGE_NT_OPTIONAL_HDR64_MAGIC => peSignatureOffset + 24 + (64 + 4 * 8 + 16) + 8 * 4,
56 _ =>
throw new BadImageFormatException(),
59 stream.Seek(certificateTableDataDirectoryOffset, SeekOrigin.Begin);
60 var certificateTableOffset = br.ReadInt32();
61 var certificateTableLength = br.ReadInt32();
63 stream.Seek(certificateTableOffset, SeekOrigin.Begin);
64 var dwLength = br.ReadInt32();
65 var wRevision = br.ReadInt16();
66 var wCertificateType = br.ReadInt16();
67 if (wRevision != WIN_CERT_REVISION_2_0)
69 if (wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA)
72 var buf = br.ReadBytes(certificateTableLength - 8);
73 var cms =
new SignedCms();
77 cms.CheckSignature(
false);
79 catch (CryptographicException)
84 var signerInfo = cms.SignerInfos[0];
86 var offsets =
new int[] { checksumOffset, certificateTableDataDirectoryOffset, certificateTableOffset };
87 var lengths =
new int[] { 4, 8, certificateTableLength };
88 var actualHash = ComputeHashWithSkip(stream, signerInfo.DigestAlgorithm.FriendlyName, offsets, lengths);
89 var requiredHash = DecodeASN1(cms.ContentInfo.Content, 0, 1, 1);
91 if (requiredHash ==
null || actualHash.Length != requiredHash.Length)
94 for (
int i = 0; i < actualHash.Length; i++)
95 if (actualHash[i] != requiredHash[i])
98 return signerInfo.Certificate;
101 static byte[] ComputeHashWithSkip(Stream stream,
string hashAlgorithm,
int[] skipOffsets,
int[] skipLengths)
104 for (
int i = skipOffsets.Length - 1; i >= 0; i--)
108 using (HashAlgorithm hash = HashAlgorithm.Create(hashAlgorithm))
110 return hash.ComputeHash(stream);
114 static byte[] DecodeASN1(
byte[] buf, params
int[] indexes)
116 return DecodeASN1(buf, 0, buf.Length, 0, indexes);
119 static byte[] DecodeASN1(
byte[] buf,
int pos,
int end,
int depth,
int[] indexes)
121 for (var index = 0; pos < end; index++)
123 var tag = buf[pos++];
124 var length = (int)buf[pos++];
127 var lenlen = length & 0x7F;
129 for (var i = 0; i < lenlen; i++)
130 length = length * 256 + buf[pos++];
132 if (indexes[depth] == index)
134 if (depth == indexes.Length - 1)
136 var data =
new byte[length];
137 Buffer.BlockCopy(buf, pos, data, 0, length);
141 if ((tag & 0x20) == 0)
144 return DecodeASN1(buf, pos, pos + length, depth + 1, indexes);