-
Notifications
You must be signed in to change notification settings - Fork 30
Add store-location=machine URI option for Windows machine key store #1006
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
4ae9047
ffcc3a2
ba8ac52
bd95378
64eab7f
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 |
|---|---|---|
|
|
@@ -35,6 +35,9 @@ const ( | |
| // The below is documented in this Microsoft whitepaper: | ||
| // https://github.com/Microsoft/TSS.MSR/blob/master/PCPTool.v11/Using%20the%20Windows%208%20Platform%20Crypto%20Provider%20and%20Associated%20TPM%20Functionality.pdf | ||
| ncryptOverwriteKeyFlag = 0x80 | ||
| // ncryptMachineKeyFlag instructs NCrypt to create or open a key in the | ||
| // machine (local machine) key store rather than the current user key store. | ||
| ncryptMachineKeyFlag uint32 = 0x00000020 | ||
| // Key usage value for generic keys | ||
| nCryptPropertyPCPKeyUsagePolicyGeneric = 0x3 | ||
| // Key usage value for AKs. | ||
|
|
@@ -282,7 +285,8 @@ func getNCryptBufferProperty(hnd uintptr, field string) ([]byte, error) { | |
|
|
||
| // winPCP represents a reference to the Platform Crypto Provider. | ||
| type winPCP struct { | ||
| hProv uintptr | ||
| hProv uintptr | ||
| machineKey bool | ||
| } | ||
|
|
||
| // Close releases all resources managed by the Handle. | ||
|
|
@@ -301,8 +305,13 @@ func (h *winPCP) newKey(name string, alg string, length uint32, policy uint32) ( | |
| return 0, nil, nil, err | ||
| } | ||
|
|
||
| var flags uint32 | ||
| if h.machineKey { | ||
| flags = ncryptMachineKeyFlag | ||
| } | ||
|
|
||
| // Create a persistent RSA key of the specified name. | ||
| r, _, msg := nCryptCreatePersistedKey.Call(h.hProv, uintptr(unsafe.Pointer(&kh)), uintptr(unsafe.Pointer(&utf16RSA[0])), uintptr(unsafe.Pointer(&utf16Name[0])), 0, 0) | ||
| r, _, msg := nCryptCreatePersistedKey.Call(h.hProv, uintptr(unsafe.Pointer(&kh)), uintptr(unsafe.Pointer(&utf16RSA[0])), uintptr(unsafe.Pointer(&utf16Name[0])), 0, uintptr(flags)) | ||
| if r != 0 { | ||
| if tpmErr := maybeWinErr(r); tpmErr != nil { | ||
| msg = tpmErr | ||
|
|
@@ -491,10 +500,13 @@ func decodeKeyBlob(keyBlob []byte) ([]byte, []byte, error) { | |
| } | ||
|
|
||
| // openPCP initializes a reference to the Microsoft PCP provider. | ||
| // Pass machineKey=true to create and open keys in the machine (local machine) | ||
| // key store rather than the current user key store. | ||
| // The Caller is expected to call Close() when they are done. | ||
| func openPCP() (*winPCP, error) { | ||
| func openPCP(machineKey bool) (*winPCP, error) { | ||
|
Member
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. Instead of passing this via |
||
| var err error | ||
| var h winPCP | ||
| h.machineKey = machineKey | ||
| pname, err := windows.UTF16FromString(pcpProviderName) | ||
| if err != nil { | ||
| return nil, err | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -186,8 +186,9 @@ func (t *TPM) CreateKey(ctx context.Context, name string, config CreateKeyConfig | |
| } | ||
|
|
||
| createConfig := internalkey.CreateConfig{ | ||
| Algorithm: config.Algorithm, | ||
| Size: config.Size, | ||
| Algorithm: config.Algorithm, | ||
| Size: config.Size, | ||
| MachineKey: t.options.attestConfig.MachineKey, | ||
| } | ||
| if err := t.validate(&createConfig); err != nil { | ||
| return nil, fmt.Errorf("invalid key creation parameters: %w", err) | ||
|
|
@@ -386,8 +387,12 @@ func (t *TPM) DeleteKey(ctx context.Context, name string) (err error) { | |
| return fmt.Errorf("failed getting key %q: %w", name, err) | ||
| } | ||
|
|
||
| var attestErr error | ||
| if err := t.attestTPM.DeleteKey(key.Data); err != nil { | ||
| return fmt.Errorf("failed deleting key %q: %w", name, err) | ||
| // Preserve the PCP error but still clean up file-store metadata below. | ||
| // On Windows the PCP key may be inaccessible when the reset command runs | ||
| // in a different session than the agent service that created the key. | ||
| attestErr = fmt.Errorf("failed deleting key %q: %w", name, err) | ||
| } | ||
|
|
||
| if err := t.store.DeleteKey(name); err != nil { | ||
|
|
@@ -398,7 +403,7 @@ func (t *TPM) DeleteKey(ctx context.Context, name string) (err error) { | |
| return fmt.Errorf("failed persisting storage: %w", err) | ||
| } | ||
|
|
||
| return | ||
| return attestErr | ||
|
Member
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. See the remark for the other case |
||
| } | ||
|
|
||
| // Signer returns a crypto.Signer backed by the Key. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -96,6 +96,17 @@ func WithCommandChannel(commandChannel CommandChannel) NewTPMOption { | |
| } | ||
| } | ||
|
|
||
| // WithMachineKey configures the TPM to create and open keys in the machine | ||
| // (local machine) key store rather than the current user key store. On Windows | ||
| // this causes NCRYPT_MACHINE_KEY_FLAG to be passed to NCrypt key operations. | ||
| // This option has no effect on non-Windows platforms. | ||
| func WithMachineKey() NewTPMOption { | ||
| return func(o *options) error { | ||
| o.attestConfig.MachineKey = true | ||
| return nil | ||
| } | ||
| } | ||
|
|
||
|
Member
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. This option will affect operations on all keys going through the specific |
||
| // WithCapabilities explicitly sets the capabilities rather | ||
| // than acquiring them from the TPM directly. The primary use | ||
| // for this option is to ease testing different TPM capabilities. | ||
|
|
@@ -241,6 +252,7 @@ func (t *TPM) initializeCommandChannel() error { | |
| t.attestConfig = &attest.OpenConfig{ | ||
| TPMVersion: t.options.attestConfig.TPMVersion, | ||
| CommandChannel: t.commandChannel, | ||
| MachineKey: t.options.attestConfig.MachineKey, | ||
|
Member
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 option probably shouldn't sit on |
||
| } | ||
| return nil | ||
| } | ||
|
|
@@ -275,6 +287,7 @@ func (t *TPM) initializeCommandChannel() error { | |
| t.attestConfig = &attest.OpenConfig{ | ||
| TPMVersion: t.options.attestConfig.TPMVersion, | ||
| CommandChannel: t.commandChannel, | ||
| MachineKey: t.options.attestConfig.MachineKey, | ||
| } | ||
|
|
||
| return nil | ||
|
|
||
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.
Is the goal to be able to act on this error case? A typed error might help.