diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-10-01 13:13:58 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-10-01 13:59:42 +0200 |
commit | e2adae0548c43213eae96fbf0fa90b8ad6d8d927 (patch) | |
tree | f8deaaa5431ddf6abd67255d509a67c8ddffd1e5 | |
parent | Revert "version: use crypt32 instead of go x509 for cn extraction for file size" (diff) | |
download | wireguard-windows-e2adae0548c43213eae96fbf0fa90b8ad6d8d927.tar.xz wireguard-windows-e2adae0548c43213eae96fbf0fa90b8ad6d8d927.zip |
elevate: use fallback shellexecute when not EV-signed
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | elevate/shellexecute.go | 7 | ||||
-rw-r--r-- | version/official_windows.go | 67 |
2 files changed, 73 insertions, 1 deletions
diff --git a/elevate/shellexecute.go b/elevate/shellexecute.go index acb5b2e2..8e238f08 100644 --- a/elevate/shellexecute.go +++ b/elevate/shellexecute.go @@ -13,6 +13,8 @@ import ( "golang.org/x/sys/windows" "golang.org/x/sys/windows/registry" + + "golang.zx2c4.com/wireguard/windows/version" ) const ( @@ -45,6 +47,11 @@ func ShellExecute(program string, arguments string, directory string, show int32 } }() + if !version.IsRunningEVSigned() { + err = windows.ERROR_INSUFFICIENT_LOGON_INFO + return + } + var processToken windows.Token err = windows.OpenProcessToken(windows.CurrentProcess(), windows.TOKEN_QUERY|windows.TOKEN_DUPLICATE, &processToken) if err != nil { diff --git a/version/official_windows.go b/version/official_windows.go index b0f62250..fffebe55 100644 --- a/version/official_windows.go +++ b/version/official_windows.go @@ -6,6 +6,7 @@ package version import ( + "encoding/asn1" "os" "unsafe" @@ -15,8 +16,20 @@ import ( const ( officialCommonName = "WireGuard LLC" + evPolicyOid = "2.23.140.1.3" + policyExtensionOid = "2.5.29.32" ) +type policyQualifierInfo struct { + PolicyQualifierId asn1.ObjectIdentifier + Qualifier asn1.RawValue +} + +type policyInformation struct { + Policy asn1.ObjectIdentifier + Qualifiers []policyQualifierInfo `asn1:"optional"` +} + func VerifyAuthenticode(path string) bool { path16, err := windows.UTF16PtrFromString(path) if err != nil { @@ -65,7 +78,7 @@ func IsRunningOfficialVersion() bool { return false } - // This below tests is easily circumvented. False certificates can be appended, and just checking the + // This below test is easily circumvented. False certificates can be appended, and just checking the // common name is not very good. But that's okay, as this isn't security related. certs, err := wintrust.ExtractCertificates(path) if err != nil { @@ -78,3 +91,55 @@ func IsRunningOfficialVersion() bool { } return false } + +// This is an easily by-passable check, which doesn't serve a security purpose but mostly just a low-grade +// informational and semantic one. +func IsRunningEVSigned() bool { + path, err := os.Executable() + if err != nil { + return false + } + path16, err := windows.UTF16PtrFromString(path) + 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_NONE, // No revocation, as this isn't security related. + UnionChoice: wintrust.WTD_CHOICE_FILE, + StateAction: wintrust.WTD_STATEACTION_VERIFY, + FileOrCatalogOrBlobOrSgnrOrCert: uintptr(unsafe.Pointer(file)), + } + err = wintrust.WinVerifyTrust(0, &wintrust.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) + if err != nil { + return false + } + + // This below tests is easily circumvented. False certificates can be appended. But that's okay, as this isn't + // security related. + certs, err := wintrust.ExtractCertificates(path) + if err != nil { + return false + } + for _, cert := range certs { + for _, extension := range cert.Extensions { + if extension.Id.String() == policyExtensionOid { + var policies []policyInformation + if _, err = asn1.Unmarshal(extension.Value, &policies); err != nil { + continue + } + for _, policy := range policies { + if policy.Policy.String() == evPolicyOid { + return true + } + } + } + } + } + return false +} |