-
Notifications
You must be signed in to change notification settings - Fork 32
Do not return error if CAPI SW key is found but CNG is not locatable #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -335,6 +335,9 @@ type WinCertStoreOptions struct { | |
| // - certStoreCreateNewFlag: Create new store if it doesn't exist | ||
| // - certStoreOpenExistingFlag: Only open existing stores | ||
| StoreFlags uint32 | ||
|
|
||
| // IgnoreNoCNG can be set in order to ignore a not found CNG key when a CAPI key exists. | ||
| IgnoreNoCNG bool | ||
| } | ||
|
|
||
| // WinCertStore is a CertStorage implementation for the Windows Certificate Store. | ||
|
|
@@ -349,6 +352,7 @@ type WinCertStore struct { | |
| stores map[string]*storeHandle | ||
| keyAccessFlags uintptr | ||
| storeFlags uint32 | ||
| ignoreNoCNG bool | ||
|
|
||
| mu sync.Mutex | ||
| } | ||
|
|
@@ -375,6 +379,7 @@ func DefaultWinCertStoreOptions(provider, container string, issuers, intermediat | |
| LegacyKey: legacyKey, | ||
| CurrentUser: false, | ||
| StoreFlags: 0, | ||
| IgnoreNoCNG: false, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -442,6 +447,7 @@ func OpenWinCertStoreWithOptions(opts WinCertStoreOptions) (*WinCertStore, error | |
| container: opts.Container, | ||
| stores: make(map[string]*storeHandle), | ||
| storeFlags: opts.StoreFlags, | ||
| ignoreNoCNG: opts.IgnoreNoCNG, | ||
| } | ||
|
|
||
| // Deep copy the issuer slices to prevent external modification | ||
|
|
@@ -1369,6 +1375,11 @@ func keyMetadata(kh uintptr, store *WinCertStore) (*Key, error) { | |
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if !store.ignoreNoCNG && uc == "" { | ||
| // key is not CNG backed, but store was opened with ignoreNoCNG=false | ||
| return nil, errors.New("CNG key was empty") | ||
| } | ||
| } | ||
|
|
||
| alg, err := getPropertyStr(kh, nCryptAlgorithmGroupProperty) | ||
|
|
@@ -1745,9 +1756,6 @@ func softwareKeyContainers(uniqueID string, storeDomain uint32) (string, string, | |
| if err != nil { | ||
| return "", "", fmt.Errorf("unable to locate CNG key: %v", err) | ||
| } | ||
| if cng == "" { | ||
| return "", "", errors.New("CNG key was empty") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add some log for this case?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if emitting logs from a package used as a library is the right way to do it (unexpected stdout/stderr, formatting differences, log vs. slog etc.).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Casual search says following cases will not work with CAPI keys.
I am not expert with these solutions and cannot say for certain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One other thought is that this could be skipped via an option in the WinCertStoreOptions. That way if something is relying on this behavior it won't break. Also FWIW, using non-exported keys has been a pain due to this so this change would massively improve that usability. It would be fairly easy to:
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the idea using
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just added the |
||
| } | ||
| default: | ||
| return "", "", fmt.Errorf("unexpected key type %q", keyType) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this fix be made at
certtostore/certtostore_windows.go
Line 1744 in ee4ff6f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
softwareKeyContainerswill return an empty string if the CNG key couldn't be located. An error will only be returned ifkeyMatchgets an error fromos.Statorioutil.ReadDircall. Therefore it returns whatever is available without being smart.Consequently I decided to leave the
softwareKeyContainersfunction as-is and to delegate the judgement of returning an error on no-CNG-key up to the callerkeyMetadata. I'm not sure if there are other callers of those functions hidden by copybara.Hope this explains why I implemented it this way but I might be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keyMatchis just a generic helper: it takes a known key file path and a directory, then tries to find a “matching” key by timestamp. Its contract is:On success: returns the matching path.
If it can’t find a match: returns "" and nil error.
On real failure (stat/ReadDir issues): returns "" and a non‑nil error.
It has no notion of CNG vs CAPI, or what “missing is acceptable” means. It only knows “found” / “not found” / “hard failure”.
softwareKeyContainersis where the CAPI vs CNG checks exist.Keep
keyMatchas a low‑level primitive as is. AdjustsoftwareKeyContainerspolicy.A missing CNG match (cng == "") is treated the same way as we treat missing CAPI when starting from CNG.