Skip to content

Commit 6e01b11

Browse files
authored
Merge pull request #50 from aws/feature/RolesAnywhere-V996803711
RolesAnywhere-V996803711: Attempt to silence UIs displayed by providers when signing
2 parents f98baf8 + 099e152 commit 6e01b11

File tree

1 file changed

+61
-35
lines changed

1 file changed

+61
-35
lines changed

aws_signing_helper/windows_cert_store_signer.go

+61-35
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ const (
7676
// NTE_BAD_ALGID — Invalid algorithm specified
7777
NTE_BAD_ALGID = 0x80090008
7878

79+
// NTE_SILENT_CONTEXT - KSP must display UI to operate
80+
NTE_SILENT_CONTEXT = 0x80090022
81+
7982
// WIN_API_FLAG specifies the flags that should be passed to
8083
// CryptAcquireCertificatePrivateKey. This impacts whether the CryptoAPI or CNG
8184
// API will be used.
@@ -89,13 +92,56 @@ const (
8992
WIN_API_FLAG = windows.CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG
9093
)
9194

92-
// Error codes for Windows APIs - implements the error interface
95+
var (
96+
// ErrRequiresUI is used when providers are required to display
97+
// UI to perform signing operations.
98+
ErrRequiresUI = errors.New("provider requries UI to operate")
99+
)
100+
101+
// Error codes for Windows APIs - implements the error interface.
102+
// Error codes are maintained on a per-thread basis. In order to
103+
// get the last error code, C.GetLastError needs to be called (called
104+
// within the checkError() function). Some Windows APIs only return
105+
// BOOLs indicating success or failure, and for more detailed error
106+
// information, error codes are used.
93107
type errCode uint64
94108

95-
// Security status for Windows APIs - implements the error interface
96-
// Go representation of the C SECURITY_STATUS
109+
// Implements the error interface for errCode and returns a string
110+
// version of the errCode
111+
func (c errCode) Error() string {
112+
var cMsg C.LPSTR
113+
ret := C.FormatMessage(
114+
C.FORMAT_MESSAGE_ALLOCATE_BUFFER|
115+
C.FORMAT_MESSAGE_FROM_SYSTEM|
116+
C.FORMAT_MESSAGE_IGNORE_INSERTS,
117+
nil,
118+
C.DWORD(c),
119+
C.ulong(C.MAKE_LANG_ID(C.LANG_NEUTRAL, C.SUBLANG_DEFAULT)),
120+
cMsg,
121+
0, nil)
122+
if ret == 0 {
123+
return fmt.Sprintf("Error %X", int(c))
124+
}
125+
126+
if cMsg == nil {
127+
return fmt.Sprintf("Error %X", int(c))
128+
}
129+
130+
goMsg := C.GoString(cMsg)
131+
132+
return fmt.Sprintf("Error: %X %s", int(c), goMsg)
133+
}
134+
135+
// Security status for Windows APIs - implements the error interface.
136+
// Some Windows API calls return this type directly.
137+
// Go representation of the C SECURITY_STATUS.
97138
type securityStatus uint64
98139

140+
// Implements the error interface
141+
func (secStatus securityStatus) Error() string {
142+
return fmt.Sprintf("SECURITY_STATUS %d", int(secStatus))
143+
}
144+
99145
// Gets the certificates that match the given CertIdentifier within the user's "MY" certificate store.
100146
// If there is only a single matching certificate, then its chain will be returned too
101147
func GetMatchingCertsAndChain(certIdentifier CertIdentifier) (store windows.Handle, certCtx *windows.CertContext, certChain []*x509.Certificate, certContainers []CertificateContainer, err error) {
@@ -441,9 +487,16 @@ func (signer *WindowsCertStoreSigner) cngSignHash(digest []byte, hash crypto.Has
441487
// Get signature
442488
sig := make([]byte, sigLen)
443489
sigPtr := (*C.BYTE)(&sig[0])
444-
if err := checkStatus(C.NCryptSignHash(*cngKeyHandle, padPtr, digestPtr, digestLen, sigPtr, sigLen, &sigLen, flags)); err != nil {
490+
if err := checkStatus(C.NCryptSignHash(*cngKeyHandle, padPtr, digestPtr, digestLen, sigPtr, sigLen, &sigLen, flags|C.NCRYPT_SILENT_FLAG)); err != nil {
491+
if err == ErrRequiresUI {
492+
if err = checkStatus(C.NCryptSignHash(*cngKeyHandle, padPtr, digestPtr, digestLen, sigPtr, sigLen, &sigLen, flags)); err == nil {
493+
goto got_signature
494+
}
495+
}
496+
445497
return nil, fmt.Errorf("failed to sign digest: %w", err)
446498
}
499+
got_signature:
447500

448501
// CNG returns a raw ECDSA signature, but we want ASN.1 DER encoding
449502
if _, isEC := privateKey.publicKey.(*ecdsa.PublicKey); isEC {
@@ -580,32 +633,6 @@ func checkError(msg string) error {
580633
return nil
581634
}
582635

583-
// Implements the error interface for errCode and returns a string
584-
// version of the errCode
585-
func (c errCode) Error() string {
586-
var cMsg C.LPSTR
587-
ret := C.FormatMessage(
588-
C.FORMAT_MESSAGE_ALLOCATE_BUFFER|
589-
C.FORMAT_MESSAGE_FROM_SYSTEM|
590-
C.FORMAT_MESSAGE_IGNORE_INSERTS,
591-
nil,
592-
C.DWORD(c),
593-
C.ulong(C.MAKE_LANG_ID(C.LANG_NEUTRAL, C.SUBLANG_DEFAULT)),
594-
cMsg,
595-
0, nil)
596-
if ret == 0 {
597-
return fmt.Sprintf("Error %X", int(c))
598-
}
599-
600-
if cMsg == nil {
601-
return fmt.Sprintf("Error %X", int(c))
602-
}
603-
604-
goMsg := C.GoString(cMsg)
605-
606-
return fmt.Sprintf("Error: %X %s", int(c), goMsg)
607-
}
608-
609636
// Converts a SECURITY_STATUS into a securityStatus
610637
func checkStatus(s C.SECURITY_STATUS) error {
611638
secStatus := securityStatus(s)
@@ -618,10 +645,9 @@ func checkStatus(s C.SECURITY_STATUS) error {
618645
return ErrUnsupportedHash
619646
}
620647

621-
return secStatus
622-
}
648+
if secStatus == NTE_SILENT_CONTEXT {
649+
return ErrRequiresUI
650+
}
623651

624-
// Implements the error interface
625-
func (secStatus securityStatus) Error() string {
626-
return fmt.Sprintf("SECURITY_STATUS %d", int(secStatus))
652+
return secStatus
627653
}

0 commit comments

Comments
 (0)