Hi @Goce Terziev ,
Thank you for the clear write up and questions. After reviewing the available Microsoft documentations, here are my answers:
1. Which exact ACE bits authorize NCryptSignHash?
The Microsoft references reviewed do not specify Software KSP’s signing ACE mask or its GENERIC_MAPPING. Neither NCryptSignHash nor NCryptOpenKey identifies the access bits checked.
-
NCRYPT_ALLOW_SIGNING_FLAG = 0x00000002is a key-usage flag, not an ACE right. See Key Storage Property Identifiers. - Generic rights are
GENERIC_READ = 0x80000000,GENERIC_WRITE = 0x40000000,GENERIC_EXECUTE = 0x20000000, andGENERIC_ALL = 0x10000000. Their meaning requires an object-specific mapping; a file mapping is not a documented Software KSP signing contract. See Generic Access Rights.
2. Which rights govern security-descriptor access? The standard Windows rights are:
- Read owner/group/DACL:
READ_CONTROL = 0x00020000. - Modify DACL:
WRITE_DAC = 0x00040000. - Change owner:
WRITE_OWNER = 0x00080000.
See ACCESSMASK and SECURITYINFORMATION. These definitions do not establish Software KSP’s complete provider-specific authorization checks. NCryptGetProperty and NCryptSetProperty document the security-information selectors, but not a complete rights mapping.
3. What does 0xD01F01FF mean?
It contains:
-
GENERIC_READ | GENERIC_WRITE | GENERIC_ALL. -
STANDARD_RIGHTS_ALL, includingREAD_CONTROL,WRITE_DAC, andWRITE_OWNER. - Object-specific bits
0x01FF.
It explicitly contains DACL-modification rights, so it is unsuitable as a least-privilege candidate for your requirement. Its signing meaning cannot be confirmed without the provider-specific mapping. See ACCESS_MASK and Generic Access Rights.
4. Should the protected DACL be applied before or after finalization?
The reviewed documentation does not establish the exact protected-DACL sequence requested.
- The general lifecycle is Create → Set properties → Finalize, with
NCRYPT_MACHINE_KEY_FLAGselecting machine scope. See NCryptCreatePersistedKey and NCryptFinalizeKey. - NCryptSetProperty documents
DACL_SECURITY_INFORMATION, but does not explicitly establish protected-DACL persistence or exclusive before/after-finalization ordering. -
SE_DACL_PROTECTEDprevents inherited ACE changes. It does not prevent authorized DACL modification. The separatePROTECTED_DACL_SECURITY_INFORMATIONflag is not listed among NCrypt’s documented selectors. See Security Descriptor Control.
5. Does descriptor read-back prove signing enforcement?
No. NCryptGetProperty retrieves the descriptor; its contract does not establish which permissions NCryptSignHash enforces.
Actual signing tests can provide operational evidence. Security event 5061 additionally documents Software KSP operation details, including identity, key, operation and return code.
6. How should service isolation be verified?
The following acceptance cases are suggested for testing on disposable keys, using fresh processes under the actual service identities:
- Service A: Sign key A successfully; deny signing key B; deny modification of either DACL.
- Service B: Sign key B successfully; deny signing key A; deny modification of either DACL.
Log opening and signing separately, generate actual signatures rather than only querying buffer size, and test DACL changes using valid replacement descriptors. This is a proposed validation procedure, not an engineering-confirmed mapping.
The APIs are documented in NCryptOpenKey, NCryptSignHash, NCryptVerifySignature, and NCryptSetProperty.
For the missing authoritative mapping and protected-DACL lifecycle contract, I recommend opening a support request with Microsoft through Support for Business. If you do not have a business support plan, you can contact Microsoft Support instead.
I hope this helps answering your questions. If you find my response helpful, I would greatly appreciate it if you could follow the guide here so others experiencing similar behavior or issue can benefit from it as well.