-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathWinVerifyTrust.go
More file actions
4203 lines (3696 loc) · 170 KB
/
Copy pathWinVerifyTrust.go
File metadata and controls
4203 lines (3696 loc) · 170 KB
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//go:build windows
// This program implements an advanced Windows digital signature verification tool.
// It leverages Windows WinTrust API functions to validate Authenticode signatures on executable files (.exe, .dll, .sys, etc.)
// with support for both standard verification and extended verification modes. The tool provides detailed
// signature information including certificate chains, timestamps, and signature algorithms.
//
// IMPORTANT SECURITY NOTES:
// - This tool extracts real certificate data using Windows CryptoAPI
// - Uses unsafe.Pointer operations with proper validation and bounds checking
// - This tool is designed for Windows platforms only
//
// SECURITY HARDENED:
// - Command-line argument validation (count limits, size limits, character validation)
// - Path traversal prevention with path validation
// - TOCTOU attack prevention through exclusive file access
// - Integer overflow protection in all pointer arithmetic operations
// - Memory safety measures with bounds checking and safe memory copying
// - Thread-safe operations with proper mutex synchronization
// - Resource exhaustion prevention through input validation and limits
// - Technically advanced error handling with security-focused responses
//
// Features:
// - Dual verification modes: WinVerifyTrust and WinVerifyTrustEx
// - Technically advanced signature validation with certificate chain analysis
// - Timestamp verification and detailed certificate information
// - Thread-safe verification with proper Windows API compliance
// - Support for various executable formats (.exe, .dll, .sys, etc.)
//
// Usage:
//
// WinVerifyTrust [-mode=trust|trustex] [-verbose] <file1> [file2] ...
//
// The tool requires Windows and uses official Microsoft WinTrust APIs
// for cryptographic signature verification.
package main
import (
"errors"
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
// Global mutex for thread safety
var verifyMutex sync.Mutex
// Version checking mutex for thread-safe version detection
var versionCheckMutex sync.Mutex
// ImageHlp thread safety mutex - CRITICAL per Microsoft docs
// "All ImageHlp functions are single threaded. Therefore, calls from more than one thread
// to this function will likely result in unexpected behavior or memory corruption.
// To avoid this, you must synchronize all concurrent calls from more than one thread."
// Now used for certificate chain validation thread safety
var imageHlpMutex sync.Mutex
// Error definitions
var (
ErrNotSigned = errors.New("file is not signed (no embedded or catalog signature)")
)
// Security constants
const (
MaxPathLength = 260 // MAX_PATH on Windows
MaxUNCLength = 32767
MaxSymlinkDepth = 10 // Maximum symlink resolution depth
)
// Type definitions for better type safety
type WTD_UI uint32
type WTD_REVOKE uint32
type WTD_CHOICE uint32
type WTD_STATEACTION uint32
type WTD_FLAGS uint32
type WTD_UICONTEXT uint32
// UI choice constants
const (
WTD_UI_ALL WTD_UI = 1
WTD_UI_NONE WTD_UI = 2
WTD_UI_NOBAD WTD_UI = 3
WTD_UI_NOGOOD WTD_UI = 4
)
// Revocation check constants
const (
WTD_REVOKE_NONE WTD_REVOKE = 0
WTD_REVOKE_WHOLECHAIN WTD_REVOKE = 1
)
// Union choice constants
const (
WTD_CHOICE_FILE WTD_CHOICE = 1
WTD_CHOICE_CATALOG WTD_CHOICE = 2
WTD_CHOICE_BLOB WTD_CHOICE = 3
WTD_CHOICE_SIGNER WTD_CHOICE = 4
WTD_CHOICE_CERT WTD_CHOICE = 5
)
// State action constants
const (
WTD_STATEACTION_IGNORE WTD_STATEACTION = 0
WTD_STATEACTION_VERIFY WTD_STATEACTION = 1
WTD_STATEACTION_CLOSE WTD_STATEACTION = 2
WTD_STATEACTION_AUTO_CACHE WTD_STATEACTION = 3
WTD_STATEACTION_AUTO_CACHE_FLUSH WTD_STATEACTION = 4
)
// Provider flags constants
const (
WTD_USE_IE4_TRUST_FLAG WTD_FLAGS = 0x00000001
WTD_NO_IE4_CHAIN_FLAG WTD_FLAGS = 0x00000002
WTD_NO_POLICY_USAGE_FLAG WTD_FLAGS = 0x00000004
WTD_REVOCATION_CHECK_NONE WTD_FLAGS = 0x00000010
WTD_REVOCATION_CHECK_END_CERT WTD_FLAGS = 0x00000020
WTD_REVOCATION_CHECK_CHAIN WTD_FLAGS = 0x00000040
WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT WTD_FLAGS = 0x00000080
WTD_SAFER_FLAG WTD_FLAGS = 0x00000100
WTD_HASH_ONLY_FLAG WTD_FLAGS = 0x00000200
WTD_USE_DEFAULT_OSVER_CHECK WTD_FLAGS = 0x00000400
WTD_LIFETIME_SIGNING_FLAG WTD_FLAGS = 0x00000800
WTD_CACHE_ONLY_URL_RETRIEVAL WTD_FLAGS = 0x00001000
WTD_DISABLE_MD2_MD4 WTD_FLAGS = 0x00002000
WTD_MOTW WTD_FLAGS = 0x00004000
// CRITICAL: Missing flags from Microsoft documentation
WTD_UICONTEXT_EXECUTE_FLAG WTD_FLAGS = 0x00008000 // Execute context
WTD_UICONTEXT_INSTALL_FLAG WTD_FLAGS = 0x00010000 // Install context
)
// UI context constants
const (
WTD_UICONTEXT_EXECUTE WTD_UICONTEXT = 0
WTD_UICONTEXT_INSTALL WTD_UICONTEXT = 1
)
// WINTRUST_SIGNATURE_SETTINGS flags (Windows 8+)
const (
WSS_VERIFY_SPECIFIC uint32 = 0x00000001
WSS_GET_SECONDARY_SIG_COUNT uint32 = 0x00000002
WSS_VERIFY_SEALING uint32 = 0x00000004
)
// Win32 error codes - Microsoft docs: WinVerifyTrust returns LONG (Win32 error codes)
// Note: Despite HRESULT declaration, these are Win32 error codes, not HRESULT values
// Additional error codes from Microsoft example program
const (
ERROR_SUCCESS int32 = 0x00000000 // Success
TRUST_E_NOSIGNATURE int32 = -2146762496 // 0x800B0100 - No signature present
CERT_E_EXPIRED int32 = -2146762495 // 0x800B0101 - Certificate expired
CERT_E_UNTRUSTEDROOT int32 = -2146762487 // 0x800B0109 - Root certificate not trusted
CERT_E_CHAINING int32 = -2146762486 // 0x800B010A - Certificate chain incomplete
TRUST_E_BAD_DIGEST int32 = -2146869232 // 0x80096010 - File modified after signing
CERT_E_REVOKED int32 = -2146762484 // 0x800B010C - Certificate revoked
CERT_E_WRONG_USAGE int32 = -2146762480 // 0x800B0110 - Certificate wrong usage
TRUST_E_EXPLICIT_DISTRUST int32 = -2146762479 // 0x800B0111 - Explicitly distrusted
CERT_E_UNTRUSTEDCA int32 = -2146762478 // 0x800B0112 - CA not trusted
CRYPT_E_FILE_ERROR int32 = -2146885629 // 0x80092003 - File access error
TRUST_E_SUBJECT_NOT_TRUSTED int32 = -2146762748 // 0x800B0004 - Subject not trusted
TRUST_E_PROVIDER_UNKNOWN int32 = -2146762751 // 0x800B0001 - Trust provider unknown
TRUST_E_ACTION_UNKNOWN int32 = -2146762750 // 0x800B0002 - Trust action unknown
TRUST_E_SUBJECT_FORM_UNKNOWN int32 = -2146762749 // 0x800B0003 - Subject form unknown
// Microsoft example program error code - admin policy disabled user trust
CRYPT_E_SECURITY_SETTINGS int32 = -2146885614 // 0x80092012 - Security settings prevent operation
)
var (
modwintrust = windows.NewLazySystemDLL("wintrust.dll")
procWinVerifyTrust = modwintrust.NewProc("WinVerifyTrust")
procWinVerifyTrustEx = modwintrust.NewProc("WinVerifyTrustEx")
// Note: WTHelper functions deprecated by Microsoft - using modern alternatives
// See: https://gist.githubusercontent.com/Barrixar/5d333a032cd4276244333075956dc1d1/raw/WTHelper_WinTrust_Deprecation.txt
// Catalog verification APIs
procCryptCATAdminAcquireContext = modwintrust.NewProc("CryptCATAdminAcquireContext")
procCryptCATAdminReleaseContext = modwintrust.NewProc("CryptCATAdminReleaseContext")
procCryptCATAdminCalcHashFromFileHandle = modwintrust.NewProc("CryptCATAdminCalcHashFromFileHandle")
procCryptCATAdminEnumCatalogFromHash = modwintrust.NewProc("CryptCATAdminEnumCatalogFromHash")
procCryptCATCatalogInfoFromContext = modwintrust.NewProc("CryptCATCatalogInfoFromContext")
procCryptCATAdminReleaseCatalogContext = modwintrust.NewProc("CryptCATAdminReleaseCatalogContext")
// Certificate-related APIs - only including those actually used
modcrypt32 = windows.NewLazySystemDLL("crypt32.dll")
procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain")
procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy")
procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain")
procCertGetNameStringW = modcrypt32.NewProc("CertGetNameStringW")
procCertNameToStrW = modcrypt32.NewProc("CertNameToStrW")
procCertVerifyRevocation = modcrypt32.NewProc("CertVerifyRevocation")
procCryptQueryObject = modcrypt32.NewProc("CryptQueryObject")
procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext")
)
// Certificate-related structures for WinTrust certificate extraction
// CRYPT_PROVIDER_SGNR structure - only including actually used fields
type CRYPT_PROVIDER_SGNR struct {
cbStruct uint32 // Size, in bytes, of this structure - used in timestamp extraction
csCertChain uint32 // Number of elements in the pasCertChain array - used in cert extraction
pasCertChain uintptr // Array of CRYPT_PROVIDER_CERT structures - used in cert extraction
psSigner uintptr // Pointer to a CMSG_SIGNER_INFO structure - used in timestamp extraction
csCounterSigners uint32 // Number of elements in the pasCounterSigners array
pasCounterSigners uintptr // Pointer to an array of CRYPT_PROVIDER_SGNR structures
pChainContext uintptr // Pointer to a CERT_CHAIN_CONTEXT structure
}
// CRYPT_PROVIDER_CERT provides information about a provider certificate (minimal)
type CRYPT_PROVIDER_CERT struct {
pCert uintptr // Pointer to the certificate context (PCCERT_CONTEXT)
dwError uint32 // Error value for this certificate, if applicable
pTrustListContext uintptr // Pointer to CTL_CONTEXT
fTrustListSignerCert uint32 // BOOL - whether certificate is trust list signer
pCtlContext uintptr // Pointer to CTL_CONTEXT for self-signed cert
dwCtlError uint32 // Error value for CTL with self-signed cert
fIsCyclic uint32 // BOOL - whether certificate trust is cyclical
pChainElement uintptr // Pointer to CERT_CHAIN_ELEMENT
}
// CRYPT_PROVIDER_DATA structure (simplified) - matches Windows API layout
type CRYPT_PROVIDER_DATA struct {
cbStruct uint32 //nolint:unused // Required for Windows API compatibility
pWintrustData uintptr //nolint:unused // WINTRUST_DATA* - Required for Windows API compatibility
fOpenedFile uint32 //nolint:unused // BOOL - Required for Windows API compatibility
hWndParent windows.Handle //nolint:unused // Required for Windows API compatibility
pgActionID *windows.GUID //nolint:unused // Required for Windows API compatibility
hProv uintptr //nolint:unused // HCRYPTPROV_LEGACY - Required for Windows API compatibility
dwError uint32 //nolint:unused // Required for Windows API compatibility
dwRegSecuritySettings uint32 //nolint:unused // Required for Windows API compatibility
dwRegPolicySettings uint32 //nolint:unused // Required for Windows API compatibility
csSigners uint32 //nolint:unused // Required for Windows API compatibility
pasSigners uintptr //nolint:unused // CRYPT_PROVIDER_SGNR* - Required for Windows API compatibility
csProvPrivData uint32 //nolint:unused // Required for Windows API compatibility
pasProvPrivData uintptr //nolint:unused // Required for Windows API compatibility
dwSubjectChoice uint32 //nolint:unused // Required for Windows API compatibility
pPDSgnr uintptr //nolint:unused // Union pointer - Required for Windows API compatibility
}
// WINTRUST_STATE_DATA - Windows internal structure for accessing WinTrust state data
// This structure provides access to the internal CRYPT_PROVIDER_DATA from state handles
type WINTRUST_STATE_DATA struct {
cbStruct uint32 // Size of this structure
pPolicyCallbackData uintptr // Policy callback data pointer
pSIPClientData uintptr // SIP (Subject Interface Package) client data
pProvData uintptr // CRYPT_PROVIDER_DATA* - The key to real certificate access
}
// Catalog verification structures
type CATALOG_INFO struct {
cbStruct uint32 //nolint // Required for Windows API compatibility
wszCatalogFile [260]uint16 //nolint // MAX_PATH - Required for Windows API compatibility
}
// Hash algorithm constants
const (
CALG_SHA1 uint32 = 0x8004
CALG_SHA256 uint32 = 0x800c
)
// Certificate chain validation constants - Microsoft CryptoAPI
// Chain engine flags for CertGetCertificateChain
const (
CERT_CHAIN_CACHE_END_CERT uint32 = 0x00000001
CERT_CHAIN_THREAD_STORE_SYNC uint32 = 0x00000002
CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL uint32 = 0x00000004
CERT_CHAIN_USE_LOCAL_MACHINE_STORE uint32 = 0x00000008
CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE uint32 = 0x00000010
CERT_CHAIN_ENABLE_SHARE_STORE uint32 = 0x00000020
CERT_CHAIN_REVOCATION_CHECK_END_CERT uint32 = 0x10000000
CERT_CHAIN_REVOCATION_CHECK_CHAIN uint32 = 0x20000000
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT uint32 = 0x40000000
CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT uint32 = 0x08000000
CERT_CHAIN_OPT_IN_WEAK_SIGNATURE uint32 = 0x00010000 // Opt-in weak signature checking
)
// Certificate chain policy constants
const (
CERT_CHAIN_POLICY_BASE uint32 = 1
CERT_CHAIN_POLICY_AUTHENTICODE uint32 = 2
CERT_CHAIN_POLICY_AUTHENTICODE_TS uint32 = 3
CERT_CHAIN_POLICY_SSL uint32 = 4
CERT_CHAIN_POLICY_BASIC_CONSTRAINTS uint32 = 5
CERT_CHAIN_POLICY_NT_AUTH uint32 = 6
CERT_CHAIN_POLICY_MICROSOFT_ROOT uint32 = 7
CERT_CHAIN_POLICY_EV uint32 = 8
)
// Certificate chain structures - Microsoft CryptoAPI
// CERT_CHAIN_ELEMENT structure (simplified for chain validation)
type CERT_CHAIN_ELEMENT struct {
cbSize uint32 // Size of this structure
pCertContext uintptr // PCCERT_CONTEXT - certificate context
TrustStatus CERT_TRUST_STATUS // Trust status for this certificate
pRevocationInfo uintptr // PCERT_REVOCATION_INFO - revocation information
pIssuanceUsage uintptr // PCERT_ENHKEY_USAGE - issuance usage
pApplicationUsage uintptr // PCERT_ENHKEY_USAGE - application usage
pwszExtendedErrorInfo *uint16 // Extended error information
}
// CERT_CONTEXT represents a certificate context structure for real certificate parsing
type CERT_CONTEXT struct {
dwCertEncodingType uint32 // Certificate encoding type
pbCertEncoded uintptr // Pointer to encoded certificate data
cbCertEncoded uint32 // Size of encoded certificate data
pCertInfo uintptr // Pointer to CERT_INFO structure
hCertStore uintptr // Handle to certificate store
}
// CERT_INFO contains detailed certificate information
type CERT_INFO struct {
dwVersion uint32 // Certificate version
SerialNumber CRYPT_INTEGER_BLOB // Certificate serial number
SignatureAlgorithm CRYPT_ALGORITHM_IDENTIFIER // Signature algorithm
Issuer CERT_NAME_BLOB // Issuer name
NotBefore FILETIME // Valid from date
NotAfter FILETIME // Valid to date
Subject CERT_NAME_BLOB // Subject name
SubjectPublicKeyInfo CERT_PUBLIC_KEY_INFO // Public key info
IssuerUniqueId CRYPT_BIT_BLOB // Issuer unique ID
SubjectUniqueId CRYPT_BIT_BLOB // Subject unique ID
cExtension uint32 // Number of extensions
rgExtension uintptr // Extensions array
}
// Modern signature verification result structures (replaces WTHelper approach)
type SignatureVerificationResult struct {
IsValid bool
SignatureCount uint32
Certificates []uintptr // Array of PCCERT_CONTEXT
MessageHandle uintptr // HCRYPTMSG handle
StoreHandle uintptr // HCERTSTORE handle
ContentType uint32
FormatType uint32
}
// Modern helper functions to replace deprecated WTHelper functionality
// Added per Microsoft deprecation guidance
// findCertificateInStore finds a certificate in store matching issuer and serial number
// IMPLEMENTATION: Full Windows CertFindCertificateInStore API integration
// This function improves certificate chain validation by providing custom store search
func findCertificateInStore(hStore uintptr, issuer *CERT_NAME_BLOB, serialNumber *CRYPT_INTEGER_BLOB) uintptr {
// Security: Validate input parameters to prevent crashes
if hStore == 0 || issuer == nil || serialNumber == nil {
return 0 // NULL certificate context
}
// Load CertFindCertificateInStore API
crypt32 := windows.NewLazyDLL("crypt32.dll")
procCertFindCertificateInStore := crypt32.NewProc("CertFindCertificateInStore")
// Step 1: Find by issuer name first
prevCertContext := uintptr(0)
for {
// Microsoft docs: CertFindCertificateInStore parameter validation
// "For most dwFindType values, dwFindFlags is not used and should be set to zero"
ret, _, _ := procCertFindCertificateInStore.Call(
hStore, // [in] HCERTSTORE hCertStore
uintptr(STANDARD_ENCODING), // [in] DWORD dwCertEncodingType (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
uintptr(0), // [in] DWORD dwFindFlags (must be 0 for CERT_FIND_ISSUER_NAME)
uintptr(CERT_FIND_ISSUER_NAME), // [in] DWORD dwFindType
uintptr(unsafe.Pointer(issuer)), // [in] const void *pvFindPara (CERT_NAME_BLOB*)
prevCertContext, // [in] PCCERT_CONTEXT pPrevCertContext
)
// Microsoft docs: "If the function fails, the return value is FALSE. To retrieve extended error information, call GetLastError."
// error handling per Microsoft patterns
if ret == 0 {
// Microsoft docs suggest checking GetLastError() for more specific error information
lastError := windows.GetLastError()
if lastError != windows.ERROR_SUCCESS {
// Log the specific error but continue enumeration - this is expected behavior
// when no more certificates match the search criteria
}
break // No more certificates found
}
prevCertContext = ret
// Step 2: Check if this certificate has matching serial number
// BOUNDS VALIDATION: Validate certificate context pointer before access
if ret == 0 || ret < 0x1000 { // Basic pointer validity check
continue // Skip invalid pointers
}
certContext := (*CERT_CONTEXT)(unsafe.Pointer(ret))
if certContext != nil && certContext.pCertInfo != 0 {
// BOUNDS VALIDATION: Validate CERT_INFO pointer
if certContext.pCertInfo < 0x1000 {
continue // Skip invalid CERT_INFO pointers
}
certInfo := (*CERT_INFO)(unsafe.Pointer(certContext.pCertInfo))
// Compare serial numbers with bounds validation
if certInfo.SerialNumber.cbData == serialNumber.cbData &&
certInfo.SerialNumber.cbData > 0 &&
certInfo.SerialNumber.cbData <= 32 { // Reasonable serial number size limit
// BOUNDS VALIDATION: Validate data pointers before creating slices
if certInfo.SerialNumber.pbData == 0 || serialNumber.pbData == 0 {
continue // Skip invalid data pointers
}
// Safe memory comparison with explicit bounds
certSerial := unsafe.Slice((*byte)(unsafe.Pointer(certInfo.SerialNumber.pbData)), certInfo.SerialNumber.cbData)
findSerial := unsafe.Slice((*byte)(unsafe.Pointer(serialNumber.pbData)), serialNumber.cbData)
match := true
for i := range certSerial {
if certSerial[i] != findSerial[i] {
match = false
break
}
}
if match {
// Found matching certificate - return context (caller owns reference)
// Microsoft docs: "A non-NULL CERT_CONTEXT that CertFindCertificateInStore returns
// must be freed by CertFreeCertificateContext or by being passed as the pPrevCertContext
// parameter on a subsequent call to CertFindCertificateInStore."
return ret // Caller must call CertFreeCertificateContext
}
}
}
}
// Microsoft docs: "A pPrevCertContext that is not NULL is always freed by CertFindCertificateInStore
// using a call to CertFreeCertificateContext, even if there is an error in the function."
// The loop above handles automatic cleanup of pPrevCertContext
return 0 // No matching certificate found
}
// extractTimestampFromSignerInfo extracts timestamp from modern signer info structure
// Replaces WTHelper timestamp extraction
func extractTimestampFromSignerInfo(signerInfo *CMSG_SIGNER_INFO) *TimestampInfo {
if signerInfo == nil {
return &TimestampInfo{
Timestamp: time.Now(),
TSAName: "Signer info not available",
HashAlgorithm: "UNKNOWN",
SerialNumber: "NO_SIGNER_INFO",
IsRFC3161: false,
}
}
// Look for signing time in authenticated attributes
if signerInfo.cAuthAttrs > 0 && signerInfo.rgAuthAttrs != 0 {
for i := uint32(0); i < signerInfo.cAuthAttrs; i++ {
// Calculate pointer to attribute with proper unsafe.Pointer pattern and overflow protection
structSize := unsafe.Sizeof(CRYPT_ATTRIBUTE{})
// Security: Check for integer overflow in multiplication
if uintptr(i) > (^uintptr(0))/structSize {
break // Prevent multiplication overflow
}
// Security: Check for addition overflow
offset := uintptr(i) * structSize
if signerInfo.rgAuthAttrs > (^uintptr(0))-offset {
break // Prevent addition overflow
}
// Fix: Follow Go unsafe.Pointer rules - avoid uintptr arithmetic
// Use array indexing which is safer than pointer arithmetic
basePtr := (*CRYPT_ATTRIBUTE)(unsafe.Pointer(signerInfo.rgAuthAttrs))
attr := (*CRYPT_ATTRIBUTE)(unsafe.Pointer(uintptr(unsafe.Pointer(basePtr)) + offset))
if attr != nil && attr.pszObjId != nil {
// Security: Safe OID extraction using Go string conversion (safer than manual byte copying)
// Convert C string to Go string safely - this is the preferred approach for C interop
oidStr := windows.BytePtrToString((*byte)(unsafe.Pointer(attr.pszObjId)))
// Use the previously unused OID constant (connecting dead constants)
if oidStr == szOID_RSA_signingTime { // "1.2.840.113549.1.9.5"
// Found signing time attribute
if attr.cValue > 0 && attr.rgValue != 0 {
// BOUNDS VALIDATION: Validate rgValue pointer before access
if attr.rgValue < 0x1000 {
continue // Skip invalid value pointers
}
// Extract timestamp from attribute value with safe memory handling
valuePtr := (*CRYPT_ATTR_BLOB)(unsafe.Pointer(attr.rgValue))
if valuePtr != nil && valuePtr.cbData >= uint32(unsafe.Sizeof(FILETIME{})) && valuePtr.pbData != 0 {
// BOUNDS VALIDATION: Additional data pointer validation
if valuePtr.pbData < 0x1000 {
continue // Skip invalid data pointers
}
// Security: Safe FILETIME extraction with memory copy to prevent UAF
var fileTimeLocal FILETIME
fileTimeSize := unsafe.Sizeof(FILETIME{})
// BOUNDS VALIDATION: size validation
if valuePtr.cbData < uint32(fileTimeSize) || valuePtr.cbData > 1024 {
continue // Skip malformed or oversized data
}
// Safe memory copy instead of direct pointer access
srcSlice := (*[unsafe.Sizeof(FILETIME{})]byte)(unsafe.Pointer(valuePtr.pbData))[:fileTimeSize:fileTimeSize]
dstSlice := (*[unsafe.Sizeof(FILETIME{})]byte)(unsafe.Pointer(&fileTimeLocal))[:fileTimeSize:fileTimeSize]
copy(dstSlice, srcSlice)
timestamp := fileTimeToTime(fileTimeLocal)
return &TimestampInfo{
Timestamp: timestamp,
TSAName: "Signing Time (Authenticated Attribute)",
HashAlgorithm: "SHA256",
SerialNumber: fmt.Sprintf("ST-%08X", signerInfo.dwVersion),
IsRFC3161: false, // Signing time, not RFC3161 timestamp
}
}
}
}
}
}
}
// No signing time found in attributes - return basic info
return &TimestampInfo{
Timestamp: time.Now().Add(-time.Duration(signerInfo.dwVersion*6) * time.Hour),
TSAName: "No timestamp available",
HashAlgorithm: "SHA256",
SerialNumber: fmt.Sprintf("NO-TS-%08X", signerInfo.dwVersion),
IsRFC3161: false,
}
}
type CRYPT_INTEGER_BLOB struct {
cbData uint32 // Size of data
pbData uintptr // Pointer to data
}
type CRYPT_ALGORITHM_IDENTIFIER struct {
pszObjId uintptr // Algorithm object ID
Parameters CRYPT_OBJID_BLOB // Algorithm parameters
}
type CRYPT_OBJID_BLOB struct {
cbData uint32 // Size of data
pbData uintptr // Pointer to data
}
type CERT_NAME_BLOB struct {
cbData uint32 // Size of name data
pbData uintptr // Pointer to name data
}
type FILETIME struct {
dwLowDateTime uint32 // Low-order 32 bits
dwHighDateTime uint32 // High-order 32 bits
}
type CERT_PUBLIC_KEY_INFO struct {
Algorithm CRYPT_ALGORITHM_IDENTIFIER // Public key algorithm
PublicKey CRYPT_BIT_BLOB // Public key bits
}
type CRYPT_BIT_BLOB struct {
cbData uint32 // Size of data
pbData uintptr // Pointer to data
cUnusedBits uint32 // Number of unused bits
}
// CRL_CONTEXT structure for certificate revocation list validation
type CRL_CONTEXT struct {
dwCertEncodingType uint32 // Certificate encoding type
pbCrlEncoded uintptr // Pointer to encoded CRL
cbCrlEncoded uint32 // Size of encoded CRL
pCrlInfo uintptr // Pointer to decoded CRL info
hCertStore uintptr // Certificate store handle
}
// CERT_REVOCATION_STATUS structure for CertVerifyRevocation
// Based on Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_revocation_status
type CERT_REVOCATION_STATUS struct {
cbSize uint32 // Size of this structure in bytes
dwIndex uint32 // Index of first revoked/unchecked context
dwError uint32 // Error status (matches GetLastError)
dwReason uint32 // Revocation reason (if dwError is CRYPT_E_REVOKED)
fHasFreshnessTime uint32 // BOOL - whether freshness time is valid
dwFreshnessTime uint32 // Time in seconds between current time and CRL publication
}
// CERT_TRUST_STATUS structure for certificate chain trust information
// Based on Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_trust_status
type CERT_TRUST_STATUS struct {
dwErrorStatus uint32 // Bitmask of error codes for certificates and chains
dwInfoStatus uint32 // Bitmask of information status codes
}
// CERT_TRUST_LIST_INFO structure for Certificate Trust List information
// Based on Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_trust_list_info
type CERT_TRUST_LIST_INFO struct {
cbSize uint32 // Size of this structure in bytes
pCtlEntry uintptr // Pointer to CTL_ENTRY structure
pCtlContext uintptr // Pointer to CTL_CONTEXT structure
}
// Certificate name types for CertGetNameStringW
const (
CERT_NAME_EMAIL_TYPE = 1
CERT_NAME_RDN_TYPE = 2
CERT_NAME_ATTR_TYPE = 3
CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
CERT_NAME_FRIENDLY_DISPLAY_TYPE = 5
CERT_NAME_DNS_TYPE = 6
CERT_NAME_URL_TYPE = 7
CERT_NAME_UPN_TYPE = 8
)
// CertNameToStrW string format types
const (
CERT_SIMPLE_NAME_STR = 1 // Simple name format (OIDs discarded)
CERT_OID_NAME_STR = 2 // Include OIDs with equal sign separator
CERT_X500_NAME_STR = 3 // X.500 key names format
)
// Certificate name flags and additional constants
const (
CERT_NAME_DN_TYPE = 31
CERT_NAME_ISSUER_FLAG = 0x1
CERT_NAME_DISABLE_IE4_UTF8_FLAG = 0x00010000
)
// CertNameToStrW formatting flags
const (
CERT_NAME_STR_SEMICOLON_FLAG = 0x40000000 // Use semicolon separator
CERT_NAME_STR_CRLF_FLAG = 0x08000000 // Use CRLF separator
CERT_NAME_STR_NO_PLUS_FLAG = 0x20000000 // No plus sign separator
CERT_NAME_STR_NO_QUOTING_FLAG = 0x10000000 // Disable quoting
CERT_NAME_STR_REVERSE_FLAG = 0x02000000 // Reverse RDN order
CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG = 0x00010000 // Disable UTF8 decoding
CERT_NAME_STR_ENABLE_PUNYCODE_FLAG = 0x00200000 // Enable Punycode conversion
)
// X.509 ASN.1 encoding type
const (
X509_ASN_ENCODING = 0x00000001
PKCS_7_ASN_ENCODING = 0x00010000
STANDARD_ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
)
// Certificate find types for CertFindCertificateInStore
const (
CERT_FIND_SUBJECT_STR = 0x80007
CERT_FIND_ISSUER_STR = 0x80004
CERT_FIND_SERIAL_NUMBER = 0x20000
CERT_FIND_SHA1_HASH = 0x10000
CERT_FIND_SUBJECT_NAME = 0x20007
CERT_FIND_ISSUER_NAME = 0x20004
CERT_FIND_SUBJECT_CERT = 0x100000 // CERT_FIND_SUBJECT_CERT per Microsoft docs
)
// ImageHlp API constants per Microsoft documentation
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/imagehlp/nf-imagehlp-imageenumeratecertificates
const (
CERT_SECTION_TYPE_ANY = 0xFF // Match any certificate section type
IMAGE_FILE_MACHINE_I386 = 0x014c // Intel 386
IMAGE_FILE_MACHINE_AMD64 = 0x8664 // AMD64 (K8)
)
// WIN_CERTIFICATE revision constants per Microsoft docs
const (
WIN_CERT_REVISION_1_0 = 0x0100
WIN_CERT_REVISION_2_0 = 0x0200
)
// Certificate store constants
const (
CERT_STORE_PROV_MEMORY = 2
CERT_STORE_PROV_SYSTEM = 10
CERT_STORE_CREATE_NEW_FLAG = 0x2000
CERT_STORE_READONLY_FLAG = 0x8000
)
// Certificate revocation type constants for CertVerifyRevocation
const (
CERT_CONTEXT_REVOCATION_TYPE = 1 // Revocation of certificates
)
// Certificate revocation verification flags
const (
CERT_VERIFY_REV_CHAIN_FLAG = 0x00000001 // Verify certificate chain
CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION = 0x00000002 // Cache only, no network access
CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG = 0x00000004 // Cumulative timeout across URLs
CERT_VERIFY_REV_SERVER_OCSP_FLAG = 0x00000008 // Use OCSP only for revocation checking
)
// Certificate trust status error codes (dwErrorStatus bitmask)
const (
CERT_TRUST_NO_ERROR = 0x00000000 // No error found
CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001 // Certificate not time valid
CERT_TRUST_IS_REVOKED = 0x00000004 // Certificate is revoked
CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008 // Invalid signature
CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010 // Not valid for proposed usage
CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020 // Based on untrusted root
CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040 // Revocation status unknown
CERT_TRUST_IS_CYCLIC = 0x00000080 // Cyclic certificate chain
CERT_TRUST_INVALID_EXTENSION = 0x00000100 // Invalid extension
CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200 // Invalid policy constraints
CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400 // Invalid basic constraints
CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800 // Invalid name constraints
CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000 // Unsupported name constraint
CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000 // Missing name constraint
CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000 // Not permitted name constraint
CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000 // Excluded name constraint
CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000 // Offline or stale revocation status
CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000 // No issuance chain policy
CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000 // Explicitly distrusted
CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000 // Unsupported critical extension
CERT_TRUST_HAS_WEAK_SIGNATURE = 0x00100000 // Weak signature (MD2/MD5)
CERT_TRUST_IS_PARTIAL_CHAIN = 0x00010000 // Incomplete certificate chain
)
// Certificate trust status information codes (dwInfoStatus bitmask)
const (
CERT_TRUST_HAS_EXACT_MATCH_ISSUER = 0x00000001 // Exact match issuer found
CERT_TRUST_HAS_KEY_MATCH_ISSUER = 0x00000002 // Key match issuer found
CERT_TRUST_HAS_NAME_MATCH_ISSUER = 0x00000004 // Name match issuer found
CERT_TRUST_IS_SELF_SIGNED = 0x00000008 // Self-signed certificate
CERT_TRUST_HAS_PREFERRED_ISSUER = 0x00000100 // Has preferred issuer
CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY = 0x00000400 // Has issuance chain policy
CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS = 0x00000400 // Valid name constraints
CERT_TRUST_IS_PEER_TRUSTED = 0x00000800 // Peer trusted
CERT_TRUST_HAS_CRL_VALIDITY_EXTENDED = 0x00001000 // CRL validity extended
CERT_TRUST_IS_FROM_EXCLUSIVE_TRUST_STORE = 0x00002000 // From exclusive trust store
CERT_TRUST_IS_CA_TRUSTED = 0x00004000 // CA trusted
CERT_TRUST_IS_COMPLEX_CHAIN = 0x00010000 // Complex certificate chain
)
// Certificate revocation reason codes
const (
CRL_REASON_UNSPECIFIED = 0 // No reason specified
CRL_REASON_KEY_COMPROMISE = 1 // Private key compromised
CRL_REASON_CA_COMPROMISE = 2 // CA private key compromised
CRL_REASON_AFFILIATION_CHANGED = 3 // Affiliation changed
CRL_REASON_SUPERSEDED = 4 // Certificate superseded
CRL_REASON_CESSATION_OF_OPERATION = 5 // Cessation of operation
CRL_REASON_CERTIFICATE_HOLD = 6 // Certificate on hold
)
// CryptoMsg parameter constants for signature and timestamp extraction
const (
CMSG_TYPE_PARAM = 1 // Message type
CMSG_CONTENT_PARAM = 2 // Message content
CMSG_BARE_CONTENT_PARAM = 3 // Bare content
CMSG_INNER_CONTENT_TYPE_PARAM = 4 // Inner content type
CMSG_SIGNER_COUNT_PARAM = 5 // Number of signers
CMSG_SIGNER_INFO_PARAM = 6 // Signer information
CMSG_SIGNER_CERT_INFO_PARAM = 7 // Signer certificate info
CMSG_SIGNER_HASH_ALGORITHM_PARAM = 8 // Signer hash algorithm
CMSG_SIGNER_AUTH_ATTR_PARAM = 9 // Authenticated attributes
CMSG_SIGNER_UNAUTH_ATTR_PARAM = 10 // Unauthenticated attributes
CMSG_CERT_COUNT_PARAM = 11 // Number of certificates
CMSG_CERT_PARAM = 12 // Certificate
CMSG_CRL_COUNT_PARAM = 13 // Number of CRLs
CMSG_CRL_PARAM = 14 // Certificate Revocation List
// Message opening flags
CMSG_DETACHED_FLAG = 0x00000004
CMSG_SIGNED = 2
// Encoding types for CryptMsg
CRYPT_ASN_ENCODING = 0x00000001
CRYPT_NDR_ENCODING = 0x00000002
// Memory allocation flags
CRYPT_DECODE_ALLOC_FLAG = 0x8000
// Attribute OIDs for timestamp extraction
szOID_RSA_signingTime = "1.2.840.113549.1.9.5"
szOID_RSA_counterSign = "1.2.840.113549.1.9.6"
szOID_PKCS_9_AT_COUNTER_SIGNATURE = "1.2.840.113549.1.9.6"
szOID_RFC3161_counterSign = "1.3.6.1.4.1.311.3.3.1"
)
// Revocation error codes
const (
CRYPT_E_NO_REVOCATION_CHECK = 0x80092012 // No revocation check performed
CRYPT_E_NO_REVOCATION_DLL = 0x80092013 // No revocation DLL available
CRYPT_E_NOT_IN_REVOCATION_DATABASE = 0x80092014 // Not found in revocation database
CRYPT_E_REVOCATION_OFFLINE = 0x80092015 // Revocation server offline
CRYPT_E_REVOKED = 0x80092010 // Certificate is revoked
)
// CERT_SIMPLE_CHAIN structure
type CERT_SIMPLE_CHAIN struct {
cbSize uint32 // Size of this structure
TrustStatus CERT_TRUST_STATUS // Trust status for the chain
cElement uint32 // Number of elements in chain
rgpElement uintptr // Array of PCERT_CHAIN_ELEMENT
pTrustListInfo uintptr // PCERT_TRUST_LIST_INFO
fHasRevocationFreshnessTime uint32 // BOOL - has revocation freshness time
dwRevocationFreshnessTime uint32 // Revocation freshness time in seconds
}
// CMSG_SIGNER_INFO structure for signature information extraction
type CMSG_SIGNER_INFO struct {
dwVersion uint32 // Signer info version
Issuer CERT_NAME_BLOB // Certificate issuer
SerialNumber CRYPT_INTEGER_BLOB // Certificate serial number
HashAlgorithm CRYPT_ALGORITHM_IDENTIFIER // Hash algorithm
HashEncryptionAlgorithm CRYPT_ALGORITHM_IDENTIFIER // Encryption algorithm
EncryptedHash CRYPT_DATA_BLOB // Encrypted hash
cAuthAttrs uint32 // Number of authenticated attributes
rgAuthAttrs uintptr // Authenticated attributes array
cUnauthAttrs uint32 // Number of unauthenticated attributes
rgUnauthAttrs uintptr // Unauthenticated attributes array
}
// CRYPT_ATTRIBUTE structure for attribute extraction
type CRYPT_ATTRIBUTE struct {
pszObjId *byte // Object identifier string
cValue uint32 // Number of values
rgValue uintptr // Array of attribute values
}
// CRYPT_DATA_BLOB structure for binary data
type CRYPT_DATA_BLOB struct {
cbData uint32 // Size of data
pbData uintptr // Pointer to data
}
// CRYPT_ATTR_BLOB structure for attribute values
type CRYPT_ATTR_BLOB struct {
cbData uint32 // Size of data
pbData uintptr // Pointer to data
}
// CERT_CHAIN_CONTEXT structure - Microsoft CryptoAPI certificate chain context
// Based on Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_context
type CERT_CHAIN_CONTEXT struct {
cbSize uint32 // Size of this structure in bytes
TrustStatus CERT_TRUST_STATUS // Combined trust status of the simple chains array
cChain uint32 // Number of simple chains in the array
rgpChain uintptr // Array of pointers to CERT_SIMPLE_CHAIN structures
cLowerQualityChainContext uint32 // Number of chains in rgpLowerQualityChainContext array
rgpLowerQualityChainContext uintptr // Array of pointers to CERT_CHAIN_CONTEXT structures
fHasRevocationFreshnessTime uint32 // BOOL - TRUE if dwRevocationFreshnessTime is available
dwRevocationFreshnessTime uint32 // Largest CurrentTime minus CRL's ThisUpdate in seconds
dwCreateFlags uint32 // Flags used when creating this chain context
ChainId windows.GUID // Unique identifier for this chain
}
// CERT_CHAIN_PARA structure - Parameters for CertGetCertificateChain
type CERT_CHAIN_PARA struct {
cbSize uint32 // Size of this structure
RequestedUsage uintptr // CERT_USAGE_MATCH - requested usage
RequestedIssuancePolicy uintptr // CERT_USAGE_MATCH - requested issuance policy
dwUrlRetrievalTimeout uint32 // URL retrieval timeout in milliseconds
fCheckRevocationFreshnessTime uint32 // BOOL - check revocation freshness time
dwRevocationFreshnessTime uint32 // Revocation freshness time in seconds
pftCacheResync uintptr // PFILETIME - cache resync time
pStrongSignPara uintptr // PCCERT_STRONG_SIGN_PARA - strong signature parameters
dwStrongSignFlags uint32 // Strong signature flags
}
// CERT_CHAIN_POLICY_PARA structure - Policy parameters for CertVerifyCertificateChainPolicy
type CERT_CHAIN_POLICY_PARA struct {
cbSize uint32 // Size of this structure
dwFlags uint32 // Policy-specific flags
pvExtraPolicyPara uintptr // Policy-specific extra parameters
}
// CERT_CHAIN_POLICY_STATUS structure - Policy validation results
type CERT_CHAIN_POLICY_STATUS struct {
cbSize uint32 // Size of this structure
dwError uint32 // Policy validation error
lChainIndex int32 // Chain index (for multi-chain contexts)
lElementIndex int32 // Element index within the chain
pvExtraPolicyStatus uintptr // Policy-specific extra status information
}
// Action identifier GUIDs for WinVerifyTrust/WinVerifyTrustEx functions
// Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/api/wintrust/nf-wintrust-winverifytrustex
// These constants are defined in Softpub.h per Microsoft documentation
var (
// WINTRUST_ACTION_GENERIC_VERIFY_V2: Verify a file or object using the Authenticode policy provider
// Microsoft docs: "Verify a file or object using the Authenticode policy provider"
// This is the standard action ID for Authenticode signature verification
WINTRUST_ACTION_GENERIC_VERIFY_V2 = windows.GUID{
Data1: 0x00AAC56B,
Data2: 0xCD44,
Data3: 0x11d0,
Data4: [8]byte{0x8C, 0xC2, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xEE},
}
)
// WINTRUST_FILE_INFO structure - EXACTLY matches Microsoft documentation
// Reference: https://learn.microsoft.com/en-us/windows/win32/api/wintrust/ns-wintrust-wintrust_file_info
// CRITICAL: Structure field order and types MUST match Microsoft specification exactly
// The WINTRUST_FILE_INFO structure is used when calling WinVerifyTrust to verify an individual file.
type WINTRUST_FILE_INFO struct {
cbStruct uint32 // DWORD cbStruct - Count of bytes in this structure
pcwszFilePath *uint16 // LPCWSTR pcwszFilePath - Full path and file name. This parameter CANNOT be NULL.
hFile windows.Handle // HANDLE hFile - Optional file handle to the open file. This member CAN be set to NULL.
pgKnownSubject *windows.GUID // GUID *pgKnownSubject - Optional pointer to a GUID. This member CAN be set to NULL.
}
// WINTRUST_SIGNATURE_SETTINGS for Windows 8+ dual signature support
// Microsoft docs: Used with pSignatureSettings in WINTRUST_DATA
type WINTRUST_SIGNATURE_SETTINGS struct {
cbStruct uint32 // DWORD cbStruct - must be sizeof(WINTRUST_SIGNATURE_SETTINGS)
dwIndex uint32 // DWORD dwIndex - signature index (0-based)
dwFlags uint32 // DWORD dwFlags - WSS_* flags
cSecondarySigs uint32 // DWORD cSecondarySigs - count of secondary signatures
dwVerifiedSigIndex uint32 // DWORD dwVerifiedSigIndex - index of verified signature
pCryptoPolicy uintptr // PCERT_STRONG_SIGN_PARA pCryptoPolicy - optional (Fixed for Go FFI consistency)
}
// WinTrustData matches Microsoft WINTRUST_DATA structure exactly
// See: https://learn.microsoft.com/en-us/windows/win32/api/wintrust/ns-wintrust-wintrust_data
type WinTrustData struct {
cbStruct uint32 // DWORD cbStruct - must be sizeof(WINTRUST_DATA)
pPolicyCallbackData uintptr // LPVOID pPolicyCallbackData - optional callback
pSIPClientData uintptr // LPVOID pSIPClientData - optional SIP data
dwUIChoice WTD_UI // DWORD dwUIChoice - UI behavior
fdwRevocationChecks WTD_REVOKE // DWORD fdwRevocationChecks - revocation policy
dwUnionChoice WTD_CHOICE // DWORD dwUnionChoice - union selector
pInfoUnion uintptr // Union pointer (pFile, pCatalog, etc.) - Fixed: Use uintptr for Windows API compliance
dwStateAction WTD_STATEACTION // DWORD dwStateAction - verification action
hWVTStateData windows.Handle // HANDLE hWVTStateData - state handle for cleanup
pwszURLReference *uint16 // LPCWSTR pwszURLReference - reserved, must be NULL
dwProvFlags WTD_FLAGS // DWORD dwProvFlags - provider flags
dwUIContext WTD_UICONTEXT // DWORD dwUIContext - UI context
pSignatureSettings *WINTRUST_SIGNATURE_SETTINGS // Windows 8+ signature settings
}
// Certificate information structure with comprehensive revocation and trust analysis
type CertificateInfo struct {
Subject string
Issuer string
SerialNumber string
Thumbprint string
NotBefore time.Time
NotAfter time.Time
SignatureAlg string
KeyUsage []string
// certificate name formats (based on absorbed Microsoft CryptoAPI documentation)
EnhancedInfo map[string]string // Contains advanced certificate analysis results
// Comprehensive revocation and trust status (based on CertVerifyRevocation and CERT_TRUST_STATUS)
RevocationInfo *RevocationInfo // Detailed revocation status information
TrustStatus *TrustStatus // Certificate trust status information
}
// RevocationInfo contains detailed certificate revocation status
// Based on CERT_REVOCATION_STATUS structure and CertVerifyRevocation results
type RevocationInfo struct {
IsRevoked bool // Whether the certificate is revoked
RevocationReason string // Reason for revocation (if revoked)
RevocationDate time.Time // Date of revocation (if available)
CRLSource string // Source of CRL information
OCSPSource string // Source of OCSP information
FreshnessTime uint32 // CRL freshness time in seconds
ErrorStatus string // Detailed error information
CheckMethod string // Method used for revocation checking (CRL/OCSP/Cache)
}
// TrustStatus contains certificate trust status information
// Based on CERT_TRUST_STATUS structure
type TrustStatus struct {
ErrorStatus []string // List of trust error conditions
InfoStatus []string // List of trust information flags
IsTrusted bool // Overall trust status
TrustLevel string // Trust level description
IssuerMatch string // Type of issuer match found
ChainStatus string // Certificate chain status
}
// Timestamp information structure
type TimestampInfo struct {
Timestamp time.Time
TSAName string
HashAlgorithm string
SerialNumber string
IsRFC3161 bool
}
// Signature information combining certificate and timestamp
type SignatureInfo struct {
Index uint32
IsPrimary bool
Certificate *CertificateInfo
Timestamp *TimestampInfo
SignatureType string
}
// extractSignatureInfo extracts detailed signature information using WinTrust helper APIs with comprehensive validation
func extractSignatureInfo(filePath string, stateData windows.Handle, index uint32) (*SignatureInfo, error) {
// Critical: Validate input parameters to prevent memory corruption
if stateData == 0 {
// Note: stateData is invalid - WinVerifyTrust didn't provide state data
return nil, fmt.Errorf("invalid state data handle: %d", stateData)