Previously, tailscale upgrade was doing the bare minimum for checking authenticode signatures via `WinVerifyTrustEx`. This is fine, but we can do better: * WinVerifyTrustEx verifies that the binary's signature is valid, but it doesn't determine *whose* signature is valid; tailscale upgrade should also ensure that the binary is actually signed *by us*. * I added the ability to check the signatures of MSI files. * In future PRs I will be adding diagnostic logging that lists details about every module (ie, DLL) loaded into our process. As part of that metadata, I want to be able to extract information about who signed the binaries. This code is modelled on some C++ I wrote for Firefox back in the day. See https://searchfox.org/mozilla-central/rev/27e4816536c891d85d63695025f2549fd7976392/toolkit/xre/dllservices/mozglue/Authenticode.cpp for reference. Fixes #8284 Signed-off-by: Aaron Klotz <aaron@tailscale.com>main
parent
ec9213a627
commit
7adf15f90e
@ -0,0 +1,512 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package authenticode |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"errors" |
||||
"fmt" |
||||
"path/filepath" |
||||
"strings" |
||||
"unsafe" |
||||
|
||||
"github.com/dblohm7/wingoes" |
||||
"github.com/dblohm7/wingoes/pe" |
||||
"golang.org/x/sys/windows" |
||||
) |
||||
|
||||
var ( |
||||
// ErrSigNotFound is returned if no authenticode signature could be found.
|
||||
ErrSigNotFound = errors.New("authenticode signature not found") |
||||
// ErrUnexpectedCertSubject is wrapped with the actual cert subject and
|
||||
// returned when the binary is signed by a different subject than expected.
|
||||
ErrUnexpectedCertSubject = errors.New("unexpected cert subject") |
||||
errCertSubjectNotFound = errors.New("cert subject not found") |
||||
errCertSubjectDecodeLenMismatch = errors.New("length mismatch while decoding cert subject") |
||||
) |
||||
|
||||
const ( |
||||
_CERT_STRONG_SIGN_OID_INFO_CHOICE = 2 |
||||
_CMSG_SIGNER_CERT_INFO_PARAM = 7 |
||||
_MSI_INVALID_HASH_IS_FATAL = 1 |
||||
_TRUST_E_NOSIGNATURE = wingoes.HRESULT(-((0x800B0100 ^ 0xFFFFFFFF) + 1)) |
||||
) |
||||
|
||||
// Verify performs authenticode verification on the file at path, and also
|
||||
// ensures that expectedCertSubject was the entity who signed it. path may point
|
||||
// to either a PE binary or an MSI package. ErrSigNotFound is returned if no
|
||||
// signature is found.
|
||||
func Verify(path string, expectedCertSubject string) error { |
||||
path16, err := windows.UTF16PtrFromString(path) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var subject string |
||||
if strings.EqualFold(filepath.Ext(path), ".msi") { |
||||
subject, err = verifyMSI(path16) |
||||
} else { |
||||
subject, _, err = queryPE(path16, true) |
||||
} |
||||
|
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if subject != expectedCertSubject { |
||||
return fmt.Errorf("%w %q", ErrUnexpectedCertSubject, subject) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// SigProvenance indicates whether an authenticode signature was embedded within
|
||||
// the file itself, or the signature applies to an associated catalog file.
|
||||
type SigProvenance int |
||||
|
||||
const ( |
||||
SigProvUnknown = SigProvenance(iota) |
||||
SigProvEmbedded |
||||
SigProvCatalog |
||||
) |
||||
|
||||
// QueryCertSubject obtains the subject associated with the certificate used to
|
||||
// sign the PE binary located at path. When err == nil, it also returns the
|
||||
// provenance of that signature. ErrSigNotFound is returned if no signature
|
||||
// is found. Note that this function does *not* validate the chain of trust; use
|
||||
// Verify for that purpose!
|
||||
func QueryCertSubject(path string) (certSubject string, provenance SigProvenance, err error) { |
||||
path16, err := windows.UTF16PtrFromString(path) |
||||
if err != nil { |
||||
return "", SigProvUnknown, err |
||||
} |
||||
|
||||
return queryPE(path16, false) |
||||
} |
||||
|
||||
func queryPE(utf16Path *uint16, verify bool) (string, SigProvenance, error) { |
||||
certSubject, err := queryEmbeddedCertSubject(utf16Path, verify) |
||||
|
||||
switch { |
||||
case err == ErrSigNotFound: |
||||
// Try looking for the signature in a catalog file.
|
||||
default: |
||||
return certSubject, SigProvEmbedded, err |
||||
} |
||||
|
||||
certSubject, err = queryCatalogCertSubject(utf16Path, verify) |
||||
switch { |
||||
case err == ErrSigNotFound: |
||||
return "", SigProvUnknown, err |
||||
default: |
||||
return certSubject, SigProvCatalog, err |
||||
} |
||||
} |
||||
|
||||
type CertSubjectError struct { |
||||
Err error |
||||
Subject string |
||||
} |
||||
|
||||
func (e *CertSubjectError) Error() string { |
||||
if e == nil { |
||||
return "<nil>" |
||||
} |
||||
if e.Subject == "" { |
||||
return e.Err.Error() |
||||
} |
||||
return fmt.Sprintf("cert subject %q: %v", e.Subject, e.Err) |
||||
} |
||||
|
||||
func (e *CertSubjectError) Unwrap() error { |
||||
return e.Err |
||||
} |
||||
|
||||
func verifyMSI(path *uint16) (string, error) { |
||||
var certCtx *windows.CertContext |
||||
hr := msiGetFileSignatureInformation(path, _MSI_INVALID_HASH_IS_FATAL, &certCtx, nil, nil) |
||||
if e := wingoes.ErrorFromHRESULT(hr); e.Failed() { |
||||
if e == wingoes.ErrorFromHRESULT(_TRUST_E_NOSIGNATURE) { |
||||
return "", ErrSigNotFound |
||||
} |
||||
return "", e |
||||
} |
||||
defer windows.CertFreeCertificateContext(certCtx) |
||||
|
||||
return certSubjectFromCertContext(certCtx) |
||||
} |
||||
|
||||
func certSubjectFromCertContext(certCtx *windows.CertContext) (string, error) { |
||||
desiredLen := windows.CertGetNameString( |
||||
certCtx, |
||||
windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, |
||||
0, |
||||
nil, |
||||
nil, |
||||
0, |
||||
) |
||||
if desiredLen <= 1 { |
||||
return "", errCertSubjectNotFound |
||||
} |
||||
|
||||
buf := make([]uint16, desiredLen) |
||||
actualLen := windows.CertGetNameString( |
||||
certCtx, |
||||
windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, |
||||
0, |
||||
nil, |
||||
&buf[0], |
||||
desiredLen, |
||||
) |
||||
if actualLen != desiredLen { |
||||
return "", errCertSubjectDecodeLenMismatch |
||||
} |
||||
|
||||
return windows.UTF16ToString(buf), nil |
||||
} |
||||
|
||||
type objectQuery struct { |
||||
certStore windows.Handle |
||||
cryptMsg windows.Handle |
||||
encodingType uint32 |
||||
} |
||||
|
||||
func newObjectQuery(utf16Path *uint16) (*objectQuery, error) { |
||||
var oq objectQuery |
||||
if err := windows.CryptQueryObject( |
||||
windows.CERT_QUERY_OBJECT_FILE, |
||||
unsafe.Pointer(utf16Path), |
||||
windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, |
||||
windows.CERT_QUERY_FORMAT_FLAG_BINARY, |
||||
0, |
||||
&oq.encodingType, |
||||
nil, |
||||
nil, |
||||
&oq.certStore, |
||||
&oq.cryptMsg, |
||||
nil, |
||||
); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &oq, nil |
||||
} |
||||
|
||||
func (oq *objectQuery) Close() error { |
||||
if oq.certStore != 0 { |
||||
if err := windows.CertCloseStore(oq.certStore, 0); err != nil { |
||||
return err |
||||
} |
||||
oq.certStore = 0 |
||||
} |
||||
|
||||
if oq.cryptMsg != 0 { |
||||
if err := cryptMsgClose(oq.cryptMsg); err != nil { |
||||
return err |
||||
} |
||||
oq.cryptMsg = 0 |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (oq *objectQuery) certSubject() (string, error) { |
||||
var certInfoLen uint32 |
||||
if err := cryptMsgGetParam( |
||||
oq.cryptMsg, |
||||
_CMSG_SIGNER_CERT_INFO_PARAM, |
||||
0, |
||||
unsafe.Pointer(nil), |
||||
&certInfoLen, |
||||
); err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
buf := make([]byte, certInfoLen) |
||||
if err := cryptMsgGetParam( |
||||
oq.cryptMsg, |
||||
_CMSG_SIGNER_CERT_INFO_PARAM, |
||||
0, |
||||
unsafe.Pointer(&buf[0]), |
||||
&certInfoLen, |
||||
); err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
certInfo := (*windows.CertInfo)(unsafe.Pointer(&buf[0])) |
||||
certCtx, err := windows.CertFindCertificateInStore( |
||||
oq.certStore, |
||||
oq.encodingType, |
||||
0, |
||||
windows.CERT_FIND_SUBJECT_CERT, |
||||
unsafe.Pointer(certInfo), |
||||
nil, |
||||
) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
defer windows.CertFreeCertificateContext(certCtx) |
||||
|
||||
return certSubjectFromCertContext(certCtx) |
||||
} |
||||
|
||||
func extractCertBlob(hfile windows.Handle) ([]byte, error) { |
||||
pef, err := pe.NewPEFromFileHandle(hfile) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer pef.Close() |
||||
|
||||
certsAny, err := pef.DataDirectoryEntry(pe.IMAGE_DIRECTORY_ENTRY_SECURITY) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
certs, ok := certsAny.([]pe.AuthenticodeCert) |
||||
if !ok || len(certs) == 0 { |
||||
return nil, ErrSigNotFound |
||||
} |
||||
|
||||
for _, cert := range certs { |
||||
if cert.Revision() != pe.WIN_CERT_REVISION_2_0 || cert.Type() != pe.WIN_CERT_TYPE_PKCS_SIGNED_DATA { |
||||
continue |
||||
} |
||||
return cert.Data(), nil |
||||
} |
||||
|
||||
return nil, ErrSigNotFound |
||||
} |
||||
|
||||
type _HCRYPTPROV windows.Handle |
||||
|
||||
type _CRYPT_VERIFY_MESSAGE_PARA struct { |
||||
CBSize uint32 |
||||
MsgAndCertEncodingType uint32 |
||||
HCryptProv _HCRYPTPROV |
||||
FNGetSignerCertificate uintptr |
||||
GetArg uintptr |
||||
StrongSignPara *windows.CertStrongSignPara |
||||
} |
||||
|
||||
func querySubjectFromBlob(blob []byte) (string, error) { |
||||
para := _CRYPT_VERIFY_MESSAGE_PARA{ |
||||
CBSize: uint32(unsafe.Sizeof(_CRYPT_VERIFY_MESSAGE_PARA{})), |
||||
MsgAndCertEncodingType: windows.X509_ASN_ENCODING | windows.PKCS_7_ASN_ENCODING, |
||||
} |
||||
|
||||
var certCtx *windows.CertContext |
||||
if err := cryptVerifyMessageSignature(¶, 0, &blob[0], uint32(len(blob)), nil, nil, &certCtx); err != nil { |
||||
return "", err |
||||
} |
||||
defer windows.CertFreeCertificateContext(certCtx) |
||||
|
||||
return certSubjectFromCertContext(certCtx) |
||||
} |
||||
|
||||
func queryEmbeddedCertSubject(utf16Path *uint16, verify bool) (string, error) { |
||||
peBinary, err := windows.CreateFile( |
||||
utf16Path, |
||||
windows.GENERIC_READ, |
||||
windows.FILE_SHARE_READ, |
||||
nil, |
||||
windows.OPEN_EXISTING, |
||||
0, |
||||
0, |
||||
) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
defer windows.CloseHandle(peBinary) |
||||
|
||||
blob, err := extractCertBlob(peBinary) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
certSubj, err := querySubjectFromBlob(blob) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !verify { |
||||
return certSubj, nil |
||||
} |
||||
|
||||
wintrustArg := unsafe.Pointer(&windows.WinTrustFileInfo{ |
||||
Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), |
||||
FilePath: utf16Path, |
||||
File: peBinary, |
||||
}) |
||||
if err := verifyTrust(windows.WTD_CHOICE_FILE, wintrustArg); err != nil { |
||||
// We might still want to know who the cert subject claims to be
|
||||
// even if the validation has failed (eg for troubleshooting purposes),
|
||||
// so we return a CertSubjectError.
|
||||
return "", &CertSubjectError{Err: err, Subject: certSubj} |
||||
} |
||||
|
||||
return certSubj, nil |
||||
} |
||||
|
||||
var ( |
||||
_BCRYPT_SHA256_ALGORITHM = &([]uint16{'S', 'H', 'A', '2', '5', '6', 0})[0] |
||||
_OID_CERT_STRONG_SIGN_OS_1 = &([]byte("1.3.6.1.4.1.311.72.1.1\x00"))[0] |
||||
) |
||||
|
||||
type _HCATADMIN windows.Handle |
||||
type _HCATINFO windows.Handle |
||||
|
||||
type _CATALOG_INFO struct { |
||||
size uint32 |
||||
catalogFile [windows.MAX_PATH]uint16 |
||||
} |
||||
|
||||
type _WINTRUST_CATALOG_INFO struct { |
||||
size uint32 |
||||
catalogVersion uint32 |
||||
catalogFilePath *uint16 |
||||
memberTag *uint16 |
||||
memberFilePath *uint16 |
||||
memberFile windows.Handle |
||||
pCalculatedFileHash *byte |
||||
cbCalculatedFileHash uint32 |
||||
catalogContext uintptr |
||||
catAdmin _HCATADMIN |
||||
} |
||||
|
||||
func queryCatalogCertSubject(utf16Path *uint16, verify bool) (string, error) { |
||||
var catAdmin _HCATADMIN |
||||
policy := windows.CertStrongSignPara{ |
||||
Size: uint32(unsafe.Sizeof(windows.CertStrongSignPara{})), |
||||
InfoChoice: _CERT_STRONG_SIGN_OID_INFO_CHOICE, |
||||
InfoOrSerializedInfoOrOID: unsafe.Pointer(_OID_CERT_STRONG_SIGN_OS_1), |
||||
} |
||||
if err := cryptCATAdminAcquireContext2( |
||||
&catAdmin, |
||||
nil, |
||||
_BCRYPT_SHA256_ALGORITHM, |
||||
&policy, |
||||
0, |
||||
); err != nil { |
||||
return "", err |
||||
} |
||||
defer cryptCATAdminReleaseContext(catAdmin, 0) |
||||
|
||||
// We use windows.CreateFile instead of standard library facilities because:
|
||||
// 1. Subsequent API calls directly utilize the file's Win32 HANDLE;
|
||||
// 2. We're going to be hashing the contents of this file, so we want to
|
||||
// provide a sequential-scan hint to the kernel.
|
||||
memberFile, err := windows.CreateFile( |
||||
utf16Path, |
||||
windows.GENERIC_READ, |
||||
windows.FILE_SHARE_READ, |
||||
nil, |
||||
windows.OPEN_EXISTING, |
||||
windows.FILE_FLAG_SEQUENTIAL_SCAN, |
||||
0, |
||||
) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
defer windows.CloseHandle(memberFile) |
||||
|
||||
var hashLen uint32 |
||||
if err := cryptCATAdminCalcHashFromFileHandle2( |
||||
catAdmin, |
||||
memberFile, |
||||
&hashLen, |
||||
nil, |
||||
0, |
||||
); err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
hashBuf := make([]byte, hashLen) |
||||
if err := cryptCATAdminCalcHashFromFileHandle2( |
||||
catAdmin, |
||||
memberFile, |
||||
&hashLen, |
||||
&hashBuf[0], |
||||
0, |
||||
); err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
catInfoCtx, err := cryptCATAdminEnumCatalogFromHash( |
||||
catAdmin, |
||||
&hashBuf[0], |
||||
hashLen, |
||||
0, |
||||
nil, |
||||
) |
||||
if err != nil { |
||||
if err == windows.ERROR_NOT_FOUND { |
||||
err = ErrSigNotFound |
||||
} |
||||
return "", err |
||||
} |
||||
defer cryptCATAdminReleaseCatalogContext(catAdmin, catInfoCtx, 0) |
||||
|
||||
catInfo := _CATALOG_INFO{ |
||||
size: uint32(unsafe.Sizeof(_CATALOG_INFO{})), |
||||
} |
||||
if err := cryptCATAdminCatalogInfoFromContext(catInfoCtx, &catInfo, 0); err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
oq, err := newObjectQuery(&catInfo.catalogFile[0]) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
defer oq.Close() |
||||
|
||||
certSubj, err := oq.certSubject() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !verify { |
||||
return certSubj, nil |
||||
} |
||||
|
||||
// memberTag is required to be formatted this way.
|
||||
hbh := strings.ToUpper(hex.EncodeToString(hashBuf)) |
||||
memberTag, err := windows.UTF16PtrFromString(hbh) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
wintrustArg := unsafe.Pointer(&_WINTRUST_CATALOG_INFO{ |
||||
size: uint32(unsafe.Sizeof(_WINTRUST_CATALOG_INFO{})), |
||||
catalogFilePath: &catInfo.catalogFile[0], |
||||
memberTag: memberTag, |
||||
memberFilePath: utf16Path, |
||||
memberFile: memberFile, |
||||
catAdmin: catAdmin, |
||||
}) |
||||
if err := verifyTrust(windows.WTD_CHOICE_CATALOG, wintrustArg); err != nil { |
||||
// We might still want to know who the cert subject claims to be
|
||||
// even if the validation has failed (eg for troubleshooting purposes),
|
||||
// so we return a CertSubjectError.
|
||||
return "", &CertSubjectError{Err: err, Subject: certSubj} |
||||
} |
||||
|
||||
return certSubj, nil |
||||
} |
||||
|
||||
func verifyTrust(infoType uint32, info unsafe.Pointer) error { |
||||
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: infoType, |
||||
StateAction: windows.WTD_STATEACTION_VERIFY, |
||||
FileOrCatalogOrBlobOrSgnrOrCert: info, |
||||
} |
||||
err := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) |
||||
|
||||
data.StateAction = windows.WTD_STATEACTION_CLOSE |
||||
windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) |
||||
|
||||
return err |
||||
} |
||||
@ -0,0 +1,18 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package authenticode |
||||
|
||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go mksyscall.go
|
||||
//go:generate go run golang.org/x/tools/cmd/goimports -w zsyscall_windows.go
|
||||
|
||||
//sys cryptCATAdminAcquireContext2(hCatAdmin *_HCATADMIN, pgSubsystem *windows.GUID, hashAlgorithm *uint16, strongHashPolicy *windows.CertStrongSignPara, flags uint32) (err error) [int32(failretval)==0] = wintrust.CryptCATAdminAcquireContext2
|
||||
//sys cryptCATAdminCalcHashFromFileHandle2(hCatAdmin _HCATADMIN, file windows.Handle, pcbHash *uint32, pbHash *byte, flags uint32) (err error) [int32(failretval)==0] = wintrust.CryptCATAdminCalcHashFromFileHandle2
|
||||
//sys cryptCATAdminCatalogInfoFromContext(hCatInfo _HCATINFO, catInfo *_CATALOG_INFO, flags uint32) (err error) [int32(failretval)==0] = wintrust.CryptCATCatalogInfoFromContext
|
||||
//sys cryptCATAdminEnumCatalogFromHash(hCatAdmin _HCATADMIN, pbHash *byte, cbHash uint32, flags uint32, prevCatInfo *_HCATINFO) (ret _HCATINFO, err error) [ret==0] = wintrust.CryptCATAdminEnumCatalogFromHash
|
||||
//sys cryptCATAdminReleaseCatalogContext(hCatAdmin _HCATADMIN, hCatInfo _HCATINFO, flags uint32) (err error) [int32(failretval)==0] = wintrust.CryptCATAdminReleaseCatalogContext
|
||||
//sys cryptCATAdminReleaseContext(hCatAdmin _HCATADMIN, flags uint32) (err error) [int32(failretval)==0] = wintrust.CryptCATAdminReleaseContext
|
||||
//sys cryptMsgClose(cryptMsg windows.Handle) (err error) [int32(failretval)==0] = crypt32.CryptMsgClose
|
||||
//sys cryptMsgGetParam(cryptMsg windows.Handle, paramType uint32, index uint32, data unsafe.Pointer, dataLen *uint32) (err error) [int32(failretval)==0] = crypt32.CryptMsgGetParam
|
||||
//sys cryptVerifyMessageSignature(pVerifyPara *_CRYPT_VERIFY_MESSAGE_PARA, signerIndex uint32, pbSignedBlob *byte, cbSignedBlob uint32, pbDecoded *byte, pdbDecoded *uint32, ppSignerCert **windows.CertContext) (err error) [int32(failretval)==0] = crypt32.CryptVerifyMessageSignature
|
||||
//sys msiGetFileSignatureInformation(signedObjectPath *uint16, flags uint32, certCtx **windows.CertContext, pbHashData *byte, cbHashData *uint32) (ret wingoes.HRESULT) = msi.MsiGetFileSignatureInformationW
|
||||
@ -0,0 +1,135 @@ |
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package authenticode |
||||
|
||||
import ( |
||||
"syscall" |
||||
"unsafe" |
||||
|
||||
"github.com/dblohm7/wingoes" |
||||
"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") |
||||
modmsi = windows.NewLazySystemDLL("msi.dll") |
||||
modwintrust = windows.NewLazySystemDLL("wintrust.dll") |
||||
|
||||
procCryptMsgClose = modcrypt32.NewProc("CryptMsgClose") |
||||
procCryptMsgGetParam = modcrypt32.NewProc("CryptMsgGetParam") |
||||
procCryptVerifyMessageSignature = modcrypt32.NewProc("CryptVerifyMessageSignature") |
||||
procMsiGetFileSignatureInformationW = modmsi.NewProc("MsiGetFileSignatureInformationW") |
||||
procCryptCATAdminAcquireContext2 = modwintrust.NewProc("CryptCATAdminAcquireContext2") |
||||
procCryptCATAdminCalcHashFromFileHandle2 = modwintrust.NewProc("CryptCATAdminCalcHashFromFileHandle2") |
||||
procCryptCATAdminEnumCatalogFromHash = modwintrust.NewProc("CryptCATAdminEnumCatalogFromHash") |
||||
procCryptCATAdminReleaseCatalogContext = modwintrust.NewProc("CryptCATAdminReleaseCatalogContext") |
||||
procCryptCATAdminReleaseContext = modwintrust.NewProc("CryptCATAdminReleaseContext") |
||||
procCryptCATCatalogInfoFromContext = modwintrust.NewProc("CryptCATCatalogInfoFromContext") |
||||
) |
||||
|
||||
func cryptMsgClose(cryptMsg windows.Handle) (err error) { |
||||
r1, _, e1 := syscall.Syscall(procCryptMsgClose.Addr(), 1, uintptr(cryptMsg), 0, 0) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptMsgGetParam(cryptMsg windows.Handle, paramType uint32, index uint32, data unsafe.Pointer, dataLen *uint32) (err error) { |
||||
r1, _, e1 := syscall.Syscall6(procCryptMsgGetParam.Addr(), 5, uintptr(cryptMsg), uintptr(paramType), uintptr(index), uintptr(data), uintptr(unsafe.Pointer(dataLen)), 0) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptVerifyMessageSignature(pVerifyPara *_CRYPT_VERIFY_MESSAGE_PARA, signerIndex uint32, pbSignedBlob *byte, cbSignedBlob uint32, pbDecoded *byte, pdbDecoded *uint32, ppSignerCert **windows.CertContext) (err error) { |
||||
r1, _, e1 := syscall.Syscall9(procCryptVerifyMessageSignature.Addr(), 7, uintptr(unsafe.Pointer(pVerifyPara)), uintptr(signerIndex), uintptr(unsafe.Pointer(pbSignedBlob)), uintptr(cbSignedBlob), uintptr(unsafe.Pointer(pbDecoded)), uintptr(unsafe.Pointer(pdbDecoded)), uintptr(unsafe.Pointer(ppSignerCert)), 0, 0) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func msiGetFileSignatureInformation(signedObjectPath *uint16, flags uint32, certCtx **windows.CertContext, pbHashData *byte, cbHashData *uint32) (ret wingoes.HRESULT) { |
||||
r0, _, _ := syscall.Syscall6(procMsiGetFileSignatureInformationW.Addr(), 5, uintptr(unsafe.Pointer(signedObjectPath)), uintptr(flags), uintptr(unsafe.Pointer(certCtx)), uintptr(unsafe.Pointer(pbHashData)), uintptr(unsafe.Pointer(cbHashData)), 0) |
||||
ret = wingoes.HRESULT(r0) |
||||
return |
||||
} |
||||
|
||||
func cryptCATAdminAcquireContext2(hCatAdmin *_HCATADMIN, pgSubsystem *windows.GUID, hashAlgorithm *uint16, strongHashPolicy *windows.CertStrongSignPara, flags uint32) (err error) { |
||||
r1, _, e1 := syscall.Syscall6(procCryptCATAdminAcquireContext2.Addr(), 5, uintptr(unsafe.Pointer(hCatAdmin)), uintptr(unsafe.Pointer(pgSubsystem)), uintptr(unsafe.Pointer(hashAlgorithm)), uintptr(unsafe.Pointer(strongHashPolicy)), uintptr(flags), 0) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptCATAdminCalcHashFromFileHandle2(hCatAdmin _HCATADMIN, file windows.Handle, pcbHash *uint32, pbHash *byte, flags uint32) (err error) { |
||||
r1, _, e1 := syscall.Syscall6(procCryptCATAdminCalcHashFromFileHandle2.Addr(), 5, uintptr(hCatAdmin), uintptr(file), uintptr(unsafe.Pointer(pcbHash)), uintptr(unsafe.Pointer(pbHash)), uintptr(flags), 0) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptCATAdminEnumCatalogFromHash(hCatAdmin _HCATADMIN, pbHash *byte, cbHash uint32, flags uint32, prevCatInfo *_HCATINFO) (ret _HCATINFO, err error) { |
||||
r0, _, e1 := syscall.Syscall6(procCryptCATAdminEnumCatalogFromHash.Addr(), 5, uintptr(hCatAdmin), uintptr(unsafe.Pointer(pbHash)), uintptr(cbHash), uintptr(flags), uintptr(unsafe.Pointer(prevCatInfo)), 0) |
||||
ret = _HCATINFO(r0) |
||||
if ret == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptCATAdminReleaseCatalogContext(hCatAdmin _HCATADMIN, hCatInfo _HCATINFO, flags uint32) (err error) { |
||||
r1, _, e1 := syscall.Syscall(procCryptCATAdminReleaseCatalogContext.Addr(), 3, uintptr(hCatAdmin), uintptr(hCatInfo), uintptr(flags)) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptCATAdminReleaseContext(hCatAdmin _HCATADMIN, flags uint32) (err error) { |
||||
r1, _, e1 := syscall.Syscall(procCryptCATAdminReleaseContext.Addr(), 2, uintptr(hCatAdmin), uintptr(flags), 0) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
|
||||
func cryptCATAdminCatalogInfoFromContext(hCatInfo _HCATINFO, catInfo *_CATALOG_INFO, flags uint32) (err error) { |
||||
r1, _, e1 := syscall.Syscall(procCryptCATCatalogInfoFromContext.Addr(), 3, uintptr(hCatInfo), uintptr(unsafe.Pointer(catInfo)), uintptr(flags)) |
||||
if int32(r1) == 0 { |
||||
err = errnoErr(e1) |
||||
} |
||||
return |
||||
} |
||||
Loading…
Reference in new issue