From fc41f439f573fce3efdd37017f072f86cb7828ff Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 22 Jan 2021 18:24:33 +0100 Subject: global: move certain win32 APIs to x/sys/windows Signed-off-by: Jason A. Donenfeld --- conf/dpapi/dpapi_windows.go | 59 ++++------- conf/dpapi/mksyscall.go | 8 -- conf/dpapi/test.exe | Bin 0 -> 3622400 bytes conf/dpapi/zdpapi_windows.go | 61 ----------- conf/storewatcher_windows.go | 24 +---- conf/zsyscall_windows.go | 28 +---- elevate/membership.go | 4 +- elevate/syscall_windows.go | 3 - elevate/zsyscall_windows.go | 34 ++---- version/certificate_test.go | 42 ++++++++ version/certificate_windows.go | 115 ++++++++++++++++++++ version/official_windows.go | 29 +++-- version/wintrust/certificate_test.go | 42 -------- version/wintrust/certificate_windows.go | 180 -------------------------------- version/wintrust/mksyscall.go | 8 -- version/wintrust/wintrust_windows.go | 116 -------------------- version/wintrust/zsyscall_windows.go | 85 --------------- 17 files changed, 207 insertions(+), 631 deletions(-) delete mode 100644 conf/dpapi/mksyscall.go create mode 100755 conf/dpapi/test.exe delete mode 100644 conf/dpapi/zdpapi_windows.go create mode 100644 version/certificate_test.go create mode 100644 version/certificate_windows.go delete mode 100644 version/wintrust/certificate_test.go delete mode 100644 version/wintrust/certificate_windows.go delete mode 100644 version/wintrust/mksyscall.go delete mode 100644 version/wintrust/wintrust_windows.go delete mode 100644 version/wintrust/zsyscall_windows.go diff --git a/conf/dpapi/dpapi_windows.go b/conf/dpapi/dpapi_windows.go index 778605e9..45ad950e 100644 --- a/conf/dpapi/dpapi_windows.go +++ b/conf/dpapi/dpapi_windows.go @@ -9,78 +9,59 @@ import ( "errors" "runtime" "unsafe" + "fmt" "golang.org/x/sys/windows" ) -const ( - dpCRYPTPROTECT_UI_FORBIDDEN uint32 = 0x1 - dpCRYPTPROTECT_LOCAL_MACHINE uint32 = 0x4 - dpCRYPTPROTECT_CRED_SYNC uint32 = 0x8 - dpCRYPTPROTECT_AUDIT uint32 = 0x10 - dpCRYPTPROTECT_NO_RECOVERY uint32 = 0x20 - dpCRYPTPROTECT_VERIFY_PROTECTION uint32 = 0x40 - dpCRYPTPROTECT_CRED_REGENERATE uint32 = 0x80 -) - -type dpBlob struct { - len uint32 - data uintptr +func bytesToBlob(bytes []byte) *windows.DataBlob { + blob := &windows.DataBlob{Size: uint32(len(bytes))} + if len(bytes) > 0 { + blob.Data = &bytes[0] + } + return blob } -func bytesToBlob(bytes []byte) *dpBlob { - blob := &dpBlob{} - blob.len = uint32(len(bytes)) - if len(bytes) > 0 { - blob.data = uintptr(unsafe.Pointer(&bytes[0])) - } - return blob -} - -//sys cryptProtectData(dataIn *dpBlob, name *uint16, optionalEntropy *dpBlob, reserved uintptr, promptStruct uintptr, flags uint32, dataOut *dpBlob) (err error) = crypt32.CryptProtectData - func Encrypt(data []byte, name string) ([]byte, error) { - out := dpBlob{} - err := cryptProtectData(bytesToBlob(data), windows.StringToUTF16Ptr(name), nil, 0, 0, dpCRYPTPROTECT_UI_FORBIDDEN, &out) + out := windows.DataBlob{} + err := windows.CryptProtectData(bytesToBlob(data), windows.StringToUTF16Ptr(name), nil, 0, nil, windows.CRYPTPROTECT_UI_FORBIDDEN, &out) if err != nil { - return nil, errors.New("Unable to encrypt DPAPI protected data: " + err.Error()) + return nil, fmt.Errorf("unable to encrypt DPAPI protected data: %w", err) } outSlice := *(*[]byte)(unsafe.Pointer(&(struct { - addr uintptr + addr *byte len int cap int - }{out.data, int(out.len), int(out.len)}))) + }{out.Data, int(out.Size), int(out.Size)}))) ret := make([]byte, len(outSlice)) copy(ret, outSlice) - windows.LocalFree(windows.Handle(out.data)) + windows.LocalFree(windows.Handle(unsafe.Pointer(out.Data))) return ret, nil } -//sys cryptUnprotectData(dataIn *dpBlob, name **uint16, optionalEntropy *dpBlob, reserved uintptr, promptStruct uintptr, flags uint32, dataOut *dpBlob) (err error) = crypt32.CryptUnprotectData - func Decrypt(data []byte, name string) ([]byte, error) { - out := dpBlob{} + out := windows.DataBlob{} var outName *uint16 utf16Name, err := windows.UTF16PtrFromString(name) if err != nil { return nil, err } - err = cryptUnprotectData(bytesToBlob(data), &outName, nil, 0, 0, dpCRYPTPROTECT_UI_FORBIDDEN, &out) + err = windows.CryptUnprotectData(bytesToBlob(data), &outName, nil, 0, nil, windows.CRYPTPROTECT_UI_FORBIDDEN, &out) if err != nil { - return nil, errors.New("Unable to decrypt DPAPI protected data: " + err.Error()) + return nil, fmt.Errorf("unable to decrypt DPAPI protected data: %w", err) } outSlice := *(*[]byte)(unsafe.Pointer(&(struct { - addr uintptr + addr *byte len int cap int - }{out.data, int(out.len), int(out.len)}))) + }{out.Data, int(out.Size), int(out.Size)}))) ret := make([]byte, len(outSlice)) copy(ret, outSlice) - windows.LocalFree(windows.Handle(out.data)) + windows.LocalFree(windows.Handle(unsafe.Pointer(out.Data))) // Note: this ridiculous open-coded strcmp is not constant time. different := false @@ -101,7 +82,7 @@ func Decrypt(data []byte, name string) ([]byte, error) { windows.LocalFree(windows.Handle(unsafe.Pointer(outName))) if different { - return nil, errors.New("The input name does not match the stored name") + return nil, errors.New("input name does not match the stored name") } return ret, nil diff --git a/conf/dpapi/mksyscall.go b/conf/dpapi/mksyscall.go deleted file mode 100644 index 7c27e2d9..00000000 --- a/conf/dpapi/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package dpapi - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zdpapi_windows.go dpapi_windows.go diff --git a/conf/dpapi/test.exe b/conf/dpapi/test.exe new file mode 100755 index 00000000..9e5f23a7 Binary files /dev/null and b/conf/dpapi/test.exe differ diff --git a/conf/dpapi/zdpapi_windows.go b/conf/dpapi/zdpapi_windows.go deleted file mode 100644 index 43738a52..00000000 --- a/conf/dpapi/zdpapi_windows.go +++ /dev/null @@ -1,61 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package dpapi - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) - errERROR_EINVAL error = syscall.EINVAL -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e syscall.Errno) error { - switch e { - case 0: - return errERROR_EINVAL - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modcrypt32 = windows.NewLazySystemDLL("crypt32.dll") - - procCryptProtectData = modcrypt32.NewProc("CryptProtectData") - procCryptUnprotectData = modcrypt32.NewProc("CryptUnprotectData") -) - -func cryptProtectData(dataIn *dpBlob, name *uint16, optionalEntropy *dpBlob, reserved uintptr, promptStruct uintptr, flags uint32, dataOut *dpBlob) (err error) { - r1, _, e1 := syscall.Syscall9(procCryptProtectData.Addr(), 7, uintptr(unsafe.Pointer(dataIn)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(optionalEntropy)), uintptr(reserved), uintptr(promptStruct), uintptr(flags), uintptr(unsafe.Pointer(dataOut)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func cryptUnprotectData(dataIn *dpBlob, name **uint16, optionalEntropy *dpBlob, reserved uintptr, promptStruct uintptr, flags uint32, dataOut *dpBlob) (err error) { - r1, _, e1 := syscall.Syscall9(procCryptUnprotectData.Addr(), 7, uintptr(unsafe.Pointer(dataIn)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(optionalEntropy)), uintptr(reserved), uintptr(promptStruct), uintptr(flags), uintptr(unsafe.Pointer(dataOut)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} diff --git a/conf/storewatcher_windows.go b/conf/storewatcher_windows.go index c5754558..44b4564e 100644 --- a/conf/storewatcher_windows.go +++ b/conf/storewatcher_windows.go @@ -11,20 +11,6 @@ import ( "golang.org/x/sys/windows" ) -const ( - fncFILE_NAME uint32 = 0x00000001 - fncDIR_NAME uint32 = 0x00000002 - fncATTRIBUTES uint32 = 0x00000004 - fncSIZE uint32 = 0x00000008 - fncLAST_WRITE uint32 = 0x00000010 - fncLAST_ACCESS uint32 = 0x00000020 - fncCREATION uint32 = 0x00000040 - fncSECURITY uint32 = 0x00000100 -) - -//sys findFirstChangeNotification(path *uint16, watchSubtree bool, filter uint32) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = kernel32.FindFirstChangeNotificationW -//sys findNextChangeNotification(handle windows.Handle) (err error) = kernel32.FindNextChangeNotification - var haveStartedWatchingConfigDir bool func startWatchingConfigDir() { @@ -36,7 +22,7 @@ func startWatchingConfigDir() { h := windows.InvalidHandle defer func() { if h != windows.InvalidHandle { - windows.CloseHandle(h) + windows.FindCloseChangeNotification(h) } haveStartedWatchingConfigDir = false }() @@ -45,7 +31,7 @@ func startWatchingConfigDir() { if err != nil { return } - h, err = findFirstChangeNotification(windows.StringToUTF16Ptr(configFileDir), true, fncFILE_NAME|fncDIR_NAME|fncATTRIBUTES|fncSIZE|fncLAST_WRITE|fncLAST_ACCESS|fncCREATION|fncSECURITY) + h, err = windows.FindFirstChangeNotification(configFileDir, true, windows.FILE_NOTIFY_CHANGE_FILE_NAME|windows.FILE_NOTIFY_CHANGE_DIR_NAME|windows.FILE_NOTIFY_CHANGE_ATTRIBUTES|windows.FILE_NOTIFY_CHANGE_SIZE|windows.FILE_NOTIFY_CHANGE_LAST_WRITE|windows.FILE_NOTIFY_CHANGE_LAST_ACCESS|windows.FILE_NOTIFY_CHANGE_CREATION|windows.FILE_NOTIFY_CHANGE_SECURITY) if err != nil { log.Printf("Unable to monitor config directory: %v", err) return @@ -54,7 +40,7 @@ func startWatchingConfigDir() { s, err := windows.WaitForSingleObject(h, windows.INFINITE) if err != nil || s == windows.WAIT_FAILED { log.Printf("Unable to wait on config directory watcher: %v", err) - windows.CloseHandle(h) + windows.FindCloseChangeNotification(h) h = windows.InvalidHandle goto startover } @@ -63,10 +49,10 @@ func startWatchingConfigDir() { cb.cb() } - err = findNextChangeNotification(h) + err = windows.FindNextChangeNotification(h) if err != nil { log.Printf("Unable to monitor config directory again: %v", err) - windows.CloseHandle(h) + windows.FindCloseChangeNotification(h) h = windows.InvalidHandle goto startover } diff --git a/conf/zsyscall_windows.go b/conf/zsyscall_windows.go index c012abaa..783411f6 100644 --- a/conf/zsyscall_windows.go +++ b/conf/zsyscall_windows.go @@ -38,35 +38,11 @@ func errnoErr(e syscall.Errno) error { } var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - modwininet = windows.NewLazySystemDLL("wininet.dll") + modwininet = windows.NewLazySystemDLL("wininet.dll") - procFindFirstChangeNotificationW = modkernel32.NewProc("FindFirstChangeNotificationW") - procFindNextChangeNotification = modkernel32.NewProc("FindNextChangeNotification") - procInternetGetConnectedState = modwininet.NewProc("InternetGetConnectedState") + procInternetGetConnectedState = modwininet.NewProc("InternetGetConnectedState") ) -func findFirstChangeNotification(path *uint16, watchSubtree bool, filter uint32) (handle windows.Handle, err error) { - var _p0 uint32 - if watchSubtree { - _p0 = 1 - } - r0, _, e1 := syscall.Syscall(procFindFirstChangeNotificationW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(_p0), uintptr(filter)) - handle = windows.Handle(r0) - if handle == windows.InvalidHandle { - err = errnoErr(e1) - } - return -} - -func findNextChangeNotification(handle windows.Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFindNextChangeNotification.Addr(), 1, uintptr(handle), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - func internetGetConnectedState(flags *uint32, reserved uint32) (connected bool) { r0, _, _ := syscall.Syscall(procInternetGetConnectedState.Addr(), 2, uintptr(unsafe.Pointer(flags)), uintptr(reserved), 0) connected = r0 != 0 diff --git a/elevate/membership.go b/elevate/membership.go index d0fe6bfe..769652c1 100644 --- a/elevate/membership.go +++ b/elevate/membership.go @@ -37,12 +37,12 @@ func TokenIsElevatedOrElevatable(token windows.Token) bool { } func IsAdminDesktop() (bool, error) { - hwnd := getShellWindow() + hwnd := windows.GetShellWindow() if hwnd == 0 { return false, windows.ERROR_INVALID_WINDOW_HANDLE } var pid uint32 - _, err := getWindowThreadProcessId(hwnd, &pid) + _, err := windows.GetWindowThreadProcessId(hwnd, &pid) if err != nil { return false, err } diff --git a/elevate/syscall_windows.go b/elevate/syscall_windows.go index 4f114711..b854fe7e 100644 --- a/elevate/syscall_windows.go +++ b/elevate/syscall_windows.go @@ -84,6 +84,3 @@ const ( //sys coInitializeEx(reserved uintptr, coInit uint32) (ret error) = ole32.CoInitializeEx //sys coUninitialize() = ole32.CoUninitialize //sys coGetObject(name *uint16, bindOpts *cBIND_OPTS3, guid *windows.GUID, functionTable ***[0xffff]uintptr) (ret error) = ole32.CoGetObject - -//sys getWindowThreadProcessId(hwnd uintptr, pid *uint32) (tid uint32, err error) = user32.GetWindowThreadProcessId -//sys getShellWindow() (hwnd uintptr) = user32.GetShellWindow diff --git a/elevate/zsyscall_windows.go b/elevate/zsyscall_windows.go index bd22f6dc..c7f71819 100644 --- a/elevate/zsyscall_windows.go +++ b/elevate/zsyscall_windows.go @@ -38,17 +38,14 @@ func errnoErr(e syscall.Errno) error { } var ( - modntdll = windows.NewLazySystemDLL("ntdll.dll") - modole32 = windows.NewLazySystemDLL("ole32.dll") - moduser32 = windows.NewLazySystemDLL("user32.dll") - - procRtlGetCurrentPeb = modntdll.NewProc("RtlGetCurrentPeb") - procRtlInitUnicodeString = modntdll.NewProc("RtlInitUnicodeString") - procCoGetObject = modole32.NewProc("CoGetObject") - procCoInitializeEx = modole32.NewProc("CoInitializeEx") - procCoUninitialize = modole32.NewProc("CoUninitialize") - procGetShellWindow = moduser32.NewProc("GetShellWindow") - procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId") + modntdll = windows.NewLazySystemDLL("ntdll.dll") + modole32 = windows.NewLazySystemDLL("ole32.dll") + + procRtlGetCurrentPeb = modntdll.NewProc("RtlGetCurrentPeb") + procRtlInitUnicodeString = modntdll.NewProc("RtlInitUnicodeString") + procCoGetObject = modole32.NewProc("CoGetObject") + procCoInitializeEx = modole32.NewProc("CoInitializeEx") + procCoUninitialize = modole32.NewProc("CoUninitialize") ) func rtlGetCurrentPeb() (peb *cPEB) { @@ -82,18 +79,3 @@ func coUninitialize() { syscall.Syscall(procCoUninitialize.Addr(), 0, 0, 0, 0) return } - -func getShellWindow() (hwnd uintptr) { - r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0) - hwnd = uintptr(r0) - return -} - -func getWindowThreadProcessId(hwnd uintptr, pid *uint32) (tid uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetWindowThreadProcessId.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(pid)), 0) - tid = uint32(r0) - if tid == 0 { - err = errnoErr(e1) - } - return -} diff --git a/version/certificate_test.go b/version/certificate_test.go new file mode 100644 index 00000000..35c4ddb6 --- /dev/null +++ b/version/certificate_test.go @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package version + +import ( + "fmt" + "path/filepath" + "testing" + + "golang.org/x/sys/windows" +) + +func TestExtractCertificateNames(t *testing.T) { + system32, err := windows.GetSystemDirectory() + if err != nil { + t.Fatal(err) + } + names, err := extractCertificateNames(filepath.Join(system32, "ntoskrnl.exe")) + if err != nil { + t.Fatal(err) + } + for i, name := range names { + fmt.Printf("%d: %s\n", i, name) + } +} + +func TestExtractCertificateExtension(t *testing.T) { + system32, err := windows.GetSystemDirectory() + if err != nil { + t.Fatal(err) + } + policies, err := extractCertificatePolicies(filepath.Join(system32, "ntoskrnl.exe"), "2.5.29.32") + if err != nil { + t.Fatal(err) + } + for i, policy := range policies { + fmt.Printf("%d: %s\n", i, policy) + } +} diff --git a/version/certificate_windows.go b/version/certificate_windows.go new file mode 100644 index 00000000..b5ae3764 --- /dev/null +++ b/version/certificate_windows.go @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package version + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +func extractCertificateNames(path string) ([]string, error) { + path16, err := windows.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + var certStore windows.Handle + err = windows.CryptQueryObject(windows.CERT_QUERY_OBJECT_FILE, unsafe.Pointer(path16), windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, windows.CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) + if err != nil { + return nil, err + } + defer windows.CertCloseStore(certStore, 0) + var cert *windows.CertContext + var names []string + for { + cert, err = windows.CertEnumCertificatesInStore(certStore, cert) + if err != nil { + if errno, ok := err.(syscall.Errno); ok { + if errno == syscall.Errno(windows.CRYPT_E_NOT_FOUND) { + break + } + } + return nil, err + } + if cert == nil { + break + } + nameLen := windows.CertGetNameString(cert, windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, nil, 0) + if nameLen == 0 { + continue + } + name16 := make([]uint16, nameLen) + if windows.CertGetNameString(cert, windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, &name16[0], nameLen) != nameLen { + continue + } + if name16[0] == 0 { + continue + } + names = append(names, windows.UTF16ToString(name16)) + } + if names == nil { + return nil, syscall.Errno(windows.CRYPT_E_NOT_FOUND) + } + return names, nil +} + +func extractCertificatePolicies(path string, oid string) ([]string, error) { + path16, err := windows.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + oid8, err := windows.BytePtrFromString(oid) + if err != nil { + return nil, err + } + var certStore windows.Handle + err = windows.CryptQueryObject(windows.CERT_QUERY_OBJECT_FILE, unsafe.Pointer(path16), windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, windows.CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) + if err != nil { + return nil, err + } + defer windows.CertCloseStore(certStore, 0) + var cert *windows.CertContext + var policies []string + for { + cert, err = windows.CertEnumCertificatesInStore(certStore, cert) + if err != nil { + if errno, ok := err.(syscall.Errno); ok { + if errno == syscall.Errno(windows.CRYPT_E_NOT_FOUND) { + break + } + } + return nil, err + } + if cert == nil { + break + } + ci := (*windows.CertInfo)(unsafe.Pointer(cert.CertInfo)) + ext := windows.CertFindExtension(oid8, ci.CountExtensions, ci.Extensions) + if ext == nil { + continue + } + var decodedLen uint32 + err = windows.CryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.ObjId, ext.Value.Data, ext.Value.Size, 0, nil, &decodedLen) + if err != nil { + return nil, err + } + bytes := make([]byte, decodedLen) + certPoliciesInfo := (*windows.CertPoliciesInfo)(unsafe.Pointer(&bytes[0])) + err = windows.CryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.ObjId, ext.Value.Data, ext.Value.Size, 0, unsafe.Pointer(&bytes[0]), &decodedLen) + if err != nil { + return nil, err + } + for i := uintptr(0); i < uintptr(certPoliciesInfo.Count); i++ { + cp := (*windows.CertPolicy)(unsafe.Pointer(uintptr(unsafe.Pointer(certPoliciesInfo.PolicyInfos)) + i*unsafe.Sizeof(*certPoliciesInfo.PolicyInfos))) + policies = append(policies, windows.BytePtrToString(cp.Identifier)) + } + } + if policies == nil { + return nil, syscall.Errno(windows.CRYPT_E_NOT_FOUND) + } + return policies, nil +} diff --git a/version/official_windows.go b/version/official_windows.go index 12b95e3b..1bfcf90b 100644 --- a/version/official_windows.go +++ b/version/official_windows.go @@ -10,8 +10,6 @@ import ( "unsafe" "golang.org/x/sys/windows" - - "golang.zx2c4.com/wireguard/windows/version/wintrust" ) const ( @@ -25,19 +23,18 @@ func VerifyAuthenticode(path string) bool { if err != nil { return false } - file := &wintrust.WinTrustFileInfo{ - CbStruct: uint32(unsafe.Sizeof(wintrust.WinTrustFileInfo{})), - FilePath: path16, - } - data := &wintrust.WinTrustData{ - CbStruct: uint32(unsafe.Sizeof(wintrust.WinTrustData{})), - UIChoice: wintrust.WTD_UI_NONE, - RevocationChecks: wintrust.WTD_REVOKE_WHOLECHAIN, // Full revocation checking, as this is called with network connectivity. - UnionChoice: wintrust.WTD_CHOICE_FILE, - StateAction: wintrust.WTD_STATEACTION_VERIFY, - FileOrCatalogOrBlobOrSgnrOrCert: uintptr(unsafe.Pointer(file)), + data := &windows.WinTrustData{ + Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), + UIChoice: windows.WTD_UI_NONE, + RevocationChecks: windows.WTD_REVOKE_WHOLECHAIN, // Full revocation checking, as this is called with network connectivity. + UnionChoice: windows.WTD_CHOICE_FILE, + StateAction: windows.WTD_STATEACTION_VERIFY, + FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ + Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), + FilePath: path16, + }), } - return wintrust.WinVerifyTrust(windows.InvalidHandle, &wintrust.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) == nil + return windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) == nil } // These are easily by-passable checks, which do not serve serve security purposes. Do not place security-sensitive @@ -49,7 +46,7 @@ func IsRunningOfficialVersion() bool { return false } - names, err := wintrust.ExtractCertificateNames(path) + names, err := extractCertificateNames(path) if err != nil { return false } @@ -67,7 +64,7 @@ func IsRunningEVSigned() bool { return false } - policies, err := wintrust.ExtractCertificatePolicies(path, policyExtensionOid) + policies, err := extractCertificatePolicies(path, policyExtensionOid) if err != nil { return false } diff --git a/version/wintrust/certificate_test.go b/version/wintrust/certificate_test.go deleted file mode 100644 index 86d90526..00000000 --- a/version/wintrust/certificate_test.go +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package wintrust - -import ( - "fmt" - "path/filepath" - "testing" - - "golang.org/x/sys/windows" -) - -func TestExtractCertificateNames(t *testing.T) { - system32, err := windows.GetSystemDirectory() - if err != nil { - t.Fatal(err) - } - names, err := ExtractCertificateNames(filepath.Join(system32, "ntoskrnl.exe")) - if err != nil { - t.Fatal(err) - } - for i, name := range names { - fmt.Printf("%d: %s\n", i, name) - } -} - -func TestExtractCertificateExtension(t *testing.T) { - system32, err := windows.GetSystemDirectory() - if err != nil { - t.Fatal(err) - } - policies, err := ExtractCertificatePolicies(filepath.Join(system32, "ntoskrnl.exe"), "2.5.29.32") - if err != nil { - t.Fatal(err) - } - for i, policy := range policies { - fmt.Printf("%d: %s\n", i, policy) - } -} diff --git a/version/wintrust/certificate_windows.go b/version/wintrust/certificate_windows.go deleted file mode 100644 index 0ce905e9..00000000 --- a/version/wintrust/certificate_windows.go +++ /dev/null @@ -1,180 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package wintrust - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -const ( - _CERT_QUERY_OBJECT_FILE = 1 - _CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 1024 - _CERT_QUERY_FORMAT_FLAG_ALL = 14 - _CERT_NAME_SIMPLE_DISPLAY_TYPE = 4 -) - -type blob struct { - len uint32 - data *byte -} - -type bitBlob struct { - len uint32 - data *byte - unusedBits uint32 -} - -type algoIdentifier struct { - objId uintptr - params blob -} - -type pubkeyInfo struct { - algo algoIdentifier - publicKey bitBlob -} - -type certExtension struct { - objId *byte - critical uint32 - value blob -} - -type certInfo struct { - version uint32 - serialNumber blob /* CRYPT_INTEGER_BLOB */ - signatureAlgorithm algoIdentifier /* CRYPT_ALGORITHM_IDENTIFIER */ - issuer blob /* CERT_NAME_BLOB */ - notbefore windows.Filetime - notafter windows.Filetime - subject blob /* CERT_NAME_BLOB */ - subjectPublicKeyInfo pubkeyInfo /* CERT_PUBLIC_KEY_INFO */ - issuerUniqueId bitBlob /* CRYPT_BIT_BLOB */ - subjectUniqueId bitBlob /* CRYPT_BIT_BLOB */ - countExtensions uint32 - extensions *certExtension /* *CERT_EXTENSION */ -} - -type certPolicy struct { - identifier *byte - countQualifiers uint32 - qualifiers uintptr /* CERT_POLICY_QUALIFIER_INFO */ -} - -type certPoliciesInfo struct { - countPolicyInfos uint32 - policyInfos *certPolicy -} - -//sys cryptQueryObject(objectType uint32, object uintptr, expectedContentTypeFlags uint32, expectedFormatTypeFlags uint32, flags uint32, msgAndCertEncodingType *uint32, contentType *uint32, formatType *uint32, certStore *windows.Handle, msg *windows.Handle, context *uintptr) (err error) = crypt32.CryptQueryObject -//sys certGetNameString(certContext *windows.CertContext, nameType uint32, flags uint32, typePara unsafe.Pointer, name *uint16, size uint32) (chars uint32) = crypt32.CertGetNameStringW -//sys certFindExtension(objId *byte, countExtensions uint32, extensions *certExtension) (ret *certExtension) = crypt32.CertFindExtension -//sys cryptDecodeObject(encodingType uint32, structType *byte, encodedBytes *byte, lenEncodedBytes uint32, flags uint32, decoded unsafe.Pointer, decodedLen *uint32) (err error) = crypt32.CryptDecodeObject - -func ExtractCertificateNames(path string) ([]string, error) { - path16, err := windows.UTF16PtrFromString(path) - if err != nil { - return nil, err - } - var certStore windows.Handle - err = cryptQueryObject(_CERT_QUERY_OBJECT_FILE, uintptr(unsafe.Pointer(path16)), _CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, _CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) - if err != nil { - return nil, err - } - defer windows.CertCloseStore(certStore, 0) - var cert *windows.CertContext - var names []string - for { - cert, err = windows.CertEnumCertificatesInStore(certStore, cert) - if err != nil { - if errno, ok := err.(syscall.Errno); ok { - if errno == syscall.Errno(windows.CRYPT_E_NOT_FOUND) { - break - } - } - return nil, err - } - if cert == nil { - break - } - nameLen := certGetNameString(cert, _CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, nil, 0) - if nameLen == 0 { - continue - } - name16 := make([]uint16, nameLen) - if certGetNameString(cert, _CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, &name16[0], nameLen) != nameLen { - continue - } - if name16[0] == 0 { - continue - } - names = append(names, windows.UTF16ToString(name16)) - } - if names == nil { - return nil, syscall.Errno(windows.CRYPT_E_NOT_FOUND) - } - return names, nil -} - -func ExtractCertificatePolicies(path string, oid string) ([]string, error) { - path16, err := windows.UTF16PtrFromString(path) - if err != nil { - return nil, err - } - oid8, err := windows.BytePtrFromString(oid) - if err != nil { - return nil, err - } - var certStore windows.Handle - err = cryptQueryObject(_CERT_QUERY_OBJECT_FILE, uintptr(unsafe.Pointer(path16)), _CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, _CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) - if err != nil { - return nil, err - } - defer windows.CertCloseStore(certStore, 0) - var cert *windows.CertContext - var policies []string - for { - cert, err = windows.CertEnumCertificatesInStore(certStore, cert) - if err != nil { - if errno, ok := err.(syscall.Errno); ok { - if errno == syscall.Errno(windows.CRYPT_E_NOT_FOUND) { - break - } - } - return nil, err - } - if cert == nil { - break - } - ci := (*certInfo)(unsafe.Pointer(cert.CertInfo)) - ext := certFindExtension(oid8, ci.countExtensions, ci.extensions) - if ext == nil { - continue - } - var decodedLen uint32 - err = cryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.objId, ext.value.data, ext.value.len, 0, nil, &decodedLen) - if err != nil { - return nil, err - } - bytes := make([]byte, decodedLen) - certPoliciesInfo := (*certPoliciesInfo)(unsafe.Pointer(&bytes[0])) - err = cryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.objId, ext.value.data, ext.value.len, 0, unsafe.Pointer(&bytes[0]), &decodedLen) - if err != nil { - return nil, err - } - for i := uintptr(0); i < uintptr(certPoliciesInfo.countPolicyInfos); i++ { - cp := (*certPolicy)(unsafe.Pointer(uintptr(unsafe.Pointer(certPoliciesInfo.policyInfos)) + i*unsafe.Sizeof(*certPoliciesInfo.policyInfos))) - policies = append(policies, windows.BytePtrToString(cp.identifier)) - } - } - if policies == nil { - return nil, syscall.Errno(windows.CRYPT_E_NOT_FOUND) - } - return policies, nil -} diff --git a/version/wintrust/mksyscall.go b/version/wintrust/mksyscall.go deleted file mode 100644 index 7709a654..00000000 --- a/version/wintrust/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package wintrust - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go wintrust_windows.go certificate_windows.go diff --git a/version/wintrust/wintrust_windows.go b/version/wintrust/wintrust_windows.go deleted file mode 100644 index e7c92606..00000000 --- a/version/wintrust/wintrust_windows.go +++ /dev/null @@ -1,116 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package wintrust - -import ( - "syscall" - - "golang.org/x/sys/windows" -) - -type WinTrustData struct { - CbStruct uint32 - PolicyCallbackData uintptr - SIPClientData uintptr - UIChoice uint32 - RevocationChecks uint32 - UnionChoice uint32 - FileOrCatalogOrBlobOrSgnrOrCert uintptr - StateAction uint32 - StateData syscall.Handle - URLReference *uint16 - ProvFlags uint32 - UIContext uint32 - SignatureSettings *WintrustSignatureSettings -} - -const ( - WTD_UI_ALL = 1 - WTD_UI_NONE = 2 - WTD_UI_NOBAD = 3 - WTD_UI_NOGOOD = 4 -) - -const ( - WTD_REVOKE_NONE = 0 - WTD_REVOKE_WHOLECHAIN = 1 -) - -const ( - WTD_CHOICE_FILE = 1 - WTD_CHOICE_CATALOG = 2 - WTD_CHOICE_BLOB = 3 - WTD_CHOICE_SIGNER = 4 - WTD_CHOICE_CERT = 5 -) - -const ( - WTD_STATEACTION_IGNORE = 0x00000000 - WTD_STATEACTION_VERIFY = 0x00000010 - WTD_STATEACTION_CLOSE = 0x00000002 - WTD_STATEACTION_AUTO_CACHE = 0x00000003 - WTD_STATEACTION_AUTO_CACHE_FLUSH = 0x00000004 -) - -const ( - WTD_USE_IE4_TRUST_FLAG = 0x1 - WTD_NO_IE4_CHAIN_FLAG = 0x2 - WTD_NO_POLICY_USAGE_FLAG = 0x4 - WTD_REVOCATION_CHECK_NONE = 0x10 - WTD_REVOCATION_CHECK_END_CERT = 0x20 - WTD_REVOCATION_CHECK_CHAIN = 0x40 - WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x80 - WTD_SAFER_FLAG = 0x100 - WTD_HASH_ONLY_FLAG = 0x200 - WTD_USE_DEFAULT_OSVER_CHECK = 0x400 - WTD_LIFETIME_SIGNING_FLAG = 0x800 - WTD_CACHE_ONLY_URL_RETRIEVAL = 0x1000 - WTD_DISABLE_MD2_MD4 = 0x2000 - WTD_MOTW = 0x4000 -) - -const ( - TRUST_E_NOSIGNATURE = 0x800B0100 - TRUST_E_EXPLICIT_DISTRUST = 0x800B0111 - TRUST_E_SUBJECT_NOT_TRUSTED = 0x800B0004 - CRYPT_E_SECURITY_SETTINGS = 0x80092026 -) - -const ( - WTD_UICONTEXT_EXECUTE = 0 - WTD_UICONTEXT_INSTALL = 1 -) - -var WINTRUST_ACTION_GENERIC_VERIFY_V2 = windows.GUID{ - Data1: 0xaac56b, - Data2: 0xcd44, - Data3: 0x11d0, - Data4: [8]byte{0x8c, 0xc2, 0x0, 0xc0, 0x4f, 0xc2, 0x95, 0xee}, -} - -type WinTrustFileInfo struct { - CbStruct uint32 - FilePath *uint16 - File windows.Handle - KnownSubject *windows.GUID -} - -type WintrustSignatureSettings struct { - CbStruct uint32 - Index uint32 - Flags uint32 - SecondarySigs uint32 - VerifiedSigIndex uint32 - CryptoPolicy *CertStrongSignPara -} - -type CertStrongSignPara struct { - CbStruct uint32 - InfoChoice uint32 - InfoOrSerializedInfoOrOID uintptr -} - -//sys WinVerifyTrust(hWnd windows.Handle, actionId *windows.GUID, data *WinTrustData) (err error) [r1 != 0] = wintrust.WinVerifyTrust diff --git a/version/wintrust/zsyscall_windows.go b/version/wintrust/zsyscall_windows.go deleted file mode 100644 index 67daccb1..00000000 --- a/version/wintrust/zsyscall_windows.go +++ /dev/null @@ -1,85 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package wintrust - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) - errERROR_EINVAL error = syscall.EINVAL -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e syscall.Errno) error { - switch e { - case 0: - return errERROR_EINVAL - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modcrypt32 = windows.NewLazySystemDLL("crypt32.dll") - modwintrust = windows.NewLazySystemDLL("wintrust.dll") - - procCertFindExtension = modcrypt32.NewProc("CertFindExtension") - procCertGetNameStringW = modcrypt32.NewProc("CertGetNameStringW") - procCryptDecodeObject = modcrypt32.NewProc("CryptDecodeObject") - procCryptQueryObject = modcrypt32.NewProc("CryptQueryObject") - procWinVerifyTrust = modwintrust.NewProc("WinVerifyTrust") -) - -func certFindExtension(objId *byte, countExtensions uint32, extensions *certExtension) (ret *certExtension) { - r0, _, _ := syscall.Syscall(procCertFindExtension.Addr(), 3, uintptr(unsafe.Pointer(objId)), uintptr(countExtensions), uintptr(unsafe.Pointer(extensions))) - ret = (*certExtension)(unsafe.Pointer(r0)) - return -} - -func certGetNameString(certContext *windows.CertContext, nameType uint32, flags uint32, typePara unsafe.Pointer, name *uint16, size uint32) (chars uint32) { - r0, _, _ := syscall.Syscall6(procCertGetNameStringW.Addr(), 6, uintptr(unsafe.Pointer(certContext)), uintptr(nameType), uintptr(flags), uintptr(typePara), uintptr(unsafe.Pointer(name)), uintptr(size)) - chars = uint32(r0) - return -} - -func cryptDecodeObject(encodingType uint32, structType *byte, encodedBytes *byte, lenEncodedBytes uint32, flags uint32, decoded unsafe.Pointer, decodedLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procCryptDecodeObject.Addr(), 7, uintptr(encodingType), uintptr(unsafe.Pointer(structType)), uintptr(unsafe.Pointer(encodedBytes)), uintptr(lenEncodedBytes), uintptr(flags), uintptr(decoded), uintptr(unsafe.Pointer(decodedLen)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func cryptQueryObject(objectType uint32, object uintptr, expectedContentTypeFlags uint32, expectedFormatTypeFlags uint32, flags uint32, msgAndCertEncodingType *uint32, contentType *uint32, formatType *uint32, certStore *windows.Handle, msg *windows.Handle, context *uintptr) (err error) { - r1, _, e1 := syscall.Syscall12(procCryptQueryObject.Addr(), 11, uintptr(objectType), uintptr(object), uintptr(expectedContentTypeFlags), uintptr(expectedFormatTypeFlags), uintptr(flags), uintptr(unsafe.Pointer(msgAndCertEncodingType)), uintptr(unsafe.Pointer(contentType)), uintptr(unsafe.Pointer(formatType)), uintptr(unsafe.Pointer(certStore)), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(context)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func WinVerifyTrust(hWnd windows.Handle, actionId *windows.GUID, data *WinTrustData) (err error) { - r1, _, e1 := syscall.Syscall(procWinVerifyTrust.Addr(), 3, uintptr(hWnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data))) - if r1 != 0 { - err = errnoErr(e1) - } - return -} -- cgit v1.2.3-59-g8ed1b