From 07524f5e8cfcec50934f44487faada277439a6e9 Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sat, 17 Oct 2026 15:29:59 +0800 Subject: [PATCH 1/2] fix(sign): explain 0x8009001D when a store key's provider fails to load (#2207) Windows reports NTE_PROVIDER_DLL_FAIL when the key storage provider holding a certificate's private key can't load its DLL: smart card or token middleware that is missing or broken, or a provider that exists only as 32-bit code a 64-bit process can't load. The certificate list showed it only as "Windows error 0x8009001D"; it now says what that means, as it already did for a missing card or provider. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz --- crates/sign/src/windows.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/sign/src/windows.rs b/crates/sign/src/windows.rs index 3974aff8c..b63d49cd0 100644 --- a/crates/sign/src/windows.rs +++ b/crates/sign/src/windows.rs @@ -200,6 +200,7 @@ const NTE_NOT_FOUND: u32 = 0x8009_0011; const NTE_BAD_PROVIDER: u32 = 0x8009_0013; const NTE_BAD_PROV_TYPE: u32 = 0x8009_0014; const NTE_BAD_KEYSET: u32 = 0x8009_0016; +const NTE_PROVIDER_DLL_FAIL: u32 = 0x8009_001D; const NTE_PROV_DLL_NOT_FOUND: u32 = 0x8009_001E; const NTE_SILENT_CONTEXT: u32 = 0x8009_0022; const NTE_NOT_SUPPORTED: u32 = 0x8009_0029; @@ -218,6 +219,11 @@ fn describe(e: &CngError) -> String { NTE_BAD_PROVIDER | NTE_BAD_PROV_TYPE | NTE_PROV_DLL_NOT_FOUND => { "its key provider isn't available to CNG (a legacy CryptoAPI-only provider, or its driver isn't installed)" } + // #2207: a smart card or token's middleware that is missing or broken, or a provider + // that exists only as 32-bit code, which a 64-bit process can't load. + NTE_PROVIDER_DLL_FAIL => { + "its key provider's software failed to load (a smart card or token driver that is missing or broken, or a 32-bit-only provider)" + } NTE_NOT_SUPPORTED => "its key provider doesn't support the operation", NTE_DEVICE_NOT_READY | NTE_DEVICE_NOT_FOUND => "the smart card or token isn't available", NTE_USER_CANCELLED => "the request was cancelled", @@ -240,6 +246,11 @@ mod tests { "the key is missing from its key store (deleted, or imported under another Windows account) (Windows error 0x80090016)" ); assert_eq!(describe(&CngError::WindowsError(0x8010_000C)), "the smart card isn't available (Windows error 0x8010000C)"); + assert_eq!( + describe(&CngError::WindowsError(0x8009_001D)), + "its key provider's software failed to load (a smart card or token driver that is missing or broken, or a 32-bit-only provider) (Windows error 0x8009001D)", + "#2207" + ); assert_eq!(describe(&CngError::WindowsError(0x57)), "Windows error 0x00000057"); assert_eq!(describe(&CngError::InvalidHashLength), "Invalid hash length"); } From 5b813ce9857c854806c9919dfebc797b9d5f3e0e Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sat, 17 Oct 2026 16:39:54 +0800 Subject: [PATCH 2/2] fix(sign): explain 0xC0000225 when a token's key provider can't find the key (#1535) STATUS_NOT_FOUND passed through by a smart card or token provider (an A3 certificate whose token isn't connected) was shown as a bare code. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz --- crates/sign/src/windows.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/sign/src/windows.rs b/crates/sign/src/windows.rs index b63d49cd0..cea93715f 100644 --- a/crates/sign/src/windows.rs +++ b/crates/sign/src/windows.rs @@ -209,6 +209,8 @@ const NTE_DEVICE_NOT_READY: u32 = 0x8009_0030; const NTE_DEVICE_NOT_FOUND: u32 = 0x8009_0035; const NTE_USER_CANCELLED: u32 = 0x8009_0036; const CRYPT_E_NO_KEY_PROPERTY: u32 = 0x8009_200B; +// An NTSTATUS (ntstatus.h) that some key providers pass through unchanged. +const STATUS_NOT_FOUND: u32 = 0xC000_0225; /// A CNG error with the Windows code and, for the usual ones, what it means. fn describe(e: &CngError) -> String { @@ -224,6 +226,10 @@ fn describe(e: &CngError) -> String { NTE_PROVIDER_DLL_FAIL => { "its key provider's software failed to load (a smart card or token driver that is missing or broken, or a 32-bit-only provider)" } + // #1535: an A3 certificate (key on a token) whose provider can't find the key. + STATUS_NOT_FOUND => { + "its key provider can't find the key (the smart card or token holding it isn't connected, or its driver doesn't see the key)" + } NTE_NOT_SUPPORTED => "its key provider doesn't support the operation", NTE_DEVICE_NOT_READY | NTE_DEVICE_NOT_FOUND => "the smart card or token isn't available", NTE_USER_CANCELLED => "the request was cancelled", @@ -251,6 +257,11 @@ mod tests { "its key provider's software failed to load (a smart card or token driver that is missing or broken, or a 32-bit-only provider) (Windows error 0x8009001D)", "#2207" ); + assert_eq!( + describe(&CngError::WindowsError(0xC000_0225)), + "its key provider can't find the key (the smart card or token holding it isn't connected, or its driver doesn't see the key) (Windows error 0xC0000225)", + "#1535" + ); assert_eq!(describe(&CngError::WindowsError(0x57)), "Windows error 0x00000057"); assert_eq!(describe(&CngError::InvalidHashLength), "Invalid hash length"); }