@@ -76,6 +76,9 @@ const (
76
76
// NTE_BAD_ALGID — Invalid algorithm specified
77
77
NTE_BAD_ALGID = 0x80090008
78
78
79
+ // NTE_SILENT_CONTEXT - KSP must display UI to operate
80
+ NTE_SILENT_CONTEXT = 0x80090022
81
+
79
82
// WIN_API_FLAG specifies the flags that should be passed to
80
83
// CryptAcquireCertificatePrivateKey. This impacts whether the CryptoAPI or CNG
81
84
// API will be used.
@@ -89,13 +92,56 @@ const (
89
92
WIN_API_FLAG = windows .CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG
90
93
)
91
94
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.
93
107
type errCode uint64
94
108
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.
97
138
type securityStatus uint64
98
139
140
+ // Implements the error interface
141
+ func (secStatus securityStatus ) Error () string {
142
+ return fmt .Sprintf ("SECURITY_STATUS %d" , int (secStatus ))
143
+ }
144
+
99
145
// Gets the certificates that match the given CertIdentifier within the user's "MY" certificate store.
100
146
// If there is only a single matching certificate, then its chain will be returned too
101
147
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
441
487
// Get signature
442
488
sig := make ([]byte , sigLen )
443
489
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
+
445
497
return nil , fmt .Errorf ("failed to sign digest: %w" , err )
446
498
}
499
+ got_signature:
447
500
448
501
// CNG returns a raw ECDSA signature, but we want ASN.1 DER encoding
449
502
if _ , isEC := privateKey .publicKey .(* ecdsa.PublicKey ); isEC {
@@ -580,32 +633,6 @@ func checkError(msg string) error {
580
633
return nil
581
634
}
582
635
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
-
609
636
// Converts a SECURITY_STATUS into a securityStatus
610
637
func checkStatus (s C.SECURITY_STATUS ) error {
611
638
secStatus := securityStatus (s )
@@ -618,10 +645,9 @@ func checkStatus(s C.SECURITY_STATUS) error {
618
645
return ErrUnsupportedHash
619
646
}
620
647
621
- return secStatus
622
- }
648
+ if secStatus == NTE_SILENT_CONTEXT {
649
+ return ErrRequiresUI
650
+ }
623
651
624
- // Implements the error interface
625
- func (secStatus securityStatus ) Error () string {
626
- return fmt .Sprintf ("SECURITY_STATUS %d" , int (secStatus ))
652
+ return secStatus
627
653
}
0 commit comments