|
05.09.2019, 08:54
#39857702
Ссылка:
Ссылка на сообщение:
Ссылка с названием темы:
|
|
|
|
Всем привет!
Встал вопрос! Как получить отпечаток (он же thumbprint) из хранилища сертификатов в винде? Набросал библиотеку для получения серийного номера из crypt32.dll, а куда дальше двигать не понятно. Подскажите как получить отпечаток?
Библиотека:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268.
unit CryptoWinUtils;
interface
uses
Windows, classes, SysUtils;
type
/////////////////////////////
// WinApi структуры
/////////////////////////////
CRYPTOAPI_BLOB = packed record
cbData: DWORD;
pbData: PByte;
end;
CRYPT_INTEGER_BLOB = CRYPTOAPI_BLOB;
CRYPT_OBJID_BLOB = CRYPTOAPI_BLOB;
CERT_NAME_BLOB = CRYPTOAPI_BLOB;
PCERT_NAME_BLOB = ^CERT_NAME_BLOB;
CRYPT_ALGORITHM_IDENTIFIER = packed record
pszObjId: LPSTR;
Parameters: CRYPT_OBJID_BLOB;
end;
CRYPT_BIT_BLOB = packed record
cbData: DWORD;
pbData: PBYTE;
cUnusedBits: DWORD;
end;
CERT_PUBLIC_KEY_INFO = packed record
Algorithm: CRYPT_ALGORITHM_IDENTIFIER;
PublicKey: CRYPT_BIT_BLOB;
end;
CERT_EXTENSION = packed record
pszObjId: LPSTR;
fCritical: BOOL;
Value: CRYPT_OBJID_BLOB;
end;
PCERT_EXTENSION = ^CERT_EXTENSION;
TARR_CERT_EXTENSION = PCERT_EXTENSION;
CERT_INFO = packed record
dwVersion: DWORD;
SerialNumber: CRYPT_INTEGER_BLOB;
SignatureAlgorithm: CRYPT_ALGORITHM_IDENTIFIER;
Issuer: CERT_NAME_BLOB;
NotBefore: FILETIME;
NotAfter: FILETIME;
Subject: CERT_NAME_BLOB;
SubjectPublicKeyInfo: CERT_PUBLIC_KEY_INFO;
IssuerUniqueId: CRYPT_BIT_BLOB;
SubjectUniqueId: CRYPT_BIT_BLOB;
cExtension: DWORD;
rgExtension: TARR_CERT_EXTENSION;
end;
PCERT_INFO = ^CERT_INFO;
HCERTSTORE = Pointer;
HCRYPTPROV = ULONG;
CERT_CONTEXT = packed record
dwCertEncodingType: DWORD;
pbCertEncoded: PBYTE;
cbCertEncoded: DWORD;
pCertInfo: PCERT_INFO;
hCertStore: HCERTSTORE;
end;
PCERT_CONTEXT = ^CERT_CONTEXT;
PCCERT_CONTEXT = ^CERT_CONTEXT;
/////////////////////////////
// Другие структуры
/////////////////////////////
TCertRow = record
SerialNumber: string;
// ...
end;
TCertRows = array of TCertRow;
const
X509_ASN_ENCODING = $00000001;
PKCS_7_ASN_ENCODING = $00010000;
CERT_SIMPLE_NAME_STR = 1; // All object identifiers (OIDs) are discarded. CERT_RDN entries are separated by a comma followed by a space (, ). Multiple attributes in a CERT_RDN are separated by a plus sign enclosed within spaces ( + ), for example, Firm, Qwe Asd + Zxc.
CERT_OID_NAME_STR = 2; // OIDs are included with an equal sign (=) separator from their attribute value. CERT_RDN entries are separated by a comma followed by a space (, ). Multiple attributes in a CERT_RDN are separated by a plus sign followed by a space (+ ).
CERT_X500_NAME_STR = 3; // OIDs are converted to their X.500 key names; otherwise, they are the same as CERT_OID_NAME_STR. If an OID does not have a corresponding X.500 name, the OID is used with a prefix of OID.
CERT_NAME_STR_SEMICOLON_FLAG = $40000000; // Replace the comma followed by a space (, ) separator with a semicolon followed by a space (; ) separator.
CERT_NAME_STR_CRLF_FLAG = $08000000; // Replace the comma followed by a space (, ) separator with a backslash followed by the letter r followed by a backslash followed by the letter n (\r\n) separator.
CERT_NAME_STR_NO_PLUS_FLAG = $20000000; // Replace the plus sign enclosed within spaces ( + ) separator with a single space separator.
CERT_NAME_STR_NO_QUOTING_FLAG = $10000000; // Disable quoting.
CERT_NAME_STR_REVERSE_FLAG = $02000000; // The order of the RDNs in the distinguished name string is reversed after decoding. This flag is not set by default.
CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG = $00010000; // By default, a CERT_RDN_T61_STRING X.500 key string is decoded as UTF8. If UTF8 decoding fails, the X.500 key is decoded as an 8 bit character. Use CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG to skip the initial attempt to decode as UTF8.
CERT_NAME_STR_ENABLE_PUNYCODE_FLAG = $00200000; // If the name pointed to by the pName parameter contains an email RDN, and the host name portion of the email address contains a Punycode encoded IA5String, the name is converted to the Unicode equivalent.
CERT_TYPE_INFO_SERIAL_NUMBER = 1;
/////////////////////////////
// WinApi функции
/////////////////////////////
function CertFreeCertificateContext(pCertContext:
PCCERT_CONTEXT): BOOL; stdcall external 'crypt32.dll';
function CertCreateCertificateContext(dwCertEncodingType: DWORD;
pbCertEncoded: PBYTE; cbCertEncoded: DWORD): PCCERT_CONTEXT; stdcall
external 'crypt32.dll';
function CertOpenSystemStoreA(hProv: HCRYPTPROV;
szSubsystemProtocol: LPCSTR): HCERTSTORE; stdcall
external 'crypt32.dll';
function CertCloseStore(hCertStore: HCERTSTORE;
dwFlags: DWORD = 0): BOOL; stdcall
external 'crypt32.dll';
function CertEnumCertificatesInStore(hCertStore: HCERTSTORE;
pPrevCertContext: PCCERT_CONTEXT): PCCERT_CONTEXT; stdcall
external 'crypt32.dll';
function CertNameToStrA(
dwCertEncodingType: DWORD;
pName: PCERT_NAME_BLOB;
dwStrType: DWORD;
psz: LPSTR;
csz: DWORD): DWORD; stdcall
external 'crypt32.dll';
function CertNameToStrW(
dwCertEncodingType: DWORD;
pName: PCERT_NAME_BLOB;
dwStrType: DWORD;
psz: LPWSTR;
csz: DWORD): DWORD; stdcall
external 'crypt32.dll';
/////////////////////////////
// Другие функции
/////////////////////////////
// ByteArrayToStr
function ByteArrayToStr(pbData: PByte; cbData: DWORD): string;
// Получить серийный номер сертификата
function CertGetSerialNumber(aCertInfo: PCCERT_CONTEXT): string;
// Получить список сертификатов из хранилища
function CertGetList(const aCertStoreName: string): TCertRows;
// Поиск сертификата
function CertFind(const aCertRows: TCertRows; const aCertData: string; const aCertTypeInfo: Integer): Integer;
implementation
// ByteArrayToStr
function ByteArrayToStr(pbData: PByte; cbData: DWORD): string;
var
I, J: Integer;
S: string;
begin
Result := '';
if not Assigned(pbData) or (cbData <= 0) then
Exit;
for I := 0 to cbData - 1 do
begin
J := PByteArray(pbData)^[i];
S := IntToHex(J, 2);
if (I > 0) and (I and 1 = 0) then
S := S + ' ';
Result := S + Result;
end;
end;
// Получить серийный номер сертификата
function CertGetSerialNumber(aCertInfo: PCCERT_CONTEXT): string;
begin
Result := ByteArrayToStr(
aCertInfo.pCertInfo.SerialNumber.pbData
, aCertInfo.pCertInfo.SerialNumber.cbData);
end;
// Получить список сертификатов из хранилища
function CertGetList(const aCertStoreName: string): TCertRows;
var
certStoreName: PChar;
hwndStore: HCERTSTORE;
cert: PCCERT_CONTEXT;
cryptoProvider: HCRYPTPROV;
id: Integer;
begin
// Преобразовываю имя хранилища
certStoreName := StrAlloc(length(aCertStoreName) + 1);
StrPCopy(certStoreName, aCertStoreName);
// Получаю доступ к хранилищу
hwndStore := CertOpenSystemStoreA(cryptoProvider, certStoreName);
// Фокус на первый сертификат
cert := CertEnumCertificatesInStore(hwndStore, nil);
// Инициализация переменных
SetLength(Result, 0);
// Перебор сертификатов
while cert <> nil do
begin
id := Length(Result);
SetLength(Result, id + 1);
// Серийный номер
Result[id].SerialNumber := CertGetSerialNumber(cert);
// Следующий сертификат
cert := CertEnumCertificatesInStore(hwndStore, cert);
end;
// Завершить работу с хранилищем
CertCloseStore(hwndStore);
end;
// Поиск сертификата
function CertFind(const aCertRows: TCertRows; const aCertData: string; const aCertTypeInfo: Integer): Integer;
var
i, len: Integer;
certData, certRowData: string;
begin
Result := -1;
len := Length(aCertRows);
// Форматирование поискового текста
case aCertTypeInfo of
// Серийный номер
CERT_TYPE_INFO_SERIAL_NUMBER:
certData := AnsiUpperCase(StringReplace(aCertData, ' ', '', [rfReplaceAll]));
end;
// Поиск текста
for i := 0 to len - 1 do
begin
// Форматирование переменной поиска из массива
case aCertTypeInfo of
// Серийный номер
CERT_TYPE_INFO_SERIAL_NUMBER:
certRowData := AnsiUpperCase(StringReplace(aCertRows[i].SerialNumber, ' ', '', [rfReplaceAll]));
else
Break;
end;
// Поиск
if certRowData = certData then
begin
Result := i;
Break;
end;
end;
end;
end.
Поиск сертификата по серийному номеру:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
procedure TForm1.Button1Click(Sender: TObject);
var
r: TCertRows;
i: integer;
begin
r := CertGetList('My');
i := CertFind(r, '01e3fbf60031a9579540ca4145db0c17yu', CERT_TYPE_INFO_SERIAL_NUMBER);
ShowMessage( IntToStr(i) );
end;
Модератор: Как мне оформить свое сообщение?
|
|
|