mirror of https://github.com/kubernetes/kops.git
Update vendor
This commit is contained in:
parent
4dc2c062fd
commit
d74c3b7792
|
@ -0,0 +1,297 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
IBM simulator code (in tpm2-simulator/) uses the following license:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
(c) Copyright IBM Corporation 2016.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither the names of the IBM Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
A portion of the source code is derived from the TPM specification,
|
||||
which has a TCG copyright. It is reproduced here for reference.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Licenses and Notices
|
||||
Copyright Licenses:
|
||||
|
||||
* Trusted Computing Group (TCG) grants to the user of the source code
|
||||
in this specification (the "Source Code") a worldwide, irrevocable,
|
||||
nonexclusive, royalty free, copyright license to reproduce, create
|
||||
derivative works, distribute, display and perform the Source Code and
|
||||
derivative works thereof, and to grant others the rights granted
|
||||
herein.
|
||||
|
||||
* The TCG grants to the user of the other parts of the specification
|
||||
(other than the Source Code) the rights to reproduce, distribute,
|
||||
display, and perform the specification solely for the purpose of
|
||||
developing products based on such documents.
|
||||
|
||||
Source Code Distribution Conditions:
|
||||
|
||||
* Redistributions of Source Code must retain the above copyright
|
||||
licenses, this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
licenses, this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
Disclaimers:
|
||||
|
||||
* THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF
|
||||
LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH
|
||||
RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)
|
||||
THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR
|
||||
OTHERWISE. Contact TCG Administration
|
||||
(admin@trustedcomputinggroup.org) for information on specification
|
||||
licensing rights available through TCG membership agreements.
|
||||
|
||||
* THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED
|
||||
WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR
|
||||
FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR
|
||||
NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY
|
||||
OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.
|
||||
|
||||
* Without limitation, TCG and its members and licensors disclaim all
|
||||
liability, including liability for infringement of any proprietary
|
||||
rights, relating to use of information in this specification and to
|
||||
the implementation of this specification, and TCG disclaims all
|
||||
liability for cost of procurement of substitute goods or services,
|
||||
lost profits, loss of use, loss of data or any incidental,
|
||||
consequential, direct, indirect, or special damages, whether under
|
||||
contract, tort, warranty or otherwise, arising in any way out of use
|
||||
or reliance upon this specification or any information herein.
|
||||
|
||||
Any marks and brands contained herein are the property of their
|
||||
respective owners.
|
|
@ -0,0 +1,29 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"attest.go",
|
||||
"close.go",
|
||||
"eventlog.go",
|
||||
"eventlog_linux.go",
|
||||
"eventlog_other.go",
|
||||
"handles.go",
|
||||
"import.go",
|
||||
"keys.go",
|
||||
"pcr.go",
|
||||
"session.go",
|
||||
"signer.go",
|
||||
"template.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm-tools/client",
|
||||
importpath = "github.com/google/go-tpm-tools/client",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/go-tpm-tools/internal:go_default_library",
|
||||
"//vendor/github.com/google/go-tpm-tools/proto/attest:go_default_library",
|
||||
"//vendor/github.com/google/go-tpm-tools/proto/tpm:go_default_library",
|
||||
"//vendor/github.com/google/go-tpm/tpm2:go_default_library",
|
||||
"//vendor/github.com/google/go-tpm/tpmutil:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,57 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
pb "github.com/google/go-tpm-tools/proto/attest"
|
||||
)
|
||||
|
||||
// AttestOpts allows for customizing the functionality of Attest.
|
||||
type AttestOpts struct {
|
||||
// A unique, application-specific nonce used to guarantee freshness of the
|
||||
// attestation. This must not be empty, and should generally be long enough
|
||||
// to make brute force attacks infeasible.
|
||||
//
|
||||
// For security reasons, applications should not allow for attesting with
|
||||
// arbitrary, externally-provided nonces. The nonce should be prefixed or
|
||||
// otherwise bound (i.e. via a KDF) to application-specific data. For more
|
||||
// information on why this is an issue, see this paper on robust remote
|
||||
// attestation protocols:
|
||||
// https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4562&rep=rep1&type=pdf
|
||||
Nonce []byte
|
||||
}
|
||||
|
||||
// Attest generates an Attestation containing the TCG Event Log and a Quote over
|
||||
// all PCR banks. The provided nonce can be used to guarantee freshness of the
|
||||
// attestation. This function will return an error if the key is not a
|
||||
// restricted signing key.
|
||||
//
|
||||
// AttestOpts is used for additional configuration of the Attestation process.
|
||||
// This is primarily used to pass the attestation's nonce:
|
||||
//
|
||||
// attestation, err := key.Attest(client.AttestOpts{Nonce: my_nonce})
|
||||
func (k *Key) Attest(opts AttestOpts) (*pb.Attestation, error) {
|
||||
if len(opts.Nonce) == 0 {
|
||||
return nil, fmt.Errorf("provided nonce must not be empty")
|
||||
}
|
||||
sels, err := implementedPCRs(k.rw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestation := pb.Attestation{}
|
||||
if attestation.AkPub, err = k.PublicArea().Encode(); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode public area: %w", err)
|
||||
}
|
||||
for _, sel := range sels {
|
||||
quote, err := k.Quote(sel, opts.Nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
attestation.Quotes = append(attestation.Quotes, quote)
|
||||
}
|
||||
if attestation.EventLog, err = GetEventLog(k.rw); err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve TCG Event Log: %w", err)
|
||||
}
|
||||
return &attestation, nil
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// CheckedClose closes the simulator and asserts that there were no leaked handles.
|
||||
func CheckedClose(tb testing.TB, rwc io.ReadWriteCloser) {
|
||||
for _, t := range []tpm2.HandleType{
|
||||
tpm2.HandleTypeLoadedSession,
|
||||
tpm2.HandleTypeSavedSession,
|
||||
tpm2.HandleTypeTransient,
|
||||
} {
|
||||
handles, err := Handles(rwc, t)
|
||||
if err != nil {
|
||||
tb.Errorf("failed to fetch handles of type %v: %v", t, err)
|
||||
}
|
||||
if len(handles) != 0 {
|
||||
tb.Errorf("tests leaked handles: %v", handles)
|
||||
}
|
||||
}
|
||||
|
||||
if err := rwc.Close(); err != nil {
|
||||
tb.Errorf("when closing simulator: %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package client
|
||||
|
||||
import "io"
|
||||
|
||||
// GetEventLog grabs the crypto-agile TCG event log for the system. The TPM can
|
||||
// override this implementation by implementing EventLogGetter.
|
||||
func GetEventLog(rw io.ReadWriter) ([]byte, error) {
|
||||
if elg, ok := rw.(EventLogGetter); ok {
|
||||
return elg.EventLog()
|
||||
}
|
||||
return getRealEventLog()
|
||||
}
|
||||
|
||||
// EventLogGetter allows a TPM (io.ReadWriter) to specify a particular
|
||||
// implementation for GetEventLog(). This is useful for testing and necessary
|
||||
// for Windows Event Log support (which requires a handle to the TPM).
|
||||
type EventLogGetter interface {
|
||||
EventLog() ([]byte, error)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func getRealEventLog() ([]byte, error) {
|
||||
return ioutil.ReadFile("/sys/kernel/security/tpm0/binary_bios_measurements")
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package client
|
||||
|
||||
import "errors"
|
||||
|
||||
func getRealEventLog() ([]byte, error) {
|
||||
return nil, errors.New("failed to get event log: only Linux supported")
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
// Reserved Handles from "TCG TPM v2.0 Provisioning Guidance" - v1r1 - Table 2
|
||||
const (
|
||||
EKReservedHandle = tpmutil.Handle(0x81010001)
|
||||
EKECCReservedHandle = tpmutil.Handle(0x81010002)
|
||||
SRKReservedHandle = tpmutil.Handle(0x81000001)
|
||||
SRKECCReservedHandle = tpmutil.Handle(0x81000002)
|
||||
)
|
||||
|
||||
// Picked available handles from TPM 2.0 Handles and Localities 2.3.1 - Table 11
|
||||
// go-tpm-tools will use handles in the range from 0x81008F00 to 0x81008FFF
|
||||
const (
|
||||
DefaultAKECCHandle = tpmutil.Handle(0x81008F00)
|
||||
DefaultAKRSAHandle = tpmutil.Handle(0x81008F01)
|
||||
)
|
||||
|
||||
// NV Indices holding GCE AK Templates
|
||||
const (
|
||||
GceAKTemplateNVIndexRSA uint32 = 0x01c10001
|
||||
GceAKTemplateNVIndexECC uint32 = 0x01c10003
|
||||
)
|
||||
|
||||
func isHierarchy(h tpmutil.Handle) bool {
|
||||
return h == tpm2.HandleOwner || h == tpm2.HandleEndorsement ||
|
||||
h == tpm2.HandlePlatform || h == tpm2.HandleNull
|
||||
}
|
||||
|
||||
// Handles returns a slice of tpmutil.Handle objects of all handles within
|
||||
// the TPM rw of type handleType.
|
||||
func Handles(rw io.ReadWriter, handleType tpm2.HandleType) ([]tpmutil.Handle, error) {
|
||||
// Handle type is determined by the most-significant octet (MSO) of the property.
|
||||
property := uint32(handleType) << 24
|
||||
|
||||
vals, moreData, err := tpm2.GetCapability(rw, tpm2.CapabilityHandles, math.MaxUint32, property)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if moreData {
|
||||
return nil, fmt.Errorf("tpm2.GetCapability() should never return moreData==true for tpm2.CapabilityHandles")
|
||||
}
|
||||
handles := make([]tpmutil.Handle, len(vals))
|
||||
for i, v := range vals {
|
||||
handle, ok := v.(tpmutil.Handle)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to assert type tpmutil.Handle of value %#v", v)
|
||||
}
|
||||
handles[i] = handle
|
||||
}
|
||||
return handles, nil
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-tpm-tools/internal"
|
||||
pb "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
func loadHandle(k *Key, blob *pb.ImportBlob) (tpmutil.Handle, error) {
|
||||
auth, err := k.session.Auth()
|
||||
if err != nil {
|
||||
return tpm2.HandleNull, err
|
||||
}
|
||||
private, err := tpm2.Import(k.rw, k.Handle(), auth, blob.PublicArea, blob.Duplicate, blob.EncryptedSeed, nil, nil)
|
||||
if err != nil {
|
||||
return tpm2.HandleNull, fmt.Errorf("import failed: %w", err)
|
||||
}
|
||||
|
||||
auth, err = k.session.Auth()
|
||||
if err != nil {
|
||||
return tpm2.HandleNull, err
|
||||
}
|
||||
handle, _, err := tpm2.LoadUsingAuth(k.rw, k.Handle(), auth, blob.PublicArea, private)
|
||||
if err != nil {
|
||||
return tpm2.HandleNull, fmt.Errorf("load failed: %w", err)
|
||||
}
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// Import decrypts the secret contained in an encoded import request.
|
||||
// The key used must be an encryption key (signing keys cannot be used).
|
||||
// The req parameter should come from server.CreateImportBlob.
|
||||
func (k *Key) Import(blob *pb.ImportBlob) ([]byte, error) {
|
||||
handle, err := loadHandle(k, blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tpm2.FlushContext(k.rw, handle)
|
||||
|
||||
unsealSession, err := newPCRSession(k.rw, internal.PCRSelection(blob.Pcrs))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer unsealSession.Close()
|
||||
|
||||
auth, err := unsealSession.Auth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := tpm2.UnsealWithSession(k.rw, auth.Session, handle, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unseal failed: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ImportSigningKey returns the signing key contained in an encoded import request.
|
||||
// The parent key must be an encryption key (signing keys cannot be used).
|
||||
// The req parameter should come from server.CreateSigningKeyImportBlob.
|
||||
func (k *Key) ImportSigningKey(blob *pb.ImportBlob) (key *Key, err error) {
|
||||
handle, err := loadHandle(k, blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key = &Key{rw: k.rw, handle: handle}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
key.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if key.pubArea, _, _, err = tpm2.ReadPublic(k.rw, handle); err != nil {
|
||||
return
|
||||
}
|
||||
if key.session, err = newPCRSession(k.rw, internal.PCRSelection(blob.Pcrs)); err != nil {
|
||||
return
|
||||
}
|
||||
return key, key.finish()
|
||||
}
|
|
@ -0,0 +1,429 @@
|
|||
// Package client contains some high-level TPM 2.0 functions.
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/google/go-tpm-tools/internal"
|
||||
pb "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
// Key wraps an active asymmetric TPM2 key. This can either be a signing key or
|
||||
// an encryption key. Users of Key should be sure to call Close() when the Key
|
||||
// is no longer needed, so that the underlying TPM handle can be freed.
|
||||
type Key struct {
|
||||
rw io.ReadWriter
|
||||
handle tpmutil.Handle
|
||||
pubArea tpm2.Public
|
||||
pubKey crypto.PublicKey
|
||||
name tpm2.Name
|
||||
session session
|
||||
}
|
||||
|
||||
// EndorsementKeyRSA generates and loads a key from DefaultEKTemplateRSA.
|
||||
func EndorsementKeyRSA(rw io.ReadWriter) (*Key, error) {
|
||||
return NewCachedKey(rw, tpm2.HandleEndorsement, DefaultEKTemplateRSA(), EKReservedHandle)
|
||||
}
|
||||
|
||||
// EndorsementKeyECC generates and loads a key from DefaultEKTemplateECC.
|
||||
func EndorsementKeyECC(rw io.ReadWriter) (*Key, error) {
|
||||
return NewCachedKey(rw, tpm2.HandleEndorsement, DefaultEKTemplateECC(), EKECCReservedHandle)
|
||||
}
|
||||
|
||||
// StorageRootKeyRSA generates and loads a key from SRKTemplateRSA.
|
||||
func StorageRootKeyRSA(rw io.ReadWriter) (*Key, error) {
|
||||
return NewCachedKey(rw, tpm2.HandleOwner, SRKTemplateRSA(), SRKReservedHandle)
|
||||
}
|
||||
|
||||
// StorageRootKeyECC generates and loads a key from SRKTemplateECC.
|
||||
func StorageRootKeyECC(rw io.ReadWriter) (*Key, error) {
|
||||
return NewCachedKey(rw, tpm2.HandleOwner, SRKTemplateECC(), SRKECCReservedHandle)
|
||||
}
|
||||
|
||||
// AttestationKeyRSA generates and loads a key from AKTemplateRSA in the Owner hierarchy.
|
||||
func AttestationKeyRSA(rw io.ReadWriter) (*Key, error) {
|
||||
return NewCachedKey(rw, tpm2.HandleOwner, AKTemplateRSA(), DefaultAKRSAHandle)
|
||||
}
|
||||
|
||||
// AttestationKeyECC generates and loads a key from AKTemplateECC in the Owner hierarchy.
|
||||
func AttestationKeyECC(rw io.ReadWriter) (*Key, error) {
|
||||
return NewCachedKey(rw, tpm2.HandleOwner, AKTemplateECC(), DefaultAKECCHandle)
|
||||
}
|
||||
|
||||
// EndorsementKeyFromNvIndex generates and loads an endorsement key using the
|
||||
// template stored at the provided nvdata index. This is useful for TPMs which
|
||||
// have a preinstalled AK template.
|
||||
func EndorsementKeyFromNvIndex(rw io.ReadWriter, idx uint32) (*Key, error) {
|
||||
return KeyFromNvIndex(rw, tpm2.HandleEndorsement, idx)
|
||||
}
|
||||
|
||||
// GceAttestationKeyRSA generates and loads the GCE RSA AK. Note that this
|
||||
// function will only work on a GCE VM. Unlike AttestationKeyRSA, this key uses
|
||||
// the Endorsement Hierarchy and its template loaded from GceAKTemplateNVIndexRSA.
|
||||
func GceAttestationKeyRSA(rw io.ReadWriter) (*Key, error) {
|
||||
return EndorsementKeyFromNvIndex(rw, GceAKTemplateNVIndexRSA)
|
||||
}
|
||||
|
||||
// GceAttestationKeyECC generates and loads the GCE ECC AK. Note that this
|
||||
// function will only work on a GCE VM. Unlike AttestationKeyECC, this key uses
|
||||
// the Endorsement Hierarchy and its template loaded from GceAKTemplateNVIndexECC.
|
||||
func GceAttestationKeyECC(rw io.ReadWriter) (*Key, error) {
|
||||
return EndorsementKeyFromNvIndex(rw, GceAKTemplateNVIndexECC)
|
||||
}
|
||||
|
||||
// KeyFromNvIndex generates and loads a key under the provided parent
|
||||
// (possibly a hierarchy root tpm2.Handle{Owner|Endorsement|Platform|Null})
|
||||
// using the template stored at the provided nvdata index.
|
||||
func KeyFromNvIndex(rw io.ReadWriter, parent tpmutil.Handle, idx uint32) (*Key, error) {
|
||||
data, err := tpm2.NVReadEx(rw, tpmutil.Handle(idx), tpm2.HandleOwner, "", 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read error at index %d: %w", idx, err)
|
||||
}
|
||||
template, err := tpm2.DecodePublic(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("index %d data was not a TPM key template: %w", idx, err)
|
||||
}
|
||||
return NewKey(rw, parent, template)
|
||||
}
|
||||
|
||||
// NewCachedKey is almost identical to NewKey, except that it initially tries to
|
||||
// see if the a key matching the provided template is at cachedHandle. If so,
|
||||
// that key is returned. If not, the key is created as in NewKey, and that key
|
||||
// is persisted to the cachedHandle, overwriting any existing key there.
|
||||
func NewCachedKey(rw io.ReadWriter, parent tpmutil.Handle, template tpm2.Public, cachedHandle tpmutil.Handle) (k *Key, err error) {
|
||||
owner := tpm2.HandleOwner
|
||||
if parent == tpm2.HandlePlatform {
|
||||
owner = tpm2.HandlePlatform
|
||||
} else if parent == tpm2.HandleNull {
|
||||
return nil, fmt.Errorf("cannot cache objects in the null hierarchy")
|
||||
}
|
||||
|
||||
cachedPub, _, _, err := tpm2.ReadPublic(rw, cachedHandle)
|
||||
if err == nil {
|
||||
if cachedPub.MatchesTemplate(template) {
|
||||
k = &Key{rw: rw, handle: cachedHandle, pubArea: cachedPub}
|
||||
return k, k.finish()
|
||||
}
|
||||
// Kick out old cached key if it does not match
|
||||
if err = tpm2.EvictControl(rw, "", owner, cachedHandle, cachedHandle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
k, err = NewKey(rw, parent, template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tpm2.FlushContext(rw, k.handle)
|
||||
|
||||
if err = tpm2.EvictControl(rw, "", owner, k.handle, cachedHandle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.handle = cachedHandle
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// NewKey generates a key from the template and loads that key into the TPM
|
||||
// under the specified parent. NewKey can call many different TPM commands:
|
||||
// - If parent is tpm2.Handle{Owner|Endorsement|Platform|Null} a primary key
|
||||
// is created in the specified hierarchy (using CreatePrimary).
|
||||
// - If parent is a valid key handle, a normal key object is created under
|
||||
// that parent (using Create and Load). NOTE: Not yet supported.
|
||||
// This function also assumes that the desired key:
|
||||
// - Does not have its usage locked to specific PCR values
|
||||
// - Usable with empty authorization sessions (i.e. doesn't need a password)
|
||||
func NewKey(rw io.ReadWriter, parent tpmutil.Handle, template tpm2.Public) (k *Key, err error) {
|
||||
if !isHierarchy(parent) {
|
||||
// TODO add support for normal objects with Create() and Load()
|
||||
return nil, fmt.Errorf("unsupported parent handle: %x", parent)
|
||||
}
|
||||
|
||||
handle, pubArea, _, _, _, _, err :=
|
||||
tpm2.CreatePrimaryEx(rw, parent, tpm2.PCRSelection{}, "", "", template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tpm2.FlushContext(rw, handle)
|
||||
}
|
||||
}()
|
||||
|
||||
k = &Key{rw: rw, handle: handle}
|
||||
if k.pubArea, err = tpm2.DecodePublic(pubArea); err != nil {
|
||||
return
|
||||
}
|
||||
return k, k.finish()
|
||||
}
|
||||
|
||||
func (k *Key) finish() error {
|
||||
var err error
|
||||
if k.pubKey, err = k.pubArea.Key(); err != nil {
|
||||
return err
|
||||
}
|
||||
if k.name, err = k.pubArea.Name(); err != nil {
|
||||
return err
|
||||
}
|
||||
// We determine the right type of session based on the auth policy
|
||||
if k.session == nil {
|
||||
if bytes.Equal(k.pubArea.AuthPolicy, defaultEKAuthPolicy()) {
|
||||
if k.session, err = newEKSession(k.rw); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(k.pubArea.AuthPolicy) == 0 {
|
||||
k.session = nullSession{}
|
||||
} else {
|
||||
return fmt.Errorf("unknown auth policy when creating key")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle allows this key to be used directly with other go-tpm commands.
|
||||
func (k *Key) Handle() tpmutil.Handle {
|
||||
return k.handle
|
||||
}
|
||||
|
||||
// Name is hash of this key's public area. Only the Digest field will ever be
|
||||
// populated. It is useful for various TPM commands related to authorization.
|
||||
// This is equivalent to k.PublicArea.Name(), except that is cannot fail.
|
||||
func (k *Key) Name() tpm2.Name {
|
||||
return k.name
|
||||
}
|
||||
|
||||
// PublicArea exposes the key's entire public area. This is useful for
|
||||
// determining additional properties of the underlying TPM key.
|
||||
func (k *Key) PublicArea() tpm2.Public {
|
||||
return k.pubArea
|
||||
}
|
||||
|
||||
// PublicKey provides a go interface to the loaded key's public area.
|
||||
func (k *Key) PublicKey() crypto.PublicKey {
|
||||
return k.pubKey
|
||||
}
|
||||
|
||||
// Close should be called when the key is no longer needed. This is important to
|
||||
// do as most TPMs can only have a small number of key simultaneously loaded.
|
||||
func (k *Key) Close() {
|
||||
if k.session != nil {
|
||||
k.session.Close()
|
||||
}
|
||||
tpm2.FlushContext(k.rw, k.handle)
|
||||
}
|
||||
|
||||
// Seal seals the sensitive byte buffer to a key. This key must be an SRK (we
|
||||
// currently do not support sealing to EKs). Optionally, the SealOpts struct can
|
||||
// be modified to provide sealed-to PCRs. In this case, the sensitive data can
|
||||
// only be unsealed if the seal-time PCRs are in the SealOpts-specified state.
|
||||
// There must not be overlap in PCRs between SealOpts' Current and Target.
|
||||
// During the sealing process, certification data will be created allowing
|
||||
// Unseal() to validate the state of the TPM during the sealing process.
|
||||
func (k *Key) Seal(sensitive []byte, opts SealOpts) (*pb.SealedBytes, error) {
|
||||
var pcrs *pb.PCRs
|
||||
var err error
|
||||
var auth []byte
|
||||
|
||||
pcrs, err = mergePCRSelAndProto(k.rw, opts.Current, opts.Target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid SealOpts: %v", err)
|
||||
}
|
||||
if len(pcrs.GetPcrs()) > 0 {
|
||||
auth = internal.PCRSessionAuth(pcrs, SessionHashAlg)
|
||||
}
|
||||
certifySel := FullPcrSel(CertifyHashAlgTpm)
|
||||
sb, err := sealHelper(k.rw, k.Handle(), auth, sensitive, certifySel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for pcrNum := range pcrs.GetPcrs() {
|
||||
sb.Pcrs = append(sb.Pcrs, pcrNum)
|
||||
}
|
||||
sb.Hash = pcrs.GetHash()
|
||||
sb.Srk = pb.ObjectType(k.pubArea.Type)
|
||||
return sb, nil
|
||||
}
|
||||
|
||||
func sealHelper(rw io.ReadWriter, parentHandle tpmutil.Handle, auth []byte, sensitive []byte, certifyPCRsSel tpm2.PCRSelection) (*pb.SealedBytes, error) {
|
||||
inPublic := tpm2.Public{
|
||||
Type: tpm2.AlgKeyedHash,
|
||||
NameAlg: SessionHashAlgTpm,
|
||||
Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent,
|
||||
AuthPolicy: auth,
|
||||
}
|
||||
if auth == nil {
|
||||
inPublic.Attributes |= tpm2.FlagUserWithAuth
|
||||
} else {
|
||||
inPublic.Attributes |= tpm2.FlagAdminWithPolicy
|
||||
}
|
||||
|
||||
priv, pub, creationData, _, ticket, err := tpm2.CreateKeyWithSensitive(rw, parentHandle, certifyPCRsSel, "", "", inPublic, sensitive)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create key: %w", err)
|
||||
}
|
||||
certifiedPcr, err := ReadPCRs(rw, certifyPCRsSel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read PCRs: %w", err)
|
||||
}
|
||||
computedDigest := internal.PCRDigest(certifiedPcr, SessionHashAlg)
|
||||
|
||||
decodedCreationData, err := tpm2.DecodeCreationData(creationData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode creation data: %w", err)
|
||||
}
|
||||
|
||||
// make sure PCRs haven't being altered after sealing
|
||||
if subtle.ConstantTimeCompare(computedDigest, decodedCreationData.PCRDigest) == 0 {
|
||||
return nil, fmt.Errorf("PCRs have been modified after sealing")
|
||||
}
|
||||
|
||||
sb := &pb.SealedBytes{}
|
||||
sb.CertifiedPcrs = certifiedPcr
|
||||
sb.Priv = priv
|
||||
sb.Pub = pub
|
||||
sb.CreationData = creationData
|
||||
if sb.Ticket, err = tpmutil.Pack(ticket); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sb, nil
|
||||
}
|
||||
|
||||
// Unseal attempts to reverse the process of Seal(), using the PCRs, public, and
|
||||
// private data in proto.SealedBytes. Optionally, the UnsealOpts parameter can
|
||||
// be used to verify the state of the TPM when the data was sealed. The
|
||||
// zero-value UnsealOpts can be passed to skip certification.
|
||||
func (k *Key) Unseal(in *pb.SealedBytes, opts UnsealOpts) ([]byte, error) {
|
||||
if in.Srk != pb.ObjectType(k.pubArea.Type) {
|
||||
return nil, fmt.Errorf("expected key of type %v, got %v", in.Srk, k.pubArea.Type)
|
||||
}
|
||||
sealed, _, err := tpm2.Load(
|
||||
k.rw,
|
||||
k.Handle(),
|
||||
/*parentPassword=*/ "",
|
||||
in.GetPub(),
|
||||
in.GetPriv())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load sealed object: %w", err)
|
||||
}
|
||||
defer tpm2.FlushContext(k.rw, sealed)
|
||||
|
||||
pcrs, err := mergePCRSelAndProto(k.rw, opts.CertifyCurrent, opts.CertifyExpected)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid UnsealOpts: %v", err)
|
||||
}
|
||||
if len(pcrs.GetPcrs()) > 0 {
|
||||
if err := internal.CheckSubset(pcrs, in.GetCertifiedPcrs()); err != nil {
|
||||
return nil, fmt.Errorf("failed to certify PCRs: %w", err)
|
||||
}
|
||||
|
||||
var ticket tpm2.Ticket
|
||||
if _, err = tpmutil.Unpack(in.GetTicket(), &ticket); err != nil {
|
||||
return nil, fmt.Errorf("ticket unpack failed: %w", err)
|
||||
}
|
||||
creationHash := SessionHashAlg.New()
|
||||
creationHash.Write(in.GetCreationData())
|
||||
|
||||
_, _, certErr := tpm2.CertifyCreation(k.rw, "", sealed, tpm2.HandleNull, nil, creationHash.Sum(nil), tpm2.SigScheme{}, ticket)
|
||||
// There is a bug in some older TPMs, where they are unable to
|
||||
// CertifyCreation when using a Null signing handle (despite this
|
||||
// being allowed by all versions of the TPM spec). To work around
|
||||
// this bug, we use a temporary signing key and ignore the signed
|
||||
// result. To reduce the cost of this workaround, we use a cached
|
||||
// ECC signing key.
|
||||
// We can detect this bug, as it triggers a RCInsufficient
|
||||
// Unmarshaling error.
|
||||
if paramErr, ok := certErr.(tpm2.ParameterError); ok && paramErr.Code == tpm2.RCInsufficient {
|
||||
signer, err := AttestationKeyECC(k.rw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fallback signing key: %w", err)
|
||||
}
|
||||
defer signer.Close()
|
||||
_, _, certErr = tpm2.CertifyCreation(k.rw, "", sealed, signer.Handle(), nil, creationHash.Sum(nil), tpm2.SigScheme{}, ticket)
|
||||
}
|
||||
if certErr != nil {
|
||||
return nil, fmt.Errorf("failed to certify creation: %w", certErr)
|
||||
}
|
||||
|
||||
// verify certify PCRs haven't been modified
|
||||
decodedCreationData, err := tpm2.DecodeCreationData(in.GetCreationData())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode creation data: %w", err)
|
||||
}
|
||||
if !internal.SamePCRSelection(in.GetCertifiedPcrs(), decodedCreationData.PCRSelection) {
|
||||
return nil, fmt.Errorf("certify PCRs does not match the PCR selection in the creation data")
|
||||
}
|
||||
expectedDigest := internal.PCRDigest(in.GetCertifiedPcrs(), SessionHashAlg)
|
||||
if subtle.ConstantTimeCompare(decodedCreationData.PCRDigest, expectedDigest) == 0 {
|
||||
return nil, fmt.Errorf("certify PCRs digest does not match the digest in the creation data")
|
||||
}
|
||||
}
|
||||
|
||||
sel := tpm2.PCRSelection{Hash: tpm2.Algorithm(in.GetHash())}
|
||||
for _, pcr := range in.GetPcrs() {
|
||||
sel.PCRs = append(sel.PCRs, int(pcr))
|
||||
}
|
||||
|
||||
session, err := newPCRSession(k.rw, sel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create session: %w", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
auth, err := session.Auth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tpm2.UnsealWithSession(k.rw, auth.Session, sealed, "")
|
||||
}
|
||||
|
||||
// Quote will tell TPM to compute a hash of a set of given PCR selection, together with
|
||||
// some extra data (typically a nonce), sign it with the given signing key, and return
|
||||
// the signature and the attestation data. This function will return an error if
|
||||
// the key is not a restricted signing key.
|
||||
func (k *Key) Quote(selpcr tpm2.PCRSelection, extraData []byte) (*pb.Quote, error) {
|
||||
// Make sure that we have a valid signing key before trying quote
|
||||
var err error
|
||||
if _, err = internal.GetSigningHashAlg(k.pubArea); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !k.hasAttribute(tpm2.FlagRestricted) {
|
||||
return nil, fmt.Errorf("unrestricted keys are insecure to use with Quote")
|
||||
}
|
||||
|
||||
quote := &pb.Quote{}
|
||||
quote.Quote, quote.RawSig, err = tpm2.QuoteRaw(k.rw, k.Handle(), "", "", extraData, selpcr, tpm2.AlgNull)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to quote: %w", err)
|
||||
}
|
||||
quote.Pcrs, err = ReadPCRs(k.rw, selpcr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read PCRs: %w", err)
|
||||
}
|
||||
// Verify the quote client-side to make sure we didn't mess things up.
|
||||
// NOTE: the quote still must be verified server-side as well.
|
||||
if err := internal.VerifyQuote(quote, k.PublicKey(), extraData); err != nil {
|
||||
return nil, fmt.Errorf("failed to verify quote: %w", err)
|
||||
}
|
||||
return quote, nil
|
||||
}
|
||||
|
||||
// Reseal is a shortcut to call Unseal() followed by Seal().
|
||||
// CertifyOpt(nillable) will be used in Unseal(), and SealOpt(nillable)
|
||||
// will be used in Seal()
|
||||
func (k *Key) Reseal(in *pb.SealedBytes, uOpts UnsealOpts, sOpts SealOpts) (*pb.SealedBytes, error) {
|
||||
sensitive, err := k.Unseal(in, uOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unseal: %w", err)
|
||||
}
|
||||
return k.Seal(sensitive, sOpts)
|
||||
}
|
||||
|
||||
func (k *Key) hasAttribute(attr tpm2.KeyProp) bool {
|
||||
return k.pubArea.Attributes&attr != 0
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
pb "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// NumPCRs is set to the spec minimum of 24, as that's all go-tpm supports.
|
||||
const NumPCRs = 24
|
||||
|
||||
// We hard-code SHA256 as the policy session hash algorithms. Note that this
|
||||
// differs from the PCR hash algorithm (which selects the bank of PCRs to use)
|
||||
// and the Public area Name algorithm. We also chose this for compatibility with
|
||||
// github.com/google/go-tpm/tpm2, as it hardcodes the nameAlg as SHA256 in
|
||||
// several places. Two constants are used to avoid repeated conversions.
|
||||
const (
|
||||
SessionHashAlg = crypto.SHA256
|
||||
SessionHashAlgTpm = tpm2.AlgSHA256
|
||||
)
|
||||
|
||||
// CertifyHashAlgTpm is the hard-coded algorithm used in certify PCRs.
|
||||
const CertifyHashAlgTpm = tpm2.AlgSHA256
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Get a list of selections corresponding to the TPM's implemented PCRs
|
||||
func implementedPCRs(rw io.ReadWriter) ([]tpm2.PCRSelection, error) {
|
||||
caps, moreData, err := tpm2.GetCapability(rw, tpm2.CapabilityPCRs, math.MaxUint32, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing implemented PCR banks: %w", err)
|
||||
}
|
||||
if moreData {
|
||||
return nil, fmt.Errorf("extra data from GetCapability")
|
||||
}
|
||||
sels := make([]tpm2.PCRSelection, len(caps))
|
||||
for i, cap := range caps {
|
||||
sel, ok := cap.(tpm2.PCRSelection)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected data from GetCapability")
|
||||
}
|
||||
sels[i] = sel
|
||||
}
|
||||
return sels, nil
|
||||
}
|
||||
|
||||
// ReadPCRs fetches all the PCR values specified in sel, making multiple calls
|
||||
// to the TPM if necessary.
|
||||
func ReadPCRs(rw io.ReadWriter, sel tpm2.PCRSelection) (*pb.PCRs, error) {
|
||||
pl := pb.PCRs{
|
||||
Hash: pb.HashAlgo(sel.Hash),
|
||||
Pcrs: map[uint32][]byte{},
|
||||
}
|
||||
|
||||
for i := 0; i < len(sel.PCRs); i += 8 {
|
||||
end := min(i+8, len(sel.PCRs))
|
||||
pcrSel := tpm2.PCRSelection{
|
||||
Hash: sel.Hash,
|
||||
PCRs: sel.PCRs[i:end],
|
||||
}
|
||||
|
||||
pcrMap, err := tpm2.ReadPCRs(rw, pcrSel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for pcr, val := range pcrMap {
|
||||
pl.Pcrs[uint32(pcr)] = val
|
||||
}
|
||||
}
|
||||
|
||||
return &pl, nil
|
||||
}
|
||||
|
||||
// ReadAllPCRs fetches all the PCR values from all implemented PCR banks.
|
||||
func ReadAllPCRs(rw io.ReadWriter) ([]*pb.PCRs, error) {
|
||||
sels, err := implementedPCRs(rw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allPcrs := make([]*pb.PCRs, len(sels))
|
||||
for i, sel := range sels {
|
||||
allPcrs[i], err = ReadPCRs(rw, sel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading bank %x PCRs: %w", sel.Hash, err)
|
||||
}
|
||||
}
|
||||
return allPcrs, nil
|
||||
}
|
||||
|
||||
// SealOpts specifies the PCR values that should be used for Seal().
|
||||
type SealOpts struct {
|
||||
// Current seals data to the current specified PCR selection.
|
||||
Current tpm2.PCRSelection
|
||||
// Target predictively seals data to the given specified PCR values.
|
||||
Target *pb.PCRs
|
||||
}
|
||||
|
||||
// UnsealOpts specifies the options that should be used for Unseal().
|
||||
// Currently, it specifies the PCRs that need to pass certification in order to
|
||||
// successfully unseal.
|
||||
// CertifyHashAlgTpm is the hard-coded algorithm that must be used with
|
||||
// UnsealOpts.
|
||||
type UnsealOpts struct {
|
||||
// CertifyCurrent certifies that a selection of current PCRs have the same
|
||||
// value when sealing.
|
||||
CertifyCurrent tpm2.PCRSelection
|
||||
// CertifyExpected certifies that the TPM had a specific set of PCR values when sealing.
|
||||
CertifyExpected *pb.PCRs
|
||||
}
|
||||
|
||||
// FullPcrSel will return a full PCR selection based on the total PCR number
|
||||
// of the TPM with the given hash algo.
|
||||
func FullPcrSel(hash tpm2.Algorithm) tpm2.PCRSelection {
|
||||
sel := tpm2.PCRSelection{Hash: hash}
|
||||
for i := 0; i < NumPCRs; i++ {
|
||||
sel.PCRs = append(sel.PCRs, int(i))
|
||||
}
|
||||
return sel
|
||||
}
|
||||
|
||||
func mergePCRSelAndProto(rw io.ReadWriter, sel tpm2.PCRSelection, proto *pb.PCRs) (*pb.PCRs, error) {
|
||||
if proto == nil || len(proto.GetPcrs()) == 0 {
|
||||
return ReadPCRs(rw, sel)
|
||||
}
|
||||
if len(sel.PCRs) == 0 {
|
||||
return proto, nil
|
||||
}
|
||||
if sel.Hash != tpm2.Algorithm(proto.Hash) {
|
||||
return nil, fmt.Errorf("current hash (%v) differs from target hash (%v)",
|
||||
sel.Hash, tpm2.Algorithm(proto.Hash))
|
||||
}
|
||||
|
||||
// At this point, both sel and proto are non-empty.
|
||||
// Verify no overlap in sel and proto PCR indexes.
|
||||
overlap := make([]int, 0)
|
||||
targetMap := proto.GetPcrs()
|
||||
for _, pcrVal := range sel.PCRs {
|
||||
if _, found := targetMap[uint32(pcrVal)]; found {
|
||||
overlap = append(overlap, pcrVal)
|
||||
}
|
||||
}
|
||||
if len(overlap) != 0 {
|
||||
return nil, fmt.Errorf("found PCR overlap: %v", overlap)
|
||||
}
|
||||
|
||||
currentPcrs, err := ReadPCRs(rw, sel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for pcr, val := range proto.GetPcrs() {
|
||||
currentPcrs.Pcrs[pcr] = val
|
||||
}
|
||||
return currentPcrs, nil
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
type session interface {
|
||||
io.Closer
|
||||
Auth() (tpm2.AuthCommand, error)
|
||||
}
|
||||
|
||||
func startAuthSession(rw io.ReadWriter) (session tpmutil.Handle, err error) {
|
||||
// This session assumes the bus is trusted, so we:
|
||||
// - use nil for tpmKey, encrypted salt, and symmetric
|
||||
// - use and all-zeros caller nonce, and ignore the returned nonce
|
||||
// As we are creating a plain TPM session, we:
|
||||
// - setup a policy session
|
||||
// - don't bind the session to any particular key
|
||||
session, _, err = tpm2.StartAuthSession(
|
||||
rw,
|
||||
/*tpmKey=*/ tpm2.HandleNull,
|
||||
/*bindKey=*/ tpm2.HandleNull,
|
||||
/*nonceCaller=*/ make([]byte, SessionHashAlg.Size()),
|
||||
/*encryptedSalt=*/ nil,
|
||||
/*sessionType=*/ tpm2.SessionPolicy,
|
||||
/*symmetric=*/ tpm2.AlgNull,
|
||||
/*authHash=*/ SessionHashAlgTpm)
|
||||
return
|
||||
}
|
||||
|
||||
type pcrSession struct {
|
||||
rw io.ReadWriter
|
||||
session tpmutil.Handle
|
||||
sel tpm2.PCRSelection
|
||||
}
|
||||
|
||||
func newPCRSession(rw io.ReadWriter, sel tpm2.PCRSelection) (session, error) {
|
||||
if len(sel.PCRs) == 0 {
|
||||
return nullSession{}, nil
|
||||
}
|
||||
session, err := startAuthSession(rw)
|
||||
return pcrSession{rw, session, sel}, err
|
||||
}
|
||||
|
||||
func (p pcrSession) Auth() (auth tpm2.AuthCommand, err error) {
|
||||
if err = tpm2.PolicyPCR(p.rw, p.session, nil, p.sel); err != nil {
|
||||
return
|
||||
}
|
||||
return tpm2.AuthCommand{Session: p.session, Attributes: tpm2.AttrContinueSession}, nil
|
||||
}
|
||||
|
||||
func (p pcrSession) Close() error {
|
||||
return tpm2.FlushContext(p.rw, p.session)
|
||||
}
|
||||
|
||||
type ekSession struct {
|
||||
rw io.ReadWriter
|
||||
session tpmutil.Handle
|
||||
}
|
||||
|
||||
func newEKSession(rw io.ReadWriter) (session, error) {
|
||||
session, err := startAuthSession(rw)
|
||||
return ekSession{rw, session}, err
|
||||
}
|
||||
|
||||
func (e ekSession) Auth() (auth tpm2.AuthCommand, err error) {
|
||||
nullAuth := tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}
|
||||
if _, err = tpm2.PolicySecret(e.rw, tpm2.HandleEndorsement, nullAuth, e.session, nil, nil, nil, 0); err != nil {
|
||||
return
|
||||
}
|
||||
return tpm2.AuthCommand{Session: e.session, Attributes: tpm2.AttrContinueSession}, nil
|
||||
}
|
||||
|
||||
func (e ekSession) Close() error {
|
||||
return tpm2.FlushContext(e.rw, e.session)
|
||||
}
|
||||
|
||||
type nullSession struct{}
|
||||
|
||||
func (n nullSession) Auth() (auth tpm2.AuthCommand, err error) {
|
||||
return tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}, nil
|
||||
}
|
||||
|
||||
func (n nullSession) Close() error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/google/go-tpm-tools/internal"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// Global mutex to protect against concurrent TPM access.
|
||||
var signerMutex sync.Mutex
|
||||
|
||||
type tpmSigner struct {
|
||||
Key *Key
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
// Public returns the tpmSigners public key.
|
||||
func (signer *tpmSigner) Public() crypto.PublicKey {
|
||||
return signer.Key.PublicKey()
|
||||
}
|
||||
|
||||
// Sign uses the TPM key to sign the digest.
|
||||
// The digest must be hashed from the same hash algorithm as the keys scheme.
|
||||
// The opts hash function must also match the keys scheme (or be nil).
|
||||
// Concurrent use of Sign is thread safe, but it is not safe to access the TPM
|
||||
// from other sources while Sign is executing.
|
||||
// For RSAPSS signatures, you cannot specify custom salt lengths. The salt
|
||||
// length will be (keyBits/8) - digestSize - 2, unless that is less than the
|
||||
// digestSize in which case, saltLen will be digestSize. The only normal case
|
||||
// where saltLen is not digestSize is when using 1024 keyBits with SHA512.
|
||||
func (signer *tpmSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
if pssOpts, ok := opts.(*rsa.PSSOptions); ok {
|
||||
if signer.Key.pubArea.RSAParameters == nil {
|
||||
return nil, fmt.Errorf("invalid options: PSSOptions can only be used with RSA keys")
|
||||
}
|
||||
if signer.Key.pubArea.RSAParameters.Sign.Alg != tpm2.AlgRSAPSS {
|
||||
return nil, fmt.Errorf("invalid options: PSSOptions cannot be used with signing alg: %v", signer.Key.pubArea.RSAParameters.Sign.Alg)
|
||||
}
|
||||
if pssOpts.SaltLength != rsa.PSSSaltLengthAuto {
|
||||
return nil, fmt.Errorf("salt length must be rsa.PSSSaltLengthAuto")
|
||||
}
|
||||
}
|
||||
if opts != nil && opts.HashFunc() != signer.Hash {
|
||||
return nil, fmt.Errorf("hash algorithm: got %v, want %v", opts.HashFunc(), signer.Hash)
|
||||
}
|
||||
if len(digest) != signer.Hash.Size() {
|
||||
return nil, fmt.Errorf("digest length: got %d, want %d", digest, signer.Hash.Size())
|
||||
}
|
||||
|
||||
signerMutex.Lock()
|
||||
defer signerMutex.Unlock()
|
||||
|
||||
auth, err := signer.Key.session.Auth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := tpm2.SignWithSession(signer.Key.rw, auth.Session, signer.Key.handle, "", digest, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getSignature(sig)
|
||||
}
|
||||
|
||||
// GetSigner returns a crypto.Signer wrapping the loaded TPM Key.
|
||||
// Concurrent use of one or more Signers is thread safe, but it is not safe to
|
||||
// access the TPM from other sources while using a Signer.
|
||||
// The returned Signer lasts the lifetime of the Key, and will no longer work
|
||||
// once the Key has been closed.
|
||||
func (k *Key) GetSigner() (crypto.Signer, error) {
|
||||
if k.hasAttribute(tpm2.FlagRestricted) {
|
||||
return nil, fmt.Errorf("restricted keys are not supported")
|
||||
}
|
||||
hashAlg, err := internal.GetSigningHashAlg(k.pubArea)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// For crypto.Signer, Go does the hashing. Make sure the hash is supported.
|
||||
hash, err := hashAlg.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tpmSigner{k, hash}, nil
|
||||
}
|
||||
|
||||
// SignData signs a data buffer with a TPM loaded key. Unlike GetSigner, this
|
||||
// method works with restricted and unrestricted keys. If this method is called
|
||||
// on a restriced key, the TPM itself will hash the provided data, failing the
|
||||
// signing operation if the data begins with TPM_GENERATED_VALUE.
|
||||
func (k *Key) SignData(data []byte) ([]byte, error) {
|
||||
hashAlg, err := internal.GetSigningHashAlg(k.pubArea)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var digest []byte
|
||||
var ticket *tpm2.Ticket
|
||||
if k.hasAttribute(tpm2.FlagRestricted) {
|
||||
// Restricted keys can only sign data hashed by the TPM. We use the
|
||||
// owner hierarchy for the Ticket, but any non-Null hierarchy would do.
|
||||
digest, ticket, err = tpm2.Hash(k.rw, hashAlg, data, tpm2.HandleOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Unrestricted keys can sign any digest, no need for TPM hashing.
|
||||
hash, err := hashAlg.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hasher := hash.New()
|
||||
hasher.Write(data)
|
||||
digest = hasher.Sum(nil)
|
||||
}
|
||||
|
||||
auth, err := k.session.Auth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err := tpm2.SignWithSession(k.rw, auth.Session, k.handle, "", digest, ticket, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getSignature(sig)
|
||||
}
|
||||
|
||||
func getSignature(sig *tpm2.Signature) ([]byte, error) {
|
||||
switch sig.Alg {
|
||||
case tpm2.AlgRSASSA:
|
||||
return sig.RSA.Signature, nil
|
||||
case tpm2.AlgRSAPSS:
|
||||
return sig.RSA.Signature, nil
|
||||
case tpm2.AlgECDSA:
|
||||
sigStruct := struct{ R, S *big.Int }{sig.ECC.R, sig.ECC.S}
|
||||
return asn1.Marshal(sigStruct)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported signing algorithm: %v", sig.Alg)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
// Calculations from Credential_Profile_EK_V2.0, section 2.1.5.3 - authPolicy
|
||||
func defaultEKAuthPolicy() []byte {
|
||||
buf, err := tpmutil.Pack(tpm2.CmdPolicySecret, tpm2.HandleEndorsement)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
digest1 := sha256.Sum256(append(make([]byte, 32), buf...))
|
||||
// We would normally append the policy buffer to digest1, but the
|
||||
// policy buffer is empty for the default Auth Policy.
|
||||
digest2 := sha256.Sum256(digest1[:])
|
||||
return digest2[:]
|
||||
}
|
||||
|
||||
func defaultEKAttributes() tpm2.KeyProp {
|
||||
// The EK is a storage key that must use session-based authorization.
|
||||
return (tpm2.FlagStorageDefault | tpm2.FlagAdminWithPolicy) & ^tpm2.FlagUserWithAuth
|
||||
}
|
||||
|
||||
func defaultSRKAttributes() tpm2.KeyProp {
|
||||
// FlagNoDA doesn't do anything (as the AuthPolicy is nil). However, this is
|
||||
// what Windows does, and we don't want to conflict.
|
||||
return tpm2.FlagStorageDefault | tpm2.FlagNoDA
|
||||
}
|
||||
|
||||
func defaultSymScheme() *tpm2.SymScheme {
|
||||
return &tpm2.SymScheme{
|
||||
Alg: tpm2.AlgAES,
|
||||
KeyBits: 128,
|
||||
Mode: tpm2.AlgCFB,
|
||||
}
|
||||
}
|
||||
|
||||
func defaultRSAParams() *tpm2.RSAParams {
|
||||
return &tpm2.RSAParams{
|
||||
Symmetric: defaultSymScheme(),
|
||||
KeyBits: 2048,
|
||||
ModulusRaw: make([]byte, 256), // public.unique must be all zeros
|
||||
}
|
||||
}
|
||||
|
||||
func defaultECCParams() *tpm2.ECCParams {
|
||||
return &tpm2.ECCParams{
|
||||
Symmetric: defaultSymScheme(),
|
||||
CurveID: tpm2.CurveNISTP256,
|
||||
Point: tpm2.ECPoint{
|
||||
XRaw: make([]byte, 32),
|
||||
YRaw: make([]byte, 32),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultEKTemplateRSA returns the default Endorsement Key (EK) template as
|
||||
// specified in Credential_Profile_EK_V2.0, section 2.1.5.1 - authPolicy.
|
||||
// https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
|
||||
func DefaultEKTemplateRSA() tpm2.Public {
|
||||
return tpm2.Public{
|
||||
Type: tpm2.AlgRSA,
|
||||
NameAlg: tpm2.AlgSHA256,
|
||||
Attributes: defaultEKAttributes(),
|
||||
AuthPolicy: defaultEKAuthPolicy(),
|
||||
RSAParameters: defaultRSAParams(),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultEKTemplateECC returns the default Endorsement Key (EK) template as
|
||||
// specified in Credential_Profile_EK_V2.0, section 2.1.5.2 - authPolicy.
|
||||
// https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
|
||||
func DefaultEKTemplateECC() tpm2.Public {
|
||||
return tpm2.Public{
|
||||
Type: tpm2.AlgECC,
|
||||
NameAlg: tpm2.AlgSHA256,
|
||||
Attributes: defaultEKAttributes(),
|
||||
AuthPolicy: defaultEKAuthPolicy(),
|
||||
ECCParameters: defaultECCParams(),
|
||||
}
|
||||
}
|
||||
|
||||
// AKTemplateRSA returns a potential Attestation Key (AK) template.
|
||||
// This is very similar to DefaultEKTemplateRSA, except that this will be a
|
||||
// signing key instead of an encrypting key.
|
||||
func AKTemplateRSA() tpm2.Public {
|
||||
return tpm2.Public{
|
||||
Type: tpm2.AlgRSA,
|
||||
NameAlg: tpm2.AlgSHA256,
|
||||
Attributes: tpm2.FlagSignerDefault,
|
||||
RSAParameters: &tpm2.RSAParams{
|
||||
Sign: &tpm2.SigScheme{
|
||||
Alg: tpm2.AlgRSASSA,
|
||||
Hash: tpm2.AlgSHA256,
|
||||
},
|
||||
KeyBits: 2048,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AKTemplateECC returns a potential Attestation Key (AK) template.
|
||||
// This is very similar to DefaultEKTemplateECC, except that this will be a
|
||||
// signing key instead of an encrypting key.
|
||||
func AKTemplateECC() tpm2.Public {
|
||||
params := defaultECCParams()
|
||||
params.Symmetric = nil
|
||||
params.Sign = &tpm2.SigScheme{
|
||||
Alg: tpm2.AlgECDSA,
|
||||
Hash: tpm2.AlgSHA256,
|
||||
}
|
||||
return tpm2.Public{
|
||||
Type: tpm2.AlgECC,
|
||||
NameAlg: tpm2.AlgSHA256,
|
||||
Attributes: tpm2.FlagSignerDefault,
|
||||
ECCParameters: params,
|
||||
}
|
||||
}
|
||||
|
||||
// SRKTemplateRSA returns a standard Storage Root Key (SRK) template.
|
||||
// This is based upon the advice in the TCG's TPM v2.0 Provisioning Guidance.
|
||||
func SRKTemplateRSA() tpm2.Public {
|
||||
return tpm2.Public{
|
||||
Type: tpm2.AlgRSA,
|
||||
NameAlg: tpm2.AlgSHA256,
|
||||
Attributes: defaultSRKAttributes(),
|
||||
RSAParameters: defaultRSAParams(),
|
||||
}
|
||||
}
|
||||
|
||||
// SRKTemplateECC returns a standard Storage Root Key (SRK) template.
|
||||
// This is based upon the advice in the TCG's TPM v2.0 Provisioning Guidance.
|
||||
func SRKTemplateECC() tpm2.Public {
|
||||
return tpm2.Public{
|
||||
Type: tpm2.AlgECC,
|
||||
NameAlg: tpm2.AlgSHA256,
|
||||
Attributes: defaultSRKAttributes(),
|
||||
ECCParameters: defaultECCParams(),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"pcrs.go",
|
||||
"public.go",
|
||||
"quote.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm-tools/internal",
|
||||
importpath = "github.com/google/go-tpm-tools/internal",
|
||||
visibility = ["//vendor/github.com/google/go-tpm-tools:__subpackages__"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/go-tpm-tools/proto/tpm:go_default_library",
|
||||
"//vendor/github.com/google/go-tpm/tpm2:go_default_library",
|
||||
"//vendor/github.com/google/go-tpm/tpmutil:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,130 @@
|
|||
// Package internal contains private helper functions needed in client and server
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
pb "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
const minPCRIndex = uint32(0)
|
||||
|
||||
func maxPCRIndex(p *pb.PCRs) uint32 {
|
||||
max := minPCRIndex
|
||||
for idx := range p.GetPcrs() {
|
||||
if idx > max {
|
||||
max = idx
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// FormatPCRs writes a multiline representation of the PCR values to w.
|
||||
func FormatPCRs(w io.Writer, p *pb.PCRs) error {
|
||||
if _, err := fmt.Fprintf(w, "%v:\n", p.Hash); err != nil {
|
||||
return err
|
||||
}
|
||||
for idx := minPCRIndex; idx <= maxPCRIndex(p); idx++ {
|
||||
if val, ok := p.GetPcrs()[idx]; ok {
|
||||
if _, err := fmt.Fprintf(w, " %2d: 0x%X\n", idx, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckSubset verifies if the pcrs PCRs are a valid "subset" of the provided
|
||||
// "superset" of PCRs. The PCR values must match (if present), and all PCRs must
|
||||
// be present in the superset. This function will return an error containing the
|
||||
// first missing or mismatched PCR number.
|
||||
func CheckSubset(subset, superset *pb.PCRs) error {
|
||||
if subset.GetHash() != superset.GetHash() {
|
||||
return fmt.Errorf("PCR hash algo not matching: %v, %v", subset.GetHash(), superset.GetHash())
|
||||
}
|
||||
for pcrNum, pcrVal := range subset.GetPcrs() {
|
||||
if expectedVal, ok := superset.GetPcrs()[pcrNum]; ok {
|
||||
if !bytes.Equal(expectedVal, pcrVal) {
|
||||
return fmt.Errorf("PCR %d mismatch: expected %v, got %v", pcrNum, expectedVal, pcrVal)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("PCR %d mismatch: value missing from the superset PCRs", pcrNum)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PCRSelection returns the corresponding tpm2.PCRSelection for the PCR data.
|
||||
func PCRSelection(p *pb.PCRs) tpm2.PCRSelection {
|
||||
sel := tpm2.PCRSelection{Hash: tpm2.Algorithm(p.GetHash())}
|
||||
|
||||
for pcrNum := range p.GetPcrs() {
|
||||
sel.PCRs = append(sel.PCRs, int(pcrNum))
|
||||
}
|
||||
return sel
|
||||
}
|
||||
|
||||
// SamePCRSelection checks if the Pcrs has the same PCRSelection as the
|
||||
// provided given tpm2.PCRSelection (including the hash algorithm).
|
||||
func SamePCRSelection(p *pb.PCRs, sel tpm2.PCRSelection) bool {
|
||||
if tpm2.Algorithm(p.GetHash()) != sel.Hash {
|
||||
return false
|
||||
}
|
||||
if len(p.GetPcrs()) != len(sel.PCRs) {
|
||||
return false
|
||||
}
|
||||
for _, pcr := range sel.PCRs {
|
||||
if _, ok := p.Pcrs[uint32(pcr)]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// PCRSessionAuth calculates the authorization value for the given PCRs.
|
||||
func PCRSessionAuth(p *pb.PCRs, hashAlg crypto.Hash) []byte {
|
||||
// Start with all zeros, we only use a single policy command on our session.
|
||||
oldDigest := make([]byte, hashAlg.Size())
|
||||
ccPolicyPCR, _ := tpmutil.Pack(tpm2.CmdPolicyPCR)
|
||||
|
||||
// Extend the policy digest, see TPM2_PolicyPCR in Part 3 of the spec.
|
||||
hash := hashAlg.New()
|
||||
hash.Write(oldDigest)
|
||||
hash.Write(ccPolicyPCR)
|
||||
hash.Write(encodePCRSelection(PCRSelection(p)))
|
||||
hash.Write(PCRDigest(p, hashAlg))
|
||||
newDigest := hash.Sum(nil)
|
||||
return newDigest[:]
|
||||
}
|
||||
|
||||
// PCRDigest computes the digest of the Pcrs. Note that the digest hash
|
||||
// algorithm may differ from the PCRs' hash (which denotes the PCR bank).
|
||||
func PCRDigest(p *pb.PCRs, hashAlg crypto.Hash) []byte {
|
||||
hash := hashAlg.New()
|
||||
for i := uint32(0); i < 24; i++ {
|
||||
if pcrValue, exists := p.GetPcrs()[i]; exists {
|
||||
hash.Write(pcrValue)
|
||||
}
|
||||
}
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
// Encode a tpm2.PCRSelection as if it were a TPML_PCR_SELECTION
|
||||
func encodePCRSelection(sel tpm2.PCRSelection) []byte {
|
||||
// Encode count, pcrSelections.hash and pcrSelections.sizeofSelect fields
|
||||
buf, _ := tpmutil.Pack(uint32(1), sel.Hash, byte(3))
|
||||
// Encode pcrSelect bitmask
|
||||
pcrBits := make([]byte, 3)
|
||||
for _, pcr := range sel.PCRs {
|
||||
byteNum := pcr / 8
|
||||
bytePos := 1 << uint(pcr%8)
|
||||
pcrBits[byteNum] |= byte(bytePos)
|
||||
}
|
||||
|
||||
return append(buf, pcrBits...)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// GetSigningHashAlg returns the hash algorithm used for a signing key. Returns
|
||||
// an error if an algorithm isn't supported, or the key is not a signing key.
|
||||
func GetSigningHashAlg(pubArea tpm2.Public) (tpm2.Algorithm, error) {
|
||||
if pubArea.Attributes&tpm2.FlagSign == 0 {
|
||||
return tpm2.AlgNull, fmt.Errorf("non-signing key used with signing operation")
|
||||
}
|
||||
|
||||
var sigScheme *tpm2.SigScheme
|
||||
switch pubArea.Type {
|
||||
case tpm2.AlgRSA:
|
||||
sigScheme = pubArea.RSAParameters.Sign
|
||||
case tpm2.AlgECC:
|
||||
sigScheme = pubArea.ECCParameters.Sign
|
||||
default:
|
||||
return tpm2.AlgNull, fmt.Errorf("unsupported key type: %v", pubArea.Type)
|
||||
}
|
||||
|
||||
if sigScheme == nil {
|
||||
return tpm2.AlgNull, fmt.Errorf("unsupported null signing scheme")
|
||||
}
|
||||
switch sigScheme.Alg {
|
||||
case tpm2.AlgRSAPSS, tpm2.AlgRSASSA, tpm2.AlgECDSA:
|
||||
return sigScheme.Hash, nil
|
||||
default:
|
||||
return tpm2.AlgNull, fmt.Errorf("unsupported signing algorithm: %v", sigScheme.Alg)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
|
||||
pb "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// VerifyQuote performs the following checks to validate a Quote:
|
||||
// - the provided signature is generated by the trusted AK public key
|
||||
// - the signature signs the provided quote data
|
||||
// - the quote data starts with TPM_GENERATED_VALUE
|
||||
// - the quote data is a valid TPMS_QUOTE_INFO
|
||||
// - the quote data was taken over the provided PCRs
|
||||
// - the provided PCR values match the quote data internal digest
|
||||
// - the provided extraData matches that in the quote data
|
||||
// Note that the caller must have already established trust in the provided
|
||||
// public key before validating the Quote.
|
||||
//
|
||||
// VerifyQuote supports ECDSA and RSASSA signature verification.
|
||||
func VerifyQuote(q *pb.Quote, trustedPub crypto.PublicKey, extraData []byte) error {
|
||||
sig, err := tpm2.DecodeSignature(bytes.NewBuffer(q.GetRawSig()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("signature decoding failed: %v", err)
|
||||
}
|
||||
|
||||
var hash crypto.Hash
|
||||
switch pub := trustedPub.(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
hash, err = sig.ECC.HashAlg.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = verifyECDSAQuoteSignature(pub, hash, q.GetQuote(), sig); err != nil {
|
||||
return err
|
||||
}
|
||||
case *rsa.PublicKey:
|
||||
hash, err = sig.RSA.HashAlg.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = verifyRSASSAQuoteSignature(pub, hash, q.GetQuote(), sig); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("only RSA and ECC public keys are currently supported, received type: %T", pub)
|
||||
|
||||
}
|
||||
|
||||
// Decode and check for magic TPMS_GENERATED_VALUE.
|
||||
attestationData, err := tpm2.DecodeAttestationData(q.GetQuote())
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding attestation data failed: %v", err)
|
||||
}
|
||||
if attestationData.Type != tpm2.TagAttestQuote {
|
||||
return fmt.Errorf("expected quote tag, got: %v", attestationData.Type)
|
||||
}
|
||||
attestedQuoteInfo := attestationData.AttestedQuoteInfo
|
||||
if attestedQuoteInfo == nil {
|
||||
return fmt.Errorf("attestation data does not contain quote info")
|
||||
}
|
||||
if subtle.ConstantTimeCompare(attestationData.ExtraData, extraData) == 0 {
|
||||
return fmt.Errorf("quote extraData did not match expected extraData")
|
||||
}
|
||||
return validatePCRDigest(attestedQuoteInfo, q.GetPcrs(), hash)
|
||||
}
|
||||
|
||||
func verifyECDSAQuoteSignature(ecdsaPub *ecdsa.PublicKey, hash crypto.Hash, quoted []byte, sig *tpm2.Signature) error {
|
||||
if sig.Alg != tpm2.AlgECDSA {
|
||||
return fmt.Errorf("signature scheme 0x%x is not supported, only ECDSA is supported", sig.Alg)
|
||||
}
|
||||
|
||||
hashConstructor := hash.New()
|
||||
hashConstructor.Write(quoted)
|
||||
if !ecdsa.Verify(ecdsaPub, hashConstructor.Sum(nil), sig.ECC.R, sig.ECC.S) {
|
||||
return fmt.Errorf("ECC signature verification failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyRSASSAQuoteSignature(rsaPub *rsa.PublicKey, hash crypto.Hash, quoted []byte, sig *tpm2.Signature) error {
|
||||
if sig.Alg != tpm2.AlgRSASSA {
|
||||
return fmt.Errorf("signature scheme 0x%x is not supported, only RSASSA (PKCS#1 v1.5) is supported", sig.Alg)
|
||||
}
|
||||
|
||||
hashConstructor := hash.New()
|
||||
hashConstructor.Write(quoted)
|
||||
if err := rsa.VerifyPKCS1v15(rsaPub, hash, hashConstructor.Sum(nil), sig.RSA.Signature); err != nil {
|
||||
return fmt.Errorf("RSASSA signature verification failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePCRDigest(quoteInfo *tpm2.QuoteInfo, pcrs *pb.PCRs, hash crypto.Hash) error {
|
||||
if !SamePCRSelection(pcrs, quoteInfo.PCRSelection) {
|
||||
return fmt.Errorf("given PCRs and Quote do not have the same PCR selection")
|
||||
}
|
||||
pcrDigest := PCRDigest(pcrs, hash)
|
||||
if subtle.ConstantTimeCompare(quoteInfo.PCRDigest, pcrDigest) == 0 {
|
||||
return fmt.Errorf("given PCRs digest not matching")
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["attest.pb.go"],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm-tools/proto/attest",
|
||||
importpath = "github.com/google/go-tpm-tools/proto/attest",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/go-tpm-tools/proto/tpm:go_default_library",
|
||||
"//vendor/google.golang.org/protobuf/reflect/protoreflect:go_default_library",
|
||||
"//vendor/google.golang.org/protobuf/runtime/protoimpl:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,854 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.17.3
|
||||
// source: attest.proto
|
||||
|
||||
package attest
|
||||
|
||||
import (
|
||||
tpm "github.com/google/go-tpm-tools/proto/tpm"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Type of hardware technology used to protect this instance
|
||||
type GCEConfidentialTechnology int32
|
||||
|
||||
const (
|
||||
GCEConfidentialTechnology_NONE GCEConfidentialTechnology = 0
|
||||
GCEConfidentialTechnology_AMD_SEV GCEConfidentialTechnology = 1
|
||||
GCEConfidentialTechnology_AMD_SEV_ES GCEConfidentialTechnology = 2
|
||||
)
|
||||
|
||||
// Enum value maps for GCEConfidentialTechnology.
|
||||
var (
|
||||
GCEConfidentialTechnology_name = map[int32]string{
|
||||
0: "NONE",
|
||||
1: "AMD_SEV",
|
||||
2: "AMD_SEV_ES",
|
||||
}
|
||||
GCEConfidentialTechnology_value = map[string]int32{
|
||||
"NONE": 0,
|
||||
"AMD_SEV": 1,
|
||||
"AMD_SEV_ES": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x GCEConfidentialTechnology) Enum() *GCEConfidentialTechnology {
|
||||
p := new(GCEConfidentialTechnology)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x GCEConfidentialTechnology) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (GCEConfidentialTechnology) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_attest_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (GCEConfidentialTechnology) Type() protoreflect.EnumType {
|
||||
return &file_attest_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x GCEConfidentialTechnology) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GCEConfidentialTechnology.Descriptor instead.
|
||||
func (GCEConfidentialTechnology) EnumDescriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// Information uniquely identifying a GCE instance. Can be used to create an
|
||||
// instance URL, which can then be used with GCE APIs. Formatted like:
|
||||
// https://www.googleapis.com/compute/v1/projects/{project_id}/zones/{zone}/instances/{instance_name}
|
||||
type GCEInstanceInfo struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Zone string `protobuf:"bytes,1,opt,name=zone,proto3" json:"zone,omitempty"`
|
||||
ProjectId string `protobuf:"bytes,2,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"`
|
||||
ProjectNumber uint64 `protobuf:"varint,3,opt,name=project_number,json=projectNumber,proto3" json:"project_number,omitempty"`
|
||||
InstanceName string `protobuf:"bytes,4,opt,name=instance_name,json=instanceName,proto3" json:"instance_name,omitempty"`
|
||||
InstanceId uint64 `protobuf:"varint,5,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) Reset() {
|
||||
*x = GCEInstanceInfo{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GCEInstanceInfo) ProtoMessage() {}
|
||||
|
||||
func (x *GCEInstanceInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GCEInstanceInfo.ProtoReflect.Descriptor instead.
|
||||
func (*GCEInstanceInfo) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) GetZone() string {
|
||||
if x != nil {
|
||||
return x.Zone
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) GetProjectId() string {
|
||||
if x != nil {
|
||||
return x.ProjectId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) GetProjectNumber() uint64 {
|
||||
if x != nil {
|
||||
return x.ProjectNumber
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) GetInstanceName() string {
|
||||
if x != nil {
|
||||
return x.InstanceName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GCEInstanceInfo) GetInstanceId() uint64 {
|
||||
if x != nil {
|
||||
return x.InstanceId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Attestation struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Attestation Key (AK) Public Area, encoded as a TPMT_PUBLIC
|
||||
AkPub []byte `protobuf:"bytes,1,opt,name=ak_pub,json=akPub,proto3" json:"ak_pub,omitempty"`
|
||||
// Quotes over all supported PCR banks
|
||||
Quotes []*tpm.Quote `protobuf:"bytes,2,rep,name=quotes,proto3" json:"quotes,omitempty"`
|
||||
// TCG Event Log, encoded in the raw binary format
|
||||
EventLog []byte `protobuf:"bytes,3,opt,name=event_log,json=eventLog,proto3" json:"event_log,omitempty"`
|
||||
// Optional information about a GCE instance, unused outside of GCE
|
||||
InstanceInfo *GCEInstanceInfo `protobuf:"bytes,4,opt,name=instance_info,json=instanceInfo,proto3" json:"instance_info,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Attestation) Reset() {
|
||||
*x = Attestation{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Attestation) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Attestation) ProtoMessage() {}
|
||||
|
||||
func (x *Attestation) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Attestation.ProtoReflect.Descriptor instead.
|
||||
func (*Attestation) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Attestation) GetAkPub() []byte {
|
||||
if x != nil {
|
||||
return x.AkPub
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Attestation) GetQuotes() []*tpm.Quote {
|
||||
if x != nil {
|
||||
return x.Quotes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Attestation) GetEventLog() []byte {
|
||||
if x != nil {
|
||||
return x.EventLog
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Attestation) GetInstanceInfo() *GCEInstanceInfo {
|
||||
if x != nil {
|
||||
return x.InstanceInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The platform/firmware state for this instance
|
||||
type PlatformState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Types that are assignable to Firmware:
|
||||
// *PlatformState_ScrtmVersionId
|
||||
// *PlatformState_GceVersion
|
||||
Firmware isPlatformState_Firmware `protobuf_oneof:"firmware"`
|
||||
// Set to NONE on non-GCE instances or non-Confidential Shielded GCE instances
|
||||
Technology GCEConfidentialTechnology `protobuf:"varint,3,opt,name=technology,proto3,enum=attest.GCEConfidentialTechnology" json:"technology,omitempty"`
|
||||
// Only set for GCE instances
|
||||
InstanceInfo *GCEInstanceInfo `protobuf:"bytes,4,opt,name=instance_info,json=instanceInfo,proto3" json:"instance_info,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PlatformState) Reset() {
|
||||
*x = PlatformState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PlatformState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PlatformState) ProtoMessage() {}
|
||||
|
||||
func (x *PlatformState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PlatformState.ProtoReflect.Descriptor instead.
|
||||
func (*PlatformState) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (m *PlatformState) GetFirmware() isPlatformState_Firmware {
|
||||
if m != nil {
|
||||
return m.Firmware
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PlatformState) GetScrtmVersionId() []byte {
|
||||
if x, ok := x.GetFirmware().(*PlatformState_ScrtmVersionId); ok {
|
||||
return x.ScrtmVersionId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PlatformState) GetGceVersion() uint32 {
|
||||
if x, ok := x.GetFirmware().(*PlatformState_GceVersion); ok {
|
||||
return x.GceVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PlatformState) GetTechnology() GCEConfidentialTechnology {
|
||||
if x != nil {
|
||||
return x.Technology
|
||||
}
|
||||
return GCEConfidentialTechnology_NONE
|
||||
}
|
||||
|
||||
func (x *PlatformState) GetInstanceInfo() *GCEInstanceInfo {
|
||||
if x != nil {
|
||||
return x.InstanceInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isPlatformState_Firmware interface {
|
||||
isPlatformState_Firmware()
|
||||
}
|
||||
|
||||
type PlatformState_ScrtmVersionId struct {
|
||||
// Raw S-CRTM version identifier (EV_S_CRTM_VERSION)
|
||||
ScrtmVersionId []byte `protobuf:"bytes,1,opt,name=scrtm_version_id,json=scrtmVersionId,proto3,oneof"`
|
||||
}
|
||||
|
||||
type PlatformState_GceVersion struct {
|
||||
// Virtual GCE firmware version (parsed from S-CRTM version id)
|
||||
GceVersion uint32 `protobuf:"varint,2,opt,name=gce_version,json=gceVersion,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*PlatformState_ScrtmVersionId) isPlatformState_Firmware() {}
|
||||
|
||||
func (*PlatformState_GceVersion) isPlatformState_Firmware() {}
|
||||
|
||||
// A parsed event from the TCG event log
|
||||
type Event struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The Platform Control Register (PCR) this event was extended into.
|
||||
PcrIndex uint32 `protobuf:"varint,1,opt,name=pcr_index,json=pcrIndex,proto3" json:"pcr_index,omitempty"`
|
||||
// The type of this event. Note that this value is not verified, so it should
|
||||
// only be used as a hint during event parsing.
|
||||
UntrustedType uint32 `protobuf:"varint,2,opt,name=untrusted_type,json=untrustedType,proto3" json:"untrusted_type,omitempty"`
|
||||
// The raw data associated to this event. The meaning of this data is
|
||||
// specific to the type of the event.
|
||||
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
|
||||
// The event digest actually extended into the TPM. This is often the hash of
|
||||
// the data field, but in some cases it may have a type-specific calculation.
|
||||
Digest []byte `protobuf:"bytes,4,opt,name=digest,proto3" json:"digest,omitempty"`
|
||||
// This is true if hash(data) == digest.
|
||||
DigestVerified bool `protobuf:"varint,5,opt,name=digest_verified,json=digestVerified,proto3" json:"digest_verified,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Event) Reset() {
|
||||
*x = Event{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Event) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Event) ProtoMessage() {}
|
||||
|
||||
func (x *Event) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Event.ProtoReflect.Descriptor instead.
|
||||
func (*Event) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Event) GetPcrIndex() uint32 {
|
||||
if x != nil {
|
||||
return x.PcrIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Event) GetUntrustedType() uint32 {
|
||||
if x != nil {
|
||||
return x.UntrustedType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Event) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Event) GetDigest() []byte {
|
||||
if x != nil {
|
||||
return x.Digest
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Event) GetDigestVerified() bool {
|
||||
if x != nil {
|
||||
return x.DigestVerified
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// The verified state of a booted machine, obtained from an Attestation
|
||||
type MachineState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Platform *PlatformState `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
// The complete parsed TCG Event Log, including those events used to
|
||||
// create the PlatformState.
|
||||
RawEvents []*Event `protobuf:"bytes,3,rep,name=raw_events,json=rawEvents,proto3" json:"raw_events,omitempty"`
|
||||
// The hash algorithm used when verifying the Attestation. This indicates:
|
||||
// - which PCR bank was used for for quote validation and event log replay
|
||||
// - the hash algorithm used to calculate event digests
|
||||
Hash tpm.HashAlgo `protobuf:"varint,4,opt,name=hash,proto3,enum=tpm.HashAlgo" json:"hash,omitempty"`
|
||||
}
|
||||
|
||||
func (x *MachineState) Reset() {
|
||||
*x = MachineState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *MachineState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*MachineState) ProtoMessage() {}
|
||||
|
||||
func (x *MachineState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MachineState.ProtoReflect.Descriptor instead.
|
||||
func (*MachineState) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *MachineState) GetPlatform() *PlatformState {
|
||||
if x != nil {
|
||||
return x.Platform
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *MachineState) GetRawEvents() []*Event {
|
||||
if x != nil {
|
||||
return x.RawEvents
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *MachineState) GetHash() tpm.HashAlgo {
|
||||
if x != nil {
|
||||
return x.Hash
|
||||
}
|
||||
return tpm.HashAlgo(0)
|
||||
}
|
||||
|
||||
// A policy dictating which values of PlatformState to allow
|
||||
type PlatformPolicy struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// If PlatformState.firmware contains a scrtm_version_id, it must appear
|
||||
// in this list. For use with a GCE VM, minimum_gce_firmware_version is
|
||||
// often a better alternative.
|
||||
AllowedScrtmVersionIds [][]byte `protobuf:"bytes,1,rep,name=allowed_scrtm_version_ids,json=allowedScrtmVersionIds,proto3" json:"allowed_scrtm_version_ids,omitempty"`
|
||||
// If PlatformState.firmware contains a minimum_gce_firmware_version, it must
|
||||
// be greater than or equal to this value. Currently, the max version is 1.
|
||||
MinimumGceFirmwareVersion uint32 `protobuf:"varint,2,opt,name=minimum_gce_firmware_version,json=minimumGceFirmwareVersion,proto3" json:"minimum_gce_firmware_version,omitempty"`
|
||||
// The PlatformState's technology must be at least as secure as
|
||||
// the specified minimum_technology (i.e. AMD_SEV_ES > AMD_SEV > NONE).
|
||||
MinimumTechnology GCEConfidentialTechnology `protobuf:"varint,3,opt,name=minimum_technology,json=minimumTechnology,proto3,enum=attest.GCEConfidentialTechnology" json:"minimum_technology,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PlatformPolicy) Reset() {
|
||||
*x = PlatformPolicy{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PlatformPolicy) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PlatformPolicy) ProtoMessage() {}
|
||||
|
||||
func (x *PlatformPolicy) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PlatformPolicy.ProtoReflect.Descriptor instead.
|
||||
func (*PlatformPolicy) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *PlatformPolicy) GetAllowedScrtmVersionIds() [][]byte {
|
||||
if x != nil {
|
||||
return x.AllowedScrtmVersionIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PlatformPolicy) GetMinimumGceFirmwareVersion() uint32 {
|
||||
if x != nil {
|
||||
return x.MinimumGceFirmwareVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PlatformPolicy) GetMinimumTechnology() GCEConfidentialTechnology {
|
||||
if x != nil {
|
||||
return x.MinimumTechnology
|
||||
}
|
||||
return GCEConfidentialTechnology_NONE
|
||||
}
|
||||
|
||||
// A policy dictating which type of MachineStates to allow
|
||||
type Policy struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Platform *PlatformPolicy `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Policy) Reset() {
|
||||
*x = Policy{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_attest_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Policy) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Policy) ProtoMessage() {}
|
||||
|
||||
func (x *Policy) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_attest_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Policy.ProtoReflect.Descriptor instead.
|
||||
func (*Policy) Descriptor() ([]byte, []int) {
|
||||
return file_attest_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *Policy) GetPlatform() *PlatformPolicy {
|
||||
if x != nil {
|
||||
return x.Platform
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_attest_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_attest_proto_rawDesc = []byte{
|
||||
0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
|
||||
0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x74, 0x70, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x22, 0xb1, 0x01, 0x0a, 0x0f, 0x47, 0x43, 0x45, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70,
|
||||
0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
|
||||
0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0xa3, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x6b, 0x5f, 0x70, 0x75, 0x62, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x6b, 0x50, 0x75, 0x62, 0x12, 0x22, 0x0a, 0x06,
|
||||
0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x74,
|
||||
0x70, 0x6d, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x06, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x12, 0x3c, 0x0a,
|
||||
0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x47, 0x43,
|
||||
0x45, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x69,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xeb, 0x01, 0x0a, 0x0d,
|
||||
0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a,
|
||||
0x10, 0x73, 0x63, 0x72, 0x74, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0e, 0x73, 0x63, 0x72, 0x74, 0x6d,
|
||||
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0b, 0x67, 0x63, 0x65,
|
||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00,
|
||||
0x52, 0x0a, 0x67, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0a,
|
||||
0x74, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x21, 0x2e, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x47, 0x43, 0x45, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c,
|
||||
0x6f, 0x67, 0x79, 0x52, 0x0a, 0x74, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x12,
|
||||
0x3c, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e,
|
||||
0x47, 0x43, 0x45, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0a, 0x0a,
|
||||
0x08, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x05, 0x45, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x63, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x63, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x12, 0x25, 0x0a, 0x0e, 0x75, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x79,
|
||||
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x75, 0x6e, 0x74, 0x72, 0x75, 0x73,
|
||||
0x74, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x64,
|
||||
0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, 0x67,
|
||||
0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65,
|
||||
0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69,
|
||||
0x67, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x22, 0x92, 0x01, 0x0a,
|
||||
0x0c, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a,
|
||||
0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x15, 0x2e, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
|
||||
0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x12, 0x2c, 0x0a, 0x0a, 0x72, 0x61, 0x77, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x61, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21,
|
||||
0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x74,
|
||||
0x70, 0x6d, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x04, 0x68, 0x61, 0x73,
|
||||
0x68, 0x22, 0xde, 0x01, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x50, 0x6f,
|
||||
0x6c, 0x69, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x19, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f,
|
||||
0x73, 0x63, 0x72, 0x74, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
|
||||
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x16, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64,
|
||||
0x53, 0x63, 0x72, 0x74, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12,
|
||||
0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x67, 0x63, 0x65, 0x5f, 0x66,
|
||||
0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x47, 0x63,
|
||||
0x65, 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x50, 0x0a, 0x12, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x74, 0x65, 0x63, 0x68,
|
||||
0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x61,
|
||||
0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x47, 0x43, 0x45, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x52,
|
||||
0x11, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f,
|
||||
0x67, 0x79, 0x22, 0x3c, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x32, 0x0a, 0x08,
|
||||
0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
|
||||
0x2e, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x2a, 0x42, 0x0a, 0x19, 0x47, 0x43, 0x45, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x12, 0x08, 0x0a,
|
||||
0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x44, 0x5f, 0x53,
|
||||
0x45, 0x56, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x4d, 0x44, 0x5f, 0x53, 0x45, 0x56, 0x5f,
|
||||
0x45, 0x53, 0x10, 0x02, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x67, 0x6f, 0x2d, 0x74, 0x70, 0x6d,
|
||||
0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x74, 0x74,
|
||||
0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_attest_proto_rawDescOnce sync.Once
|
||||
file_attest_proto_rawDescData = file_attest_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_attest_proto_rawDescGZIP() []byte {
|
||||
file_attest_proto_rawDescOnce.Do(func() {
|
||||
file_attest_proto_rawDescData = protoimpl.X.CompressGZIP(file_attest_proto_rawDescData)
|
||||
})
|
||||
return file_attest_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_attest_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_attest_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_attest_proto_goTypes = []interface{}{
|
||||
(GCEConfidentialTechnology)(0), // 0: attest.GCEConfidentialTechnology
|
||||
(*GCEInstanceInfo)(nil), // 1: attest.GCEInstanceInfo
|
||||
(*Attestation)(nil), // 2: attest.Attestation
|
||||
(*PlatformState)(nil), // 3: attest.PlatformState
|
||||
(*Event)(nil), // 4: attest.Event
|
||||
(*MachineState)(nil), // 5: attest.MachineState
|
||||
(*PlatformPolicy)(nil), // 6: attest.PlatformPolicy
|
||||
(*Policy)(nil), // 7: attest.Policy
|
||||
(*tpm.Quote)(nil), // 8: tpm.Quote
|
||||
(tpm.HashAlgo)(0), // 9: tpm.HashAlgo
|
||||
}
|
||||
var file_attest_proto_depIdxs = []int32{
|
||||
8, // 0: attest.Attestation.quotes:type_name -> tpm.Quote
|
||||
1, // 1: attest.Attestation.instance_info:type_name -> attest.GCEInstanceInfo
|
||||
0, // 2: attest.PlatformState.technology:type_name -> attest.GCEConfidentialTechnology
|
||||
1, // 3: attest.PlatformState.instance_info:type_name -> attest.GCEInstanceInfo
|
||||
3, // 4: attest.MachineState.platform:type_name -> attest.PlatformState
|
||||
4, // 5: attest.MachineState.raw_events:type_name -> attest.Event
|
||||
9, // 6: attest.MachineState.hash:type_name -> tpm.HashAlgo
|
||||
0, // 7: attest.PlatformPolicy.minimum_technology:type_name -> attest.GCEConfidentialTechnology
|
||||
6, // 8: attest.Policy.platform:type_name -> attest.PlatformPolicy
|
||||
9, // [9:9] is the sub-list for method output_type
|
||||
9, // [9:9] is the sub-list for method input_type
|
||||
9, // [9:9] is the sub-list for extension type_name
|
||||
9, // [9:9] is the sub-list for extension extendee
|
||||
0, // [0:9] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_attest_proto_init() }
|
||||
func file_attest_proto_init() {
|
||||
if File_attest_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_attest_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GCEInstanceInfo); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Attestation); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PlatformState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Event); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*MachineState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PlatformPolicy); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Policy); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_attest_proto_msgTypes[2].OneofWrappers = []interface{}{
|
||||
(*PlatformState_ScrtmVersionId)(nil),
|
||||
(*PlatformState_GceVersion)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_attest_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 7,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_attest_proto_goTypes,
|
||||
DependencyIndexes: file_attest_proto_depIdxs,
|
||||
EnumInfos: file_attest_proto_enumTypes,
|
||||
MessageInfos: file_attest_proto_msgTypes,
|
||||
}.Build()
|
||||
File_attest_proto = out.File
|
||||
file_attest_proto_rawDesc = nil
|
||||
file_attest_proto_goTypes = nil
|
||||
file_attest_proto_depIdxs = nil
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["tpm.pb.go"],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm-tools/proto/tpm",
|
||||
importpath = "github.com/google/go-tpm-tools/proto/tpm",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/google.golang.org/protobuf/reflect/protoreflect:go_default_library",
|
||||
"//vendor/google.golang.org/protobuf/runtime/protoimpl:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,595 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.17.3
|
||||
// source: tpm.proto
|
||||
|
||||
package tpm
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Enum values come from TCG Algorithm Registry - v1.27 - Table 3
|
||||
type ObjectType int32
|
||||
|
||||
const (
|
||||
ObjectType_OBJECT_INVALID ObjectType = 0
|
||||
ObjectType_RSA ObjectType = 1
|
||||
ObjectType_ECC ObjectType = 35
|
||||
)
|
||||
|
||||
// Enum value maps for ObjectType.
|
||||
var (
|
||||
ObjectType_name = map[int32]string{
|
||||
0: "OBJECT_INVALID",
|
||||
1: "RSA",
|
||||
35: "ECC",
|
||||
}
|
||||
ObjectType_value = map[string]int32{
|
||||
"OBJECT_INVALID": 0,
|
||||
"RSA": 1,
|
||||
"ECC": 35,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ObjectType) Enum() *ObjectType {
|
||||
p := new(ObjectType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ObjectType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ObjectType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_tpm_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (ObjectType) Type() protoreflect.EnumType {
|
||||
return &file_tpm_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x ObjectType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ObjectType.Descriptor instead.
|
||||
func (ObjectType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_tpm_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type HashAlgo int32
|
||||
|
||||
const (
|
||||
HashAlgo_HASH_INVALID HashAlgo = 0
|
||||
HashAlgo_SHA1 HashAlgo = 4
|
||||
HashAlgo_SHA256 HashAlgo = 11
|
||||
HashAlgo_SHA384 HashAlgo = 12
|
||||
HashAlgo_SHA512 HashAlgo = 13
|
||||
)
|
||||
|
||||
// Enum value maps for HashAlgo.
|
||||
var (
|
||||
HashAlgo_name = map[int32]string{
|
||||
0: "HASH_INVALID",
|
||||
4: "SHA1",
|
||||
11: "SHA256",
|
||||
12: "SHA384",
|
||||
13: "SHA512",
|
||||
}
|
||||
HashAlgo_value = map[string]int32{
|
||||
"HASH_INVALID": 0,
|
||||
"SHA1": 4,
|
||||
"SHA256": 11,
|
||||
"SHA384": 12,
|
||||
"SHA512": 13,
|
||||
}
|
||||
)
|
||||
|
||||
func (x HashAlgo) Enum() *HashAlgo {
|
||||
p := new(HashAlgo)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x HashAlgo) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (HashAlgo) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_tpm_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (HashAlgo) Type() protoreflect.EnumType {
|
||||
return &file_tpm_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x HashAlgo) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HashAlgo.Descriptor instead.
|
||||
func (HashAlgo) EnumDescriptor() ([]byte, []int) {
|
||||
return file_tpm_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
// SealedBytes stores the result of a TPM2_Seal. The private portion (priv) has
|
||||
// already been encrypted and is no longer sensitive. The hash algorithm is
|
||||
// assumed to be SHA256.
|
||||
type SealedBytes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Priv []byte `protobuf:"bytes,1,opt,name=priv,proto3" json:"priv,omitempty"`
|
||||
Pub []byte `protobuf:"bytes,2,opt,name=pub,proto3" json:"pub,omitempty"`
|
||||
Pcrs []uint32 `protobuf:"varint,3,rep,packed,name=pcrs,proto3" json:"pcrs,omitempty"`
|
||||
Hash HashAlgo `protobuf:"varint,4,opt,name=hash,proto3,enum=tpm.HashAlgo" json:"hash,omitempty"`
|
||||
Srk ObjectType `protobuf:"varint,5,opt,name=srk,proto3,enum=tpm.ObjectType" json:"srk,omitempty"`
|
||||
CertifiedPcrs *PCRs `protobuf:"bytes,6,opt,name=certified_pcrs,json=certifiedPcrs,proto3" json:"certified_pcrs,omitempty"`
|
||||
CreationData []byte `protobuf:"bytes,7,opt,name=creation_data,json=creationData,proto3" json:"creation_data,omitempty"`
|
||||
Ticket []byte `protobuf:"bytes,8,opt,name=ticket,proto3" json:"ticket,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SealedBytes) Reset() {
|
||||
*x = SealedBytes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_tpm_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SealedBytes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SealedBytes) ProtoMessage() {}
|
||||
|
||||
func (x *SealedBytes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_tpm_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SealedBytes.ProtoReflect.Descriptor instead.
|
||||
func (*SealedBytes) Descriptor() ([]byte, []int) {
|
||||
return file_tpm_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetPriv() []byte {
|
||||
if x != nil {
|
||||
return x.Priv
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetPub() []byte {
|
||||
if x != nil {
|
||||
return x.Pub
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetPcrs() []uint32 {
|
||||
if x != nil {
|
||||
return x.Pcrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetHash() HashAlgo {
|
||||
if x != nil {
|
||||
return x.Hash
|
||||
}
|
||||
return HashAlgo_HASH_INVALID
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetSrk() ObjectType {
|
||||
if x != nil {
|
||||
return x.Srk
|
||||
}
|
||||
return ObjectType_OBJECT_INVALID
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetCertifiedPcrs() *PCRs {
|
||||
if x != nil {
|
||||
return x.CertifiedPcrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetCreationData() []byte {
|
||||
if x != nil {
|
||||
return x.CreationData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SealedBytes) GetTicket() []byte {
|
||||
if x != nil {
|
||||
return x.Ticket
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImportBlob struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Duplicate []byte `protobuf:"bytes,1,opt,name=duplicate,proto3" json:"duplicate,omitempty"`
|
||||
EncryptedSeed []byte `protobuf:"bytes,2,opt,name=encrypted_seed,json=encryptedSeed,proto3" json:"encrypted_seed,omitempty"`
|
||||
PublicArea []byte `protobuf:"bytes,3,opt,name=public_area,json=publicArea,proto3" json:"public_area,omitempty"`
|
||||
Pcrs *PCRs `protobuf:"bytes,4,opt,name=pcrs,proto3" json:"pcrs,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ImportBlob) Reset() {
|
||||
*x = ImportBlob{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_tpm_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ImportBlob) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ImportBlob) ProtoMessage() {}
|
||||
|
||||
func (x *ImportBlob) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_tpm_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ImportBlob.ProtoReflect.Descriptor instead.
|
||||
func (*ImportBlob) Descriptor() ([]byte, []int) {
|
||||
return file_tpm_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ImportBlob) GetDuplicate() []byte {
|
||||
if x != nil {
|
||||
return x.Duplicate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ImportBlob) GetEncryptedSeed() []byte {
|
||||
if x != nil {
|
||||
return x.EncryptedSeed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ImportBlob) GetPublicArea() []byte {
|
||||
if x != nil {
|
||||
return x.PublicArea
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ImportBlob) GetPcrs() *PCRs {
|
||||
if x != nil {
|
||||
return x.Pcrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Quote struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// TPM2 quote, encoded as a TPMS_ATTEST
|
||||
Quote []byte `protobuf:"bytes,1,opt,name=quote,proto3" json:"quote,omitempty"`
|
||||
// TPM2 signature, encoded as a TPMT_SIGNATURE
|
||||
RawSig []byte `protobuf:"bytes,2,opt,name=raw_sig,json=rawSig,proto3" json:"raw_sig,omitempty"`
|
||||
// PCR values of the bank being quoted
|
||||
Pcrs *PCRs `protobuf:"bytes,3,opt,name=pcrs,proto3" json:"pcrs,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Quote) Reset() {
|
||||
*x = Quote{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_tpm_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Quote) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Quote) ProtoMessage() {}
|
||||
|
||||
func (x *Quote) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_tpm_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Quote.ProtoReflect.Descriptor instead.
|
||||
func (*Quote) Descriptor() ([]byte, []int) {
|
||||
return file_tpm_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Quote) GetQuote() []byte {
|
||||
if x != nil {
|
||||
return x.Quote
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Quote) GetRawSig() []byte {
|
||||
if x != nil {
|
||||
return x.RawSig
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Quote) GetPcrs() *PCRs {
|
||||
if x != nil {
|
||||
return x.Pcrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PCRs struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Hash HashAlgo `protobuf:"varint,1,opt,name=hash,proto3,enum=tpm.HashAlgo" json:"hash,omitempty"`
|
||||
Pcrs map[uint32][]byte `protobuf:"bytes,2,rep,name=pcrs,proto3" json:"pcrs,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *PCRs) Reset() {
|
||||
*x = PCRs{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_tpm_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PCRs) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PCRs) ProtoMessage() {}
|
||||
|
||||
func (x *PCRs) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_tpm_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PCRs.ProtoReflect.Descriptor instead.
|
||||
func (*PCRs) Descriptor() ([]byte, []int) {
|
||||
return file_tpm_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *PCRs) GetHash() HashAlgo {
|
||||
if x != nil {
|
||||
return x.Hash
|
||||
}
|
||||
return HashAlgo_HASH_INVALID
|
||||
}
|
||||
|
||||
func (x *PCRs) GetPcrs() map[uint32][]byte {
|
||||
if x != nil {
|
||||
return x.Pcrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_tpm_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_tpm_proto_rawDesc = []byte{
|
||||
0x0a, 0x09, 0x74, 0x70, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x74, 0x70, 0x6d,
|
||||
0x22, 0xfc, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x70, 0x72, 0x69, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
|
||||
0x70, 0x72, 0x69, 0x76, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x75, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x03, 0x70, 0x75, 0x62, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x63, 0x72, 0x73, 0x18, 0x03,
|
||||
0x20, 0x03, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x63, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x68, 0x61,
|
||||
0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x74, 0x70, 0x6d, 0x2e, 0x48,
|
||||
0x61, 0x73, 0x68, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a,
|
||||
0x03, 0x73, 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x74, 0x70, 0x6d,
|
||||
0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x03, 0x73, 0x72, 0x6b,
|
||||
0x12, 0x30, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x70, 0x63,
|
||||
0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x74, 0x70, 0x6d, 0x2e, 0x50,
|
||||
0x43, 0x52, 0x73, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x63,
|
||||
0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64,
|
||||
0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65,
|
||||
0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x22,
|
||||
0x91, 0x01, 0x0a, 0x0a, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1c,
|
||||
0x0a, 0x09, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x09, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e,
|
||||
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x53,
|
||||
0x65, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x72,
|
||||
0x65, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x41, 0x72, 0x65, 0x61, 0x12, 0x1d, 0x0a, 0x04, 0x70, 0x63, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x09, 0x2e, 0x74, 0x70, 0x6d, 0x2e, 0x50, 0x43, 0x52, 0x73, 0x52, 0x04, 0x70,
|
||||
0x63, 0x72, 0x73, 0x22, 0x55, 0x0a, 0x05, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x6f,
|
||||
0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x69, 0x67, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x61, 0x77, 0x53, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x04, 0x70,
|
||||
0x63, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x74, 0x70, 0x6d, 0x2e,
|
||||
0x50, 0x43, 0x52, 0x73, 0x52, 0x04, 0x70, 0x63, 0x72, 0x73, 0x22, 0x8b, 0x01, 0x0a, 0x04, 0x50,
|
||||
0x43, 0x52, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0e, 0x32, 0x0d, 0x2e, 0x74, 0x70, 0x6d, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x41, 0x6c, 0x67, 0x6f,
|
||||
0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x04, 0x70, 0x63, 0x72, 0x73, 0x18, 0x02,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x70, 0x6d, 0x2e, 0x50, 0x43, 0x52, 0x73, 0x2e,
|
||||
0x50, 0x63, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x70, 0x63, 0x72, 0x73, 0x1a,
|
||||
0x37, 0x0a, 0x09, 0x50, 0x63, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x32, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54,
|
||||
0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x52, 0x53,
|
||||
0x41, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x43, 0x43, 0x10, 0x23, 0x2a, 0x4a, 0x0a, 0x08,
|
||||
0x48, 0x61, 0x73, 0x68, 0x41, 0x6c, 0x67, 0x6f, 0x12, 0x10, 0x0a, 0x0c, 0x48, 0x41, 0x53, 0x48,
|
||||
0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x48,
|
||||
0x41, 0x31, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x0b,
|
||||
0x12, 0x0a, 0x0a, 0x06, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x10, 0x0c, 0x12, 0x0a, 0x0a, 0x06,
|
||||
0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x10, 0x0d, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x67, 0x6f,
|
||||
0x2d, 0x74, 0x70, 0x6d, 0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x74, 0x70, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_tpm_proto_rawDescOnce sync.Once
|
||||
file_tpm_proto_rawDescData = file_tpm_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_tpm_proto_rawDescGZIP() []byte {
|
||||
file_tpm_proto_rawDescOnce.Do(func() {
|
||||
file_tpm_proto_rawDescData = protoimpl.X.CompressGZIP(file_tpm_proto_rawDescData)
|
||||
})
|
||||
return file_tpm_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_tpm_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_tpm_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_tpm_proto_goTypes = []interface{}{
|
||||
(ObjectType)(0), // 0: tpm.ObjectType
|
||||
(HashAlgo)(0), // 1: tpm.HashAlgo
|
||||
(*SealedBytes)(nil), // 2: tpm.SealedBytes
|
||||
(*ImportBlob)(nil), // 3: tpm.ImportBlob
|
||||
(*Quote)(nil), // 4: tpm.Quote
|
||||
(*PCRs)(nil), // 5: tpm.PCRs
|
||||
nil, // 6: tpm.PCRs.PcrsEntry
|
||||
}
|
||||
var file_tpm_proto_depIdxs = []int32{
|
||||
1, // 0: tpm.SealedBytes.hash:type_name -> tpm.HashAlgo
|
||||
0, // 1: tpm.SealedBytes.srk:type_name -> tpm.ObjectType
|
||||
5, // 2: tpm.SealedBytes.certified_pcrs:type_name -> tpm.PCRs
|
||||
5, // 3: tpm.ImportBlob.pcrs:type_name -> tpm.PCRs
|
||||
5, // 4: tpm.Quote.pcrs:type_name -> tpm.PCRs
|
||||
1, // 5: tpm.PCRs.hash:type_name -> tpm.HashAlgo
|
||||
6, // 6: tpm.PCRs.pcrs:type_name -> tpm.PCRs.PcrsEntry
|
||||
7, // [7:7] is the sub-list for method output_type
|
||||
7, // [7:7] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_tpm_proto_init() }
|
||||
func file_tpm_proto_init() {
|
||||
if File_tpm_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_tpm_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SealedBytes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_tpm_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ImportBlob); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_tpm_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Quote); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_tpm_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PCRs); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_tpm_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_tpm_proto_goTypes,
|
||||
DependencyIndexes: file_tpm_proto_depIdxs,
|
||||
EnumInfos: file_tpm_proto_enumTypes,
|
||||
MessageInfos: file_tpm_proto_msgTypes,
|
||||
}.Build()
|
||||
File_tpm_proto = out.File
|
||||
file_tpm_proto_rawDesc = nil
|
||||
file_tpm_proto_goTypes = nil
|
||||
file_tpm_proto_depIdxs = nil
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"constants.go",
|
||||
"error.go",
|
||||
"kdf.go",
|
||||
"open_other.go",
|
||||
"open_windows.go",
|
||||
"structures.go",
|
||||
"tpm2.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm/tpm2",
|
||||
importpath = "github.com/google/go-tpm/tpm2",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/go-tpm/tpmutil:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"//vendor/github.com/google/go-tpm/tpmutil/tbs:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
|
@ -0,0 +1,35 @@
|
|||
# TPM 2.0 client library
|
||||
|
||||
## Tests
|
||||
|
||||
This library contains unit tests in `github.com/google/go-tpm/tpm2`, which just
|
||||
tests that various encoding and error checking functions work correctly. It also
|
||||
contains more comprehensive integration tests in
|
||||
`github.com/google/go-tpm/tpm2/test`, which run actual commands on a TPM.
|
||||
|
||||
By default, these integration tests are run against the
|
||||
[`go-tpm-tools`](https://github.com/google/go-tpm-tools)
|
||||
simulator, which is baesed on the
|
||||
[Microsoft Reference TPM2 code](https://github.com/microsoft/ms-tpm-20-ref). To
|
||||
run both the unit and integration tests, run (in this directory)
|
||||
```bash
|
||||
go test . ./test
|
||||
```
|
||||
|
||||
These integration tests can also be run against a real TPM device. This is
|
||||
slightly more complex as the tests often need to be built as a normal user and
|
||||
then executed as root. For example,
|
||||
```bash
|
||||
# Build the test binary without running it
|
||||
go test -c github.com/google/go-tpm/tpm2/test
|
||||
# Execute the test binary as root
|
||||
sudo ./test.test --tpm-path=/dev/tpmrm0
|
||||
```
|
||||
On Linux, The `--tpm-path` causes the integration tests to be run against a
|
||||
real TPM located at that path (usually `/dev/tpmrm0` or `/dev/tpm0`). On Windows, the story is similar, execept that
|
||||
the `--use-tbs` flag is used instead.
|
||||
|
||||
Tip: if your TPM host is remote and you don't want to install Go on it, this
|
||||
same two-step process can be used. The test binary can be copied to a remote
|
||||
host and run without extra installation (as the test binary has very few
|
||||
*runtime* dependancies).
|
|
@ -0,0 +1,500 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpm2
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
// Register the relevant hash implementations to prevent a runtime failure.
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
var hashInfo = []struct {
|
||||
alg Algorithm
|
||||
hash crypto.Hash
|
||||
}{
|
||||
{AlgSHA1, crypto.SHA1},
|
||||
{AlgSHA256, crypto.SHA256},
|
||||
{AlgSHA384, crypto.SHA384},
|
||||
{AlgSHA512, crypto.SHA512},
|
||||
{AlgSHA3_256, crypto.SHA3_256},
|
||||
{AlgSHA3_384, crypto.SHA3_384},
|
||||
{AlgSHA3_512, crypto.SHA3_512},
|
||||
}
|
||||
|
||||
// MAX_DIGEST_BUFFER is the maximum size of []byte request or response fields.
|
||||
// Typically used for chunking of big blobs of data (such as for hashing or
|
||||
// encryption).
|
||||
const maxDigestBuffer = 1024
|
||||
|
||||
// Algorithm represents a TPM_ALG_ID value.
|
||||
type Algorithm uint16
|
||||
|
||||
// HashToAlgorithm looks up the TPM2 algorithm corresponding to the provided crypto.Hash
|
||||
func HashToAlgorithm(hash crypto.Hash) (Algorithm, error) {
|
||||
for _, info := range hashInfo {
|
||||
if info.hash == hash {
|
||||
return info.alg, nil
|
||||
}
|
||||
}
|
||||
return AlgUnknown, fmt.Errorf("go hash algorithm #%d has no TPM2 algorithm", hash)
|
||||
}
|
||||
|
||||
// IsNull returns true if a is AlgNull or zero (unset).
|
||||
func (a Algorithm) IsNull() bool {
|
||||
return a == AlgNull || a == AlgUnknown
|
||||
}
|
||||
|
||||
// UsesCount returns true if a signature algorithm uses count value.
|
||||
func (a Algorithm) UsesCount() bool {
|
||||
return a == AlgECDAA
|
||||
}
|
||||
|
||||
// UsesHash returns true if the algorithm requires the use of a hash.
|
||||
func (a Algorithm) UsesHash() bool {
|
||||
return a == AlgOAEP
|
||||
}
|
||||
|
||||
// Hash returns a crypto.Hash based on the given TPM_ALG_ID.
|
||||
// An error is returned if the given algorithm is not a hash algorithm or is not available.
|
||||
func (a Algorithm) Hash() (crypto.Hash, error) {
|
||||
for _, info := range hashInfo {
|
||||
if info.alg == a {
|
||||
if !info.hash.Available() {
|
||||
return crypto.Hash(0), fmt.Errorf("go hash algorithm #%d not available", info.hash)
|
||||
}
|
||||
return info.hash, nil
|
||||
}
|
||||
}
|
||||
return crypto.Hash(0), fmt.Errorf("hash algorithm not supported: 0x%x", a)
|
||||
}
|
||||
|
||||
// Supported Algorithms.
|
||||
const (
|
||||
AlgUnknown Algorithm = 0x0000
|
||||
AlgRSA Algorithm = 0x0001
|
||||
AlgSHA1 Algorithm = 0x0004
|
||||
AlgHMAC Algorithm = 0x0005
|
||||
AlgAES Algorithm = 0x0006
|
||||
AlgKeyedHash Algorithm = 0x0008
|
||||
AlgXOR Algorithm = 0x000A
|
||||
AlgSHA256 Algorithm = 0x000B
|
||||
AlgSHA384 Algorithm = 0x000C
|
||||
AlgSHA512 Algorithm = 0x000D
|
||||
AlgNull Algorithm = 0x0010
|
||||
AlgRSASSA Algorithm = 0x0014
|
||||
AlgRSAES Algorithm = 0x0015
|
||||
AlgRSAPSS Algorithm = 0x0016
|
||||
AlgOAEP Algorithm = 0x0017
|
||||
AlgECDSA Algorithm = 0x0018
|
||||
AlgECDH Algorithm = 0x0019
|
||||
AlgECDAA Algorithm = 0x001A
|
||||
AlgKDF2 Algorithm = 0x0021
|
||||
AlgECC Algorithm = 0x0023
|
||||
AlgSymCipher Algorithm = 0x0025
|
||||
AlgSHA3_256 Algorithm = 0x0027
|
||||
AlgSHA3_384 Algorithm = 0x0028
|
||||
AlgSHA3_512 Algorithm = 0x0029
|
||||
AlgCTR Algorithm = 0x0040
|
||||
AlgOFB Algorithm = 0x0041
|
||||
AlgCBC Algorithm = 0x0042
|
||||
AlgCFB Algorithm = 0x0043
|
||||
AlgECB Algorithm = 0x0044
|
||||
)
|
||||
|
||||
// HandleType defines a type of handle.
|
||||
type HandleType uint8
|
||||
|
||||
// Supported handle types
|
||||
const (
|
||||
HandleTypePCR HandleType = 0x00
|
||||
HandleTypeNVIndex HandleType = 0x01
|
||||
HandleTypeHMACSession HandleType = 0x02
|
||||
HandleTypeLoadedSession HandleType = 0x02
|
||||
HandleTypePolicySession HandleType = 0x03
|
||||
HandleTypeSavedSession HandleType = 0x03
|
||||
HandleTypePermanent HandleType = 0x40
|
||||
HandleTypeTransient HandleType = 0x80
|
||||
HandleTypePersistent HandleType = 0x81
|
||||
)
|
||||
|
||||
// SessionType defines the type of session created in StartAuthSession.
|
||||
type SessionType uint8
|
||||
|
||||
// Supported session types.
|
||||
const (
|
||||
SessionHMAC SessionType = 0x00
|
||||
SessionPolicy SessionType = 0x01
|
||||
SessionTrial SessionType = 0x03
|
||||
)
|
||||
|
||||
// SessionAttributes represents an attribute of a session.
|
||||
type SessionAttributes byte
|
||||
|
||||
// Session Attributes (Structures 8.4 TPMA_SESSION)
|
||||
const (
|
||||
AttrContinueSession SessionAttributes = 1 << iota
|
||||
AttrAuditExclusive
|
||||
AttrAuditReset
|
||||
_ // bit 3 reserved
|
||||
_ // bit 4 reserved
|
||||
AttrDecrypt
|
||||
AttrEcrypt
|
||||
AttrAudit
|
||||
)
|
||||
|
||||
// EmptyAuth represents the empty authorization value.
|
||||
var EmptyAuth []byte
|
||||
|
||||
// KeyProp is a bitmask used in Attributes field of key templates. Individual
|
||||
// flags should be OR-ed to form a full mask.
|
||||
type KeyProp uint32
|
||||
|
||||
// Key properties.
|
||||
const (
|
||||
FlagFixedTPM KeyProp = 0x00000002
|
||||
FlagStClear KeyProp = 0x00000004
|
||||
FlagFixedParent KeyProp = 0x00000010
|
||||
FlagSensitiveDataOrigin KeyProp = 0x00000020
|
||||
FlagUserWithAuth KeyProp = 0x00000040
|
||||
FlagAdminWithPolicy KeyProp = 0x00000080
|
||||
FlagNoDA KeyProp = 0x00000400
|
||||
FlagRestricted KeyProp = 0x00010000
|
||||
FlagDecrypt KeyProp = 0x00020000
|
||||
FlagSign KeyProp = 0x00040000
|
||||
|
||||
FlagSealDefault = FlagFixedTPM | FlagFixedParent
|
||||
FlagSignerDefault = FlagSign | FlagRestricted | FlagFixedTPM |
|
||||
FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth
|
||||
FlagStorageDefault = FlagDecrypt | FlagRestricted | FlagFixedTPM |
|
||||
FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth
|
||||
)
|
||||
|
||||
// TPMProp represents a Property Tag (TPM_PT) used with calls to GetCapability(CapabilityTPMProperties).
|
||||
type TPMProp uint32
|
||||
|
||||
// TPM Capability Properties, see TPM 2.0 Spec, Rev 1.38, Table 23.
|
||||
// Fixed TPM Properties (PT_FIXED)
|
||||
const (
|
||||
FamilyIndicator TPMProp = 0x100 + iota
|
||||
SpecLevel
|
||||
SpecRevision
|
||||
SpecDayOfYear
|
||||
SpecYear
|
||||
Manufacturer
|
||||
VendorString1
|
||||
VendorString2
|
||||
VendorString3
|
||||
VendorString4
|
||||
VendorTPMType
|
||||
FirmwareVersion1
|
||||
FirmwareVersion2
|
||||
InputMaxBufferSize
|
||||
TransientObjectsMin
|
||||
PersistentObjectsMin
|
||||
LoadedObjectsMin
|
||||
ActiveSessionsMax
|
||||
PCRCount
|
||||
PCRSelectMin
|
||||
ContextGapMax
|
||||
_ // (PT_FIXED + 21) is skipped
|
||||
NVCountersMax
|
||||
NVIndexMax
|
||||
MemoryMethod
|
||||
ClockUpdate
|
||||
ContextHash
|
||||
ContextSym
|
||||
ContextSymSize
|
||||
OrderlyCount
|
||||
CommandMaxSize
|
||||
ResponseMaxSize
|
||||
DigestMaxSize
|
||||
ObjectContextMaxSize
|
||||
SessionContextMaxSize
|
||||
PSFamilyIndicator
|
||||
PSSpecLevel
|
||||
PSSpecRevision
|
||||
PSSpecDayOfYear
|
||||
PSSpecYear
|
||||
SplitSigningMax
|
||||
TotalCommands
|
||||
LibraryCommands
|
||||
VendorCommands
|
||||
NVMaxBufferSize
|
||||
TPMModes
|
||||
CapabilityMaxBufferSize
|
||||
)
|
||||
|
||||
// Variable TPM Properties (PT_VAR)
|
||||
const (
|
||||
TPMAPermanent TPMProp = 0x200 + iota
|
||||
TPMAStartupClear
|
||||
HRNVIndex
|
||||
HRLoaded
|
||||
HRLoadedAvail
|
||||
HRActive
|
||||
HRActiveAvail
|
||||
HRTransientAvail
|
||||
CurrentPersistent
|
||||
AvailPersistent
|
||||
NVCounters
|
||||
NVCountersAvail
|
||||
AlgorithmSet
|
||||
LoadedCurves
|
||||
LockoutCounter
|
||||
MaxAuthFail
|
||||
LockoutInterval
|
||||
LockoutRecovery
|
||||
NVWriteRecovery
|
||||
AuditCounter0
|
||||
AuditCounter1
|
||||
)
|
||||
|
||||
// Allowed ranges of different kinds of Handles (TPM_HANDLE)
|
||||
// These constants have type TPMProp for backwards compatibility.
|
||||
const (
|
||||
PCRFirst TPMProp = 0x00000000
|
||||
HMACSessionFirst TPMProp = 0x02000000
|
||||
LoadedSessionFirst TPMProp = 0x02000000
|
||||
PolicySessionFirst TPMProp = 0x03000000
|
||||
ActiveSessionFirst TPMProp = 0x03000000
|
||||
TransientFirst TPMProp = 0x80000000
|
||||
PersistentFirst TPMProp = 0x81000000
|
||||
PersistentLast TPMProp = 0x81FFFFFF
|
||||
PlatformPersistent TPMProp = 0x81800000
|
||||
NVIndexFirst TPMProp = 0x01000000
|
||||
NVIndexLast TPMProp = 0x01FFFFFF
|
||||
PermanentFirst TPMProp = 0x40000000
|
||||
PermanentLast TPMProp = 0x4000010F
|
||||
)
|
||||
|
||||
// Reserved Handles.
|
||||
const (
|
||||
HandleOwner tpmutil.Handle = 0x40000001 + iota
|
||||
HandleRevoke
|
||||
HandleTransport
|
||||
HandleOperator
|
||||
HandleAdmin
|
||||
HandleEK
|
||||
HandleNull
|
||||
HandleUnassigned
|
||||
HandlePasswordSession
|
||||
HandleLockout
|
||||
HandleEndorsement
|
||||
HandlePlatform
|
||||
)
|
||||
|
||||
// Capability identifies some TPM property or state type.
|
||||
type Capability uint32
|
||||
|
||||
// TPM Capabilities.
|
||||
const (
|
||||
CapabilityAlgs Capability = iota
|
||||
CapabilityHandles
|
||||
CapabilityCommands
|
||||
CapabilityPPCommands
|
||||
CapabilityAuditCommands
|
||||
CapabilityPCRs
|
||||
CapabilityTPMProperties
|
||||
CapabilityPCRProperties
|
||||
CapabilityECCCurves
|
||||
CapabilityAuthPolicies
|
||||
)
|
||||
|
||||
// TPM Structure Tags. Tags are used to disambiguate structures, similar to Alg
|
||||
// values: tag value defines what kind of data lives in a nested field.
|
||||
const (
|
||||
TagNull tpmutil.Tag = 0x8000
|
||||
TagNoSessions tpmutil.Tag = 0x8001
|
||||
TagSessions tpmutil.Tag = 0x8002
|
||||
TagAttestCertify tpmutil.Tag = 0x8017
|
||||
TagAttestQuote tpmutil.Tag = 0x8018
|
||||
TagAttestCreation tpmutil.Tag = 0x801a
|
||||
TagHashCheck tpmutil.Tag = 0x8024
|
||||
)
|
||||
|
||||
// StartupType instructs the TPM on how to handle its state during Shutdown or
|
||||
// Startup.
|
||||
type StartupType uint16
|
||||
|
||||
// Startup types
|
||||
const (
|
||||
StartupClear StartupType = iota
|
||||
StartupState
|
||||
)
|
||||
|
||||
// EllipticCurve identifies specific EC curves.
|
||||
type EllipticCurve uint16
|
||||
|
||||
// ECC curves supported by TPM 2.0 spec.
|
||||
const (
|
||||
CurveNISTP192 = EllipticCurve(iota + 1)
|
||||
CurveNISTP224
|
||||
CurveNISTP256
|
||||
CurveNISTP384
|
||||
CurveNISTP521
|
||||
|
||||
CurveBNP256 = EllipticCurve(iota + 10)
|
||||
CurveBNP638
|
||||
|
||||
CurveSM2P256 = EllipticCurve(0x0020)
|
||||
)
|
||||
|
||||
var toGoCurve = map[EllipticCurve]elliptic.Curve{
|
||||
CurveNISTP224: elliptic.P224(),
|
||||
CurveNISTP256: elliptic.P256(),
|
||||
CurveNISTP384: elliptic.P384(),
|
||||
CurveNISTP521: elliptic.P521(),
|
||||
}
|
||||
|
||||
// Supported TPM operations.
|
||||
const (
|
||||
CmdNVUndefineSpaceSpecial tpmutil.Command = 0x0000011F
|
||||
CmdEvictControl tpmutil.Command = 0x00000120
|
||||
CmdUndefineSpace tpmutil.Command = 0x00000122
|
||||
CmdClear tpmutil.Command = 0x00000126
|
||||
CmdHierarchyChangeAuth tpmutil.Command = 0x00000129
|
||||
CmdDefineSpace tpmutil.Command = 0x0000012A
|
||||
CmdCreatePrimary tpmutil.Command = 0x00000131
|
||||
CmdIncrementNVCounter tpmutil.Command = 0x00000134
|
||||
CmdWriteNV tpmutil.Command = 0x00000137
|
||||
CmdWriteLockNV tpmutil.Command = 0x00000138
|
||||
CmdDictionaryAttackLockReset tpmutil.Command = 0x00000139
|
||||
CmdDictionaryAttackParameters tpmutil.Command = 0x0000013A
|
||||
CmdPCREvent tpmutil.Command = 0x0000013C
|
||||
CmdSequenceComplete tpmutil.Command = 0x0000013E
|
||||
CmdStartup tpmutil.Command = 0x00000144
|
||||
CmdShutdown tpmutil.Command = 0x00000145
|
||||
CmdActivateCredential tpmutil.Command = 0x00000147
|
||||
CmdCertify tpmutil.Command = 0x00000148
|
||||
CmdCertifyCreation tpmutil.Command = 0x0000014A
|
||||
CmdReadNV tpmutil.Command = 0x0000014E
|
||||
CmdReadLockNV tpmutil.Command = 0x0000014F
|
||||
CmdPolicySecret tpmutil.Command = 0x00000151
|
||||
CmdCreate tpmutil.Command = 0x00000153
|
||||
CmdECDHZGen tpmutil.Command = 0x00000154
|
||||
CmdImport tpmutil.Command = 0x00000156
|
||||
CmdLoad tpmutil.Command = 0x00000157
|
||||
CmdQuote tpmutil.Command = 0x00000158
|
||||
CmdRSADecrypt tpmutil.Command = 0x00000159
|
||||
CmdSequenceUpdate tpmutil.Command = 0x0000015C
|
||||
CmdSign tpmutil.Command = 0x0000015D
|
||||
CmdUnseal tpmutil.Command = 0x0000015E
|
||||
CmdContextLoad tpmutil.Command = 0x00000161
|
||||
CmdContextSave tpmutil.Command = 0x00000162
|
||||
CmdECDHKeyGen tpmutil.Command = 0x00000163
|
||||
CmdEncryptDecrypt tpmutil.Command = 0x00000164
|
||||
CmdFlushContext tpmutil.Command = 0x00000165
|
||||
CmdLoadExternal tpmutil.Command = 0x00000167
|
||||
CmdMakeCredential tpmutil.Command = 0x00000168
|
||||
CmdReadPublicNV tpmutil.Command = 0x00000169
|
||||
CmdPolicyCommandCode tpmutil.Command = 0x0000016C
|
||||
CmdPolicyOr tpmutil.Command = 0x00000171
|
||||
CmdReadPublic tpmutil.Command = 0x00000173
|
||||
CmdRSAEncrypt tpmutil.Command = 0x00000174
|
||||
CmdStartAuthSession tpmutil.Command = 0x00000176
|
||||
CmdGetCapability tpmutil.Command = 0x0000017A
|
||||
CmdGetRandom tpmutil.Command = 0x0000017B
|
||||
CmdHash tpmutil.Command = 0x0000017D
|
||||
CmdPCRRead tpmutil.Command = 0x0000017E
|
||||
CmdPolicyPCR tpmutil.Command = 0x0000017F
|
||||
CmdReadClock tpmutil.Command = 0x00000181
|
||||
CmdPCRExtend tpmutil.Command = 0x00000182
|
||||
CmdEventSequenceComplete tpmutil.Command = 0x00000185
|
||||
CmdHashSequenceStart tpmutil.Command = 0x00000186
|
||||
CmdPolicyGetDigest tpmutil.Command = 0x00000189
|
||||
CmdPolicyPassword tpmutil.Command = 0x0000018C
|
||||
CmdEncryptDecrypt2 tpmutil.Command = 0x00000193
|
||||
)
|
||||
|
||||
// Regular TPM 2.0 devices use 24-bit mask (3 bytes) for PCR selection.
|
||||
const sizeOfPCRSelect = 3
|
||||
|
||||
const defaultRSAExponent = 1<<16 + 1
|
||||
|
||||
// NVAttr is a bitmask used in Attributes field of NV indexes. Individual
|
||||
// flags should be OR-ed to form a full mask.
|
||||
type NVAttr uint32
|
||||
|
||||
// NV Attributes
|
||||
const (
|
||||
AttrPPWrite NVAttr = 0x00000001
|
||||
AttrOwnerWrite NVAttr = 0x00000002
|
||||
AttrAuthWrite NVAttr = 0x00000004
|
||||
AttrPolicyWrite NVAttr = 0x00000008
|
||||
AttrPolicyDelete NVAttr = 0x00000400
|
||||
AttrWriteLocked NVAttr = 0x00000800
|
||||
AttrWriteAll NVAttr = 0x00001000
|
||||
AttrWriteDefine NVAttr = 0x00002000
|
||||
AttrWriteSTClear NVAttr = 0x00004000
|
||||
AttrGlobalLock NVAttr = 0x00008000
|
||||
AttrPPRead NVAttr = 0x00010000
|
||||
AttrOwnerRead NVAttr = 0x00020000
|
||||
AttrAuthRead NVAttr = 0x00040000
|
||||
AttrPolicyRead NVAttr = 0x00080000
|
||||
AttrNoDA NVAttr = 0x02000000
|
||||
AttrOrderly NVAttr = 0x04000000
|
||||
AttrClearSTClear NVAttr = 0x08000000
|
||||
AttrReadLocked NVAttr = 0x10000000
|
||||
AttrWritten NVAttr = 0x20000000
|
||||
AttrPlatformCreate NVAttr = 0x40000000
|
||||
AttrReadSTClear NVAttr = 0x80000000
|
||||
)
|
||||
|
||||
var permMap = map[NVAttr]string{
|
||||
AttrPPWrite: "PPWrite",
|
||||
AttrOwnerWrite: "OwnerWrite",
|
||||
AttrAuthWrite: "AuthWrite",
|
||||
AttrPolicyWrite: "PolicyWrite",
|
||||
AttrPolicyDelete: "PolicyDelete",
|
||||
AttrWriteLocked: "WriteLocked",
|
||||
AttrWriteAll: "WriteAll",
|
||||
AttrWriteDefine: "WriteDefine",
|
||||
AttrWriteSTClear: "WriteSTClear",
|
||||
AttrGlobalLock: "GlobalLock",
|
||||
AttrPPRead: "PPRead",
|
||||
AttrOwnerRead: "OwnerRead",
|
||||
AttrAuthRead: "AuthRead",
|
||||
AttrPolicyRead: "PolicyRead",
|
||||
AttrNoDA: "No Do",
|
||||
AttrOrderly: "Oderly",
|
||||
AttrClearSTClear: "ClearSTClear",
|
||||
AttrReadLocked: "ReadLocked",
|
||||
AttrWritten: "Writte",
|
||||
AttrPlatformCreate: "PlatformCreate",
|
||||
AttrReadSTClear: "ReadSTClear",
|
||||
}
|
||||
|
||||
// String returns a textual representation of the set of NVAttr
|
||||
func (p NVAttr) String() string {
|
||||
var retString strings.Builder
|
||||
for iterator, item := range permMap {
|
||||
if (p & iterator) != 0 {
|
||||
retString.WriteString(item + " + ")
|
||||
}
|
||||
}
|
||||
if retString.String() == "" {
|
||||
return "Permission/s not found"
|
||||
}
|
||||
return strings.TrimSuffix(retString.String(), " + ")
|
||||
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
package tpm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
type (
|
||||
// RCFmt0 holds Format 0 error codes
|
||||
RCFmt0 uint8
|
||||
|
||||
// RCFmt1 holds Format 1 error codes
|
||||
RCFmt1 uint8
|
||||
|
||||
// RCWarn holds error codes used in warnings
|
||||
RCWarn uint8
|
||||
|
||||
// RCIndex is used to reference arguments, handles and sessions in errors
|
||||
RCIndex uint8
|
||||
)
|
||||
|
||||
// Format 0 error codes.
|
||||
const (
|
||||
RCInitialize RCFmt0 = 0x00
|
||||
RCFailure = 0x01
|
||||
RCSequence = 0x03
|
||||
RCPrivate = 0x0B
|
||||
RCHMAC = 0x19
|
||||
RCDisabled = 0x20
|
||||
RCExclusive = 0x21
|
||||
RCAuthType = 0x24
|
||||
RCAuthMissing = 0x25
|
||||
RCPolicy = 0x26
|
||||
RCPCR = 0x27
|
||||
RCPCRChanged = 0x28
|
||||
RCUpgrade = 0x2D
|
||||
RCTooManyContexts = 0x2E
|
||||
RCAuthUnavailable = 0x2F
|
||||
RCReboot = 0x30
|
||||
RCUnbalanced = 0x31
|
||||
RCCommandSize = 0x42
|
||||
RCCommandCode = 0x43
|
||||
RCAuthSize = 0x44
|
||||
RCAuthContext = 0x45
|
||||
RCNVRange = 0x46
|
||||
RCNVSize = 0x47
|
||||
RCNVLocked = 0x48
|
||||
RCNVAuthorization = 0x49
|
||||
RCNVUninitialized = 0x4A
|
||||
RCNVSpace = 0x4B
|
||||
RCNVDefined = 0x4C
|
||||
RCBadContext = 0x50
|
||||
RCCPHash = 0x51
|
||||
RCParent = 0x52
|
||||
RCNeedsTest = 0x53
|
||||
RCNoResult = 0x54
|
||||
RCSensitive = 0x55
|
||||
)
|
||||
|
||||
var fmt0Msg = map[RCFmt0]string{
|
||||
RCInitialize: "TPM not initialized by TPM2_Startup or already initialized",
|
||||
RCFailure: "commands not being accepted because of a TPM failure",
|
||||
RCSequence: "improper use of a sequence handle",
|
||||
RCPrivate: "not currently used",
|
||||
RCHMAC: "not currently used",
|
||||
RCDisabled: "the command is disabled",
|
||||
RCExclusive: "command failed because audit sequence required exclusivity",
|
||||
RCAuthType: "authorization handle is not correct for command",
|
||||
RCAuthMissing: "5 command requires an authorization session for handle and it is not present",
|
||||
RCPolicy: "policy failure in math operation or an invalid authPolicy value",
|
||||
RCPCR: "PCR check fail",
|
||||
RCPCRChanged: "PCR have changed since checked",
|
||||
RCUpgrade: "TPM is in field upgrade mode unless called via TPM2_FieldUpgradeData(), then it is not in field upgrade mode",
|
||||
RCTooManyContexts: "context ID counter is at maximum",
|
||||
RCAuthUnavailable: "authValue or authPolicy is not available for selected entity",
|
||||
RCReboot: "a _TPM_Init and Startup(CLEAR) is required before the TPM can resume operation",
|
||||
RCUnbalanced: "the protection algorithms (hash and symmetric) are not reasonably balanced; the digest size of the hash must be larger than the key size of the symmetric algorithm",
|
||||
RCCommandSize: "command commandSize value is inconsistent with contents of the command buffer; either the size is not the same as the octets loaded by the hardware interface layer or the value is not large enough to hold a command header",
|
||||
RCCommandCode: "command code not supported",
|
||||
RCAuthSize: "the value of authorizationSize is out of range or the number of octets in the Authorization Area is greater than required",
|
||||
RCAuthContext: "use of an authorization session with a context command or another command that cannot have an authorization session",
|
||||
RCNVRange: "NV offset+size is out of range",
|
||||
RCNVSize: "Requested allocation size is larger than allowed",
|
||||
RCNVLocked: "NV access locked",
|
||||
RCNVAuthorization: "NV access authorization fails in command actions",
|
||||
RCNVUninitialized: "an NV Index is used before being initialized or the state saved by TPM2_Shutdown(STATE) could not be restored",
|
||||
RCNVSpace: "insufficient space for NV allocation",
|
||||
RCNVDefined: "NV Index or persistent object already defined",
|
||||
RCBadContext: "context in TPM2_ContextLoad() is not valid",
|
||||
RCCPHash: "cpHash value already set or not correct for use",
|
||||
RCParent: "handle for parent is not a valid parent",
|
||||
RCNeedsTest: "some function needs testing",
|
||||
RCNoResult: "returned when an internal function cannot process a request due to an unspecified problem; this code is usually related to invalid parameters that are not properly filtered by the input unmarshaling code",
|
||||
RCSensitive: "the sensitive area did not unmarshal correctly after decryption",
|
||||
}
|
||||
|
||||
// Format 1 error codes.
|
||||
const (
|
||||
RCAsymmetric = 0x01
|
||||
RCAttributes = 0x02
|
||||
RCHash = 0x03
|
||||
RCValue = 0x04
|
||||
RCHierarchy = 0x05
|
||||
RCKeySize = 0x07
|
||||
RCMGF = 0x08
|
||||
RCMode = 0x09
|
||||
RCType = 0x0A
|
||||
RCHandle = 0x0B
|
||||
RCKDF = 0x0C
|
||||
RCRange = 0x0D
|
||||
RCAuthFail = 0x0E
|
||||
RCNonce = 0x0F
|
||||
RCPP = 0x10
|
||||
RCScheme = 0x12
|
||||
RCSize = 0x15
|
||||
RCSymmetric = 0x16
|
||||
RCTag = 0x17
|
||||
RCSelector = 0x18
|
||||
RCInsufficient = 0x1A
|
||||
RCSignature = 0x1B
|
||||
RCKey = 0x1C
|
||||
RCPolicyFail = 0x1D
|
||||
RCIntegrity = 0x1F
|
||||
RCTicket = 0x20
|
||||
RCReservedBits = 0x21
|
||||
RCBadAuth = 0x22
|
||||
RCExpired = 0x23
|
||||
RCPolicyCC = 0x24
|
||||
RCBinding = 0x25
|
||||
RCCurve = 0x26
|
||||
RCECCPoint = 0x27
|
||||
)
|
||||
|
||||
var fmt1Msg = map[RCFmt1]string{
|
||||
RCAsymmetric: "asymmetric algorithm not supported or not correct",
|
||||
RCAttributes: "inconsistent attributes",
|
||||
RCHash: "hash algorithm not supported or not appropriate",
|
||||
RCValue: "value is out of range or is not correct for the context",
|
||||
RCHierarchy: "hierarchy is not enabled or is not correct for the use",
|
||||
RCKeySize: "key size is not supported",
|
||||
RCMGF: "mask generation function not supported",
|
||||
RCMode: "mode of operation not supported",
|
||||
RCType: "the type of the value is not appropriate for the use",
|
||||
RCHandle: "the handle is not correct for the use",
|
||||
RCKDF: "unsupported key derivation function or function not appropriate for use",
|
||||
RCRange: "value was out of allowed range",
|
||||
RCAuthFail: "the authorization HMAC check failed and DA counter incremented",
|
||||
RCNonce: "invalid nonce size or nonce value mismatch",
|
||||
RCPP: "authorization requires assertion of PP",
|
||||
RCScheme: "unsupported or incompatible scheme",
|
||||
RCSize: "structure is the wrong size",
|
||||
RCSymmetric: "unsupported symmetric algorithm or key size, or not appropriate for instance",
|
||||
RCTag: "incorrect structure tag",
|
||||
RCSelector: "union selector is incorrect",
|
||||
RCInsufficient: "the TPM was unable to unmarshal a value because there were not enough octets in the input buffer",
|
||||
RCSignature: "the signature is not valid",
|
||||
RCKey: "key fields are not compatible with the selected use",
|
||||
RCPolicyFail: "a policy check failed",
|
||||
RCIntegrity: "integrity check failed",
|
||||
RCTicket: "invalid ticket",
|
||||
RCReservedBits: "reserved bits not set to zero as required",
|
||||
RCBadAuth: "authorization failure without DA implications",
|
||||
RCExpired: "the policy has expired",
|
||||
RCPolicyCC: "the commandCode in the policy is not the commandCode of the command or the command code in a policy command references a command that is not implemented",
|
||||
RCBinding: "public and sensitive portions of an object are not cryptographically bound",
|
||||
RCCurve: "curve not supported",
|
||||
RCECCPoint: "point is not on the required curve",
|
||||
}
|
||||
|
||||
// Warning codes.
|
||||
const (
|
||||
RCContextGap RCWarn = 0x01
|
||||
RCObjectMemory = 0x02
|
||||
RCSessionMemory = 0x03
|
||||
RCMemory = 0x04
|
||||
RCSessionHandles = 0x05
|
||||
RCObjectHandles = 0x06
|
||||
RCLocality = 0x07
|
||||
RCYielded = 0x08
|
||||
RCCanceled = 0x09
|
||||
RCTesting = 0x0A
|
||||
RCReferenceH0 = 0x10
|
||||
RCReferenceH1 = 0x11
|
||||
RCReferenceH2 = 0x12
|
||||
RCReferenceH3 = 0x13
|
||||
RCReferenceH4 = 0x14
|
||||
RCReferenceH5 = 0x15
|
||||
RCReferenceH6 = 0x16
|
||||
RCReferenceS0 = 0x18
|
||||
RCReferenceS1 = 0x19
|
||||
RCReferenceS2 = 0x1A
|
||||
RCReferenceS3 = 0x1B
|
||||
RCReferenceS4 = 0x1C
|
||||
RCReferenceS5 = 0x1D
|
||||
RCReferenceS6 = 0x1E
|
||||
RCNVRate = 0x20
|
||||
RCLockout = 0x21
|
||||
RCRetry = 0x22
|
||||
RCNVUnavailable = 0x23
|
||||
)
|
||||
|
||||
var warnMsg = map[RCWarn]string{
|
||||
RCContextGap: "gap for context ID is too large",
|
||||
RCObjectMemory: "out of memory for object contexts",
|
||||
RCSessionMemory: "out of memory for session contexts",
|
||||
RCMemory: "out of shared object/session memory or need space for internal operations",
|
||||
RCSessionHandles: "out of session handles",
|
||||
RCObjectHandles: "out of object handles",
|
||||
RCLocality: "bad locality",
|
||||
RCYielded: "the TPM has suspended operation on the command; forward progress was made and the command may be retried",
|
||||
RCCanceled: "the command was canceled",
|
||||
RCTesting: "TPM is performing self-tests",
|
||||
RCReferenceH0: "the 1st handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceH1: "the 2nd handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceH2: "the 3rd handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceH3: "the 4th handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceH4: "the 5th handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceH5: "the 6th handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceH6: "the 7th handle in the handle area references a transient object or session that is not loaded",
|
||||
RCReferenceS0: "the 1st authorization session handle references a session that is not loaded",
|
||||
RCReferenceS1: "the 2nd authorization session handle references a session that is not loaded",
|
||||
RCReferenceS2: "the 3rd authorization session handle references a session that is not loaded",
|
||||
RCReferenceS3: "the 4th authorization session handle references a session that is not loaded",
|
||||
RCReferenceS4: "the 5th authorization session handle references a session that is not loaded",
|
||||
RCReferenceS5: "the 6th authorization session handle references a session that is not loaded",
|
||||
RCReferenceS6: "the 7th authorization session handle references a session that is not loaded",
|
||||
RCNVRate: "the TPM is rate-limiting accesses to prevent wearout of NV",
|
||||
RCLockout: "authorizations for objects subject to DA protection are not allowed at this time because the TPM is in DA lockout mode",
|
||||
RCRetry: "the TPM was not able to start the command",
|
||||
RCNVUnavailable: "the command may require writing of NV and NV is not current accessible",
|
||||
}
|
||||
|
||||
// Indexes for arguments, handles and sessions.
|
||||
const (
|
||||
RC1 RCIndex = iota + 1
|
||||
RC2
|
||||
RC3
|
||||
RC4
|
||||
RC5
|
||||
RC6
|
||||
RC7
|
||||
RC8
|
||||
RC9
|
||||
RCA
|
||||
RCB
|
||||
RCC
|
||||
RCD
|
||||
RCE
|
||||
RCF
|
||||
)
|
||||
|
||||
const unknownCode = "unknown error code"
|
||||
|
||||
// Error is returned for all Format 0 errors from the TPM. It is used for general
|
||||
// errors not specific to a parameter, handle or session.
|
||||
type Error struct {
|
||||
Code RCFmt0
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
msg := fmt0Msg[e.Code]
|
||||
if msg == "" {
|
||||
msg = unknownCode
|
||||
}
|
||||
return fmt.Sprintf("error code 0x%x : %s", e.Code, msg)
|
||||
}
|
||||
|
||||
// VendorError represents a vendor-specific error response. These types of responses
|
||||
// are not decoded and Code contains the complete response code.
|
||||
type VendorError struct {
|
||||
Code uint32
|
||||
}
|
||||
|
||||
func (e VendorError) Error() string {
|
||||
return fmt.Sprintf("vendor error code 0x%x", e.Code)
|
||||
}
|
||||
|
||||
// Warning is typically used to report transient errors.
|
||||
type Warning struct {
|
||||
Code RCWarn
|
||||
}
|
||||
|
||||
func (w Warning) Error() string {
|
||||
msg := warnMsg[w.Code]
|
||||
if msg == "" {
|
||||
msg = unknownCode
|
||||
}
|
||||
return fmt.Sprintf("warning code 0x%x : %s", w.Code, msg)
|
||||
}
|
||||
|
||||
// ParameterError describes an error related to a parameter, and the parameter number.
|
||||
type ParameterError struct {
|
||||
Code RCFmt1
|
||||
Parameter RCIndex
|
||||
}
|
||||
|
||||
func (e ParameterError) Error() string {
|
||||
msg := fmt1Msg[e.Code]
|
||||
if msg == "" {
|
||||
msg = unknownCode
|
||||
}
|
||||
return fmt.Sprintf("parameter %d, error code 0x%x : %s", e.Parameter, e.Code, msg)
|
||||
}
|
||||
|
||||
// HandleError describes an error related to a handle, and the handle number.
|
||||
type HandleError struct {
|
||||
Code RCFmt1
|
||||
Handle RCIndex
|
||||
}
|
||||
|
||||
func (e HandleError) Error() string {
|
||||
msg := fmt1Msg[e.Code]
|
||||
if msg == "" {
|
||||
msg = unknownCode
|
||||
}
|
||||
return fmt.Sprintf("handle %d, error code 0x%x : %s", e.Handle, e.Code, msg)
|
||||
}
|
||||
|
||||
// SessionError describes an error related to a session, and the session number.
|
||||
type SessionError struct {
|
||||
Code RCFmt1
|
||||
Session RCIndex
|
||||
}
|
||||
|
||||
func (e SessionError) Error() string {
|
||||
msg := fmt1Msg[e.Code]
|
||||
if msg == "" {
|
||||
msg = unknownCode
|
||||
}
|
||||
return fmt.Sprintf("session %d, error code 0x%x : %s", e.Session, e.Code, msg)
|
||||
}
|
||||
|
||||
// Decode a TPM2 response code and return the appropriate error. Logic
|
||||
// according to the "Response Code Evaluation" chart in Part 1 of the TPM 2.0
|
||||
// spec.
|
||||
func decodeResponse(code tpmutil.ResponseCode) error {
|
||||
if code == tpmutil.RCSuccess {
|
||||
return nil
|
||||
}
|
||||
if code&0x180 == 0 { // Bits 7:8 == 0 is a TPM1 error
|
||||
return fmt.Errorf("response status 0x%x", code)
|
||||
}
|
||||
if code&0x80 == 0 { // Bit 7 unset
|
||||
if code&0x400 > 0 { // Bit 10 set, vendor specific code
|
||||
return VendorError{uint32(code)}
|
||||
}
|
||||
if code&0x800 > 0 { // Bit 11 set, warning with code in bit 0:6
|
||||
return Warning{RCWarn(code & 0x7f)}
|
||||
}
|
||||
// error with code in bit 0:6
|
||||
return Error{RCFmt0(code & 0x7f)}
|
||||
}
|
||||
if code&0x40 > 0 { // Bit 6 set, code in 0:5, parameter number in 8:11
|
||||
return ParameterError{RCFmt1(code & 0x3f), RCIndex((code & 0xf00) >> 8)}
|
||||
}
|
||||
if code&0x800 == 0 { // Bit 11 unset, code in 0:5, handle in 8:10
|
||||
return HandleError{RCFmt1(code & 0x3f), RCIndex((code & 0x700) >> 8)}
|
||||
}
|
||||
// Code in 0:5, Session in 8:10
|
||||
return SessionError{RCFmt1(code & 0x3f), RCIndex((code & 0x700) >> 8)}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpm2
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// KDFa implements TPM 2.0's default key derivation function, as defined in
|
||||
// section 11.4.9.2 of the TPM revision 2 specification part 1.
|
||||
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
|
||||
// The key & label parameters must not be zero length.
|
||||
// The label parameter is a non-null-terminated string.
|
||||
// The contextU & contextV parameters are optional.
|
||||
func KDFa(hashAlg Algorithm, key []byte, label string, contextU, contextV []byte, bits int) ([]byte, error) {
|
||||
h, err := hashAlg.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mac := hmac.New(h.New, key)
|
||||
|
||||
out := kdf(mac, bits, func() {
|
||||
mac.Write([]byte(label))
|
||||
mac.Write([]byte{0}) // Terminating null character for C-string.
|
||||
mac.Write(contextU)
|
||||
mac.Write(contextV)
|
||||
binary.Write(mac, binary.BigEndian, uint32(bits))
|
||||
})
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// KDFe implements TPM 2.0's ECDH key derivation function, as defined in
|
||||
// section 11.4.9.3 of the TPM revision 2 specification part 1.
|
||||
// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/
|
||||
// The z parameter is the x coordinate of one parties private ECC key and the other parties public ECC key.
|
||||
// The use parameter is a non-null-terminated string.
|
||||
// The partyUInfo and partyVInfo are the x coordinates of the initiators and the responders ECC points respectively.
|
||||
func KDFe(hashAlg Algorithm, z []byte, use string, partyUInfo, partyVInfo []byte, bits int) ([]byte, error) {
|
||||
createHash, err := hashAlg.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h := createHash.New()
|
||||
|
||||
out := kdf(h, bits, func() {
|
||||
h.Write(z)
|
||||
h.Write([]byte(use))
|
||||
h.Write([]byte{0}) // Terminating null character for C-string.
|
||||
h.Write(partyUInfo)
|
||||
h.Write(partyVInfo)
|
||||
})
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func kdf(h hash.Hash, bits int, update func()) []byte {
|
||||
bytes := (bits + 7) / 8
|
||||
out := []byte{}
|
||||
|
||||
for counter := 1; len(out) < bytes; counter++ {
|
||||
h.Reset()
|
||||
binary.Write(h, binary.BigEndian, uint32(counter))
|
||||
update()
|
||||
|
||||
out = h.Sum(out)
|
||||
}
|
||||
// out's length is a multiple of hash size, so there will be excess bytes if bytes isn't a multiple of hash size.
|
||||
out = out[:bytes]
|
||||
|
||||
// As mentioned in the KDFa and KDFe specs mentioned above,
|
||||
// the unused bits of the most significant octet are masked off.
|
||||
if maskBits := uint8(bits % 8); maskBits > 0 {
|
||||
out[0] &= (1 << maskBits) - 1
|
||||
}
|
||||
return out
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// +build !windows
|
||||
|
||||
// Copyright (c) 2019, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
// OpenTPM opens a channel to the TPM at the given path. If the file is a
|
||||
// device, then it treats it like a normal TPM device, and if the file is a
|
||||
// Unix domain socket, then it opens a connection to the socket.
|
||||
func OpenTPM(path string) (io.ReadWriteCloser, error) {
|
||||
rwc, err := tpmutil.OpenTPM(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure this is a TPM 2.0
|
||||
_, err = GetManufacturer(rwc)
|
||||
if err != nil {
|
||||
rwc.Close()
|
||||
return nil, fmt.Errorf("open %s: device is not a TPM 2.0", path)
|
||||
}
|
||||
return rwc, nil
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
"github.com/google/go-tpm/tpmutil/tbs"
|
||||
)
|
||||
|
||||
// OpenTPM opens a channel to the TPM.
|
||||
func OpenTPM() (io.ReadWriteCloser, error) {
|
||||
info, err := tbs.GetDeviceInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if info.TPMVersion != tbs.TPMVersion20 {
|
||||
return nil, fmt.Errorf("openTPM: device is not a TPM 2.0")
|
||||
}
|
||||
|
||||
return tpmutil.OpenTPM()
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"encoding.go",
|
||||
"poll_other.go",
|
||||
"poll_unix.go",
|
||||
"run.go",
|
||||
"run_other.go",
|
||||
"run_windows.go",
|
||||
"structures.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm/tpmutil",
|
||||
importpath = "github.com/google/go-tpm/tpmutil",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:android": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:ios": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//vendor/golang.org/x/sys/unix:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"//vendor/github.com/google/go-tpm/tpmutil/tbs:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
|
@ -0,0 +1,211 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
selfMarshalerType = reflect.TypeOf((*SelfMarshaler)(nil)).Elem()
|
||||
handlesAreaType = reflect.TypeOf((*[]Handle)(nil))
|
||||
)
|
||||
|
||||
// packWithHeader takes a header and a sequence of elements that are either of
|
||||
// fixed length or slices of fixed-length types and packs them into a single
|
||||
// byte array using binary.Write. It updates the CommandHeader to have the right
|
||||
// length.
|
||||
func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
|
||||
hdrSize := binary.Size(ch)
|
||||
body, err := Pack(cmd...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't pack message body: %v", err)
|
||||
}
|
||||
bodySize := len(body)
|
||||
ch.Size = uint32(hdrSize + bodySize)
|
||||
header, err := Pack(ch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't pack message header: %v", err)
|
||||
}
|
||||
return append(header, body...), nil
|
||||
}
|
||||
|
||||
// Pack encodes a set of elements into a single byte array, using
|
||||
// encoding/binary. This means that all the elements must be encodeable
|
||||
// according to the rules of encoding/binary.
|
||||
//
|
||||
// It has one difference from encoding/binary: it encodes byte slices with a
|
||||
// prepended length, to match how the TPM encodes variable-length arrays. If
|
||||
// you wish to add a byte slice without length prefix, use RawBytes.
|
||||
func Pack(elts ...interface{}) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := packType(buf, elts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// tryMarshal attempts to use a TPMMarshal() method defined on the type
|
||||
// to pack v into buf. True is returned if the method exists and the
|
||||
// marshal was attempted.
|
||||
func tryMarshal(buf io.Writer, v reflect.Value) (bool, error) {
|
||||
t := v.Type()
|
||||
if t.Implements(selfMarshalerType) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return true, fmt.Errorf("cannot call TPMMarshal on a nil pointer of type %T", v)
|
||||
}
|
||||
return true, v.Interface().(SelfMarshaler).TPMMarshal(buf)
|
||||
}
|
||||
|
||||
// We might have a non-pointer struct field, but we dont have a
|
||||
// pointer with which to implement the interface.
|
||||
// If the pointer of the type implements the interface, we should be
|
||||
// able to construct a value to call TPMMarshal() with.
|
||||
// TODO(awly): Try and avoid blowing away private data by using Addr() instead of Set()
|
||||
if reflect.PtrTo(t).Implements(selfMarshalerType) {
|
||||
tmp := reflect.New(t)
|
||||
tmp.Elem().Set(v)
|
||||
return true, tmp.Interface().(SelfMarshaler).TPMMarshal(buf)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func packValue(buf io.Writer, v reflect.Value) error {
|
||||
if v.Type() == handlesAreaType {
|
||||
v = v.Convert(reflect.TypeOf((*handleList)(nil)))
|
||||
}
|
||||
if canMarshal, err := tryMarshal(buf, v); canMarshal {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
return fmt.Errorf("cannot pack nil %s", v.Type().String())
|
||||
}
|
||||
return packValue(buf, v.Elem())
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
if err := packValue(buf, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return binary.Write(buf, binary.BigEndian, v.Interface())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func packType(buf io.Writer, elts ...interface{}) error {
|
||||
for _, e := range elts {
|
||||
if err := packValue(buf, reflect.ValueOf(e)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// tryUnmarshal attempts to use TPMUnmarshal() to perform the
|
||||
// unpack, if the given value implements SelfMarshaler.
|
||||
// True is returned if v implements SelfMarshaler & TPMUnmarshal
|
||||
// was called, along with an error returned from TPMUnmarshal.
|
||||
func tryUnmarshal(buf io.Reader, v reflect.Value) (bool, error) {
|
||||
t := v.Type()
|
||||
if t.Implements(selfMarshalerType) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return true, fmt.Errorf("cannot call TPMUnmarshal on a nil pointer")
|
||||
}
|
||||
return true, v.Interface().(SelfMarshaler).TPMUnmarshal(buf)
|
||||
}
|
||||
|
||||
// We might have a non-pointer struct field, which is addressable,
|
||||
// If the pointer of the type implements the interface, and the
|
||||
// value is addressable, we should be able to call TPMUnmarshal().
|
||||
if v.CanAddr() && reflect.PtrTo(t).Implements(selfMarshalerType) {
|
||||
return true, v.Addr().Interface().(SelfMarshaler).TPMUnmarshal(buf)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Unpack is a convenience wrapper around UnpackBuf. Unpack returns the number
|
||||
// of bytes read from b to fill elts and error, if any.
|
||||
func Unpack(b []byte, elts ...interface{}) (int, error) {
|
||||
buf := bytes.NewBuffer(b)
|
||||
err := UnpackBuf(buf, elts...)
|
||||
read := len(b) - buf.Len()
|
||||
return read, err
|
||||
}
|
||||
|
||||
func unpackValue(buf io.Reader, v reflect.Value) error {
|
||||
if v.Type() == handlesAreaType {
|
||||
v = v.Convert(reflect.TypeOf((*handleList)(nil)))
|
||||
}
|
||||
if didUnmarshal, err := tryUnmarshal(buf, v); didUnmarshal {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
return fmt.Errorf("cannot unpack nil %s", v.Type().String())
|
||||
}
|
||||
return unpackValue(buf, v.Elem())
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
if err := unpackValue(buf, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
// binary.Read can only set pointer values, so we need to take the address.
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("cannot unpack unaddressable leaf type %q", v.Type().String())
|
||||
}
|
||||
return binary.Read(buf, binary.BigEndian, v.Addr().Interface())
|
||||
}
|
||||
}
|
||||
|
||||
// UnpackBuf recursively unpacks types from a reader just as encoding/binary
|
||||
// does under binary.BigEndian, but with one difference: it unpacks a byte
|
||||
// slice by first reading an integer with lengthPrefixSize bytes, then reading
|
||||
// that many bytes. It assumes that incoming values are pointers to values so
|
||||
// that, e.g., underlying slices can be resized as needed.
|
||||
func UnpackBuf(buf io.Reader, elts ...interface{}) error {
|
||||
for _, e := range elts {
|
||||
v := reflect.ValueOf(e)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("non-pointer value %q passed to UnpackBuf", v.Type().String())
|
||||
}
|
||||
if v.IsNil() {
|
||||
return errors.New("nil pointer passed to UnpackBuf")
|
||||
}
|
||||
|
||||
if err := unpackValue(buf, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// +build !linux,!darwin
|
||||
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// Not implemented on Windows.
|
||||
func poll(f *os.File) error { return nil }
|
|
@ -0,0 +1,32 @@
|
|||
// +build linux darwin
|
||||
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// poll blocks until the file descriptor is ready for reading or an error occurs.
|
||||
func poll(f *os.File) error {
|
||||
var (
|
||||
fds = []unix.PollFd{{
|
||||
Fd: int32(f.Fd()),
|
||||
Events: 0x1, // POLLIN
|
||||
}}
|
||||
timeout = -1 // Indefinite timeout
|
||||
)
|
||||
|
||||
if _, err := unix.Poll(fds, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Revents is filled in by the kernel.
|
||||
// If the expected event happened, Revents should match Events.
|
||||
if fds[0].Revents != fds[0].Events {
|
||||
return fmt.Errorf("unexpected poll Revents 0x%x", fds[0].Revents)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package tpmutil provides common utility functions for both TPM 1.2 and TPM 2.0 devices.
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// maxTPMResponse is the largest possible response from the TPM. We need to know
|
||||
// this because we don't always know the length of the TPM response, and
|
||||
// /dev/tpm insists on giving it all back in a single value rather than
|
||||
// returning a header and a body in separate responses.
|
||||
const maxTPMResponse = 4096
|
||||
|
||||
// RunCommand executes cmd with given tag and arguments. Returns TPM response
|
||||
// body (without response header) and response code from the header. Returned
|
||||
// error may be nil if response code is not RCSuccess; caller should check
|
||||
// both.
|
||||
func RunCommand(rw io.ReadWriter, tag Tag, cmd Command, in ...interface{}) ([]byte, ResponseCode, error) {
|
||||
if rw == nil {
|
||||
return nil, 0, errors.New("nil TPM handle")
|
||||
}
|
||||
ch := commandHeader{tag, 0, cmd}
|
||||
inb, err := packWithHeader(ch, in...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if _, err := rw.Write(inb); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// If the TPM is a real device, it may not be ready for reading immediately after writing
|
||||
// the command. Wait until the file descriptor is ready to be read from.
|
||||
if f, ok := rw.(*os.File); ok {
|
||||
if err = poll(f); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
outb := make([]byte, maxTPMResponse)
|
||||
outlen, err := rw.Read(outb)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// Resize the buffer to match the amount read from the TPM.
|
||||
outb = outb[:outlen]
|
||||
|
||||
var rh responseHeader
|
||||
read, err := Unpack(outb, &rh)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
outb = outb[read:]
|
||||
|
||||
if rh.Res != RCSuccess {
|
||||
return nil, rh.Res, nil
|
||||
}
|
||||
|
||||
return outb, rh.Res, nil
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
// +build !windows
|
||||
|
||||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
// OpenTPM opens a channel to the TPM at the given path. If the file is a
|
||||
// device, then it treats it like a normal TPM device, and if the file is a
|
||||
// Unix domain socket, then it opens a connection to the socket.
|
||||
func OpenTPM(path string) (io.ReadWriteCloser, error) {
|
||||
// If it's a regular file, then open it
|
||||
var rwc io.ReadWriteCloser
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeDevice != 0 {
|
||||
var f *os.File
|
||||
f, err = os.OpenFile(path, os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rwc = io.ReadWriteCloser(f)
|
||||
} else if fi.Mode()&os.ModeSocket != 0 {
|
||||
rwc = NewEmulatorReadWriteCloser(path)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported TPM file mode %s", fi.Mode().String())
|
||||
}
|
||||
|
||||
return rwc, nil
|
||||
}
|
||||
|
||||
// dialer abstracts the net.Dial call so test code can provide its own net.Conn
|
||||
// implementation.
|
||||
type dialer func(network, path string) (net.Conn, error)
|
||||
|
||||
// EmulatorReadWriteCloser manages connections with a TPM emulator over a Unix
|
||||
// domain socket. These emulators often operate in a write/read/disconnect
|
||||
// sequence, so the Write method always connects, and the Read method always
|
||||
// closes. EmulatorReadWriteCloser is not thread safe.
|
||||
type EmulatorReadWriteCloser struct {
|
||||
path string
|
||||
conn net.Conn
|
||||
dialer dialer
|
||||
}
|
||||
|
||||
// NewEmulatorReadWriteCloser stores information about a Unix domain socket to
|
||||
// write to and read from.
|
||||
func NewEmulatorReadWriteCloser(path string) *EmulatorReadWriteCloser {
|
||||
return &EmulatorReadWriteCloser{
|
||||
path: path,
|
||||
dialer: net.Dial,
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements io.Reader by reading from the Unix domain socket and closing
|
||||
// it.
|
||||
func (erw *EmulatorReadWriteCloser) Read(p []byte) (int, error) {
|
||||
// Read is always the second operation in a Write/Read sequence.
|
||||
if erw.conn == nil {
|
||||
return 0, fmt.Errorf("Must call Write then Read in an alternating sequence")
|
||||
}
|
||||
n, err := erw.conn.Read(p)
|
||||
erw.conn.Close()
|
||||
erw.conn = nil
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Write implements io.Writer by connecting to the Unix domain socket and
|
||||
// writing.
|
||||
func (erw *EmulatorReadWriteCloser) Write(p []byte) (int, error) {
|
||||
if erw.conn != nil {
|
||||
return 0, fmt.Errorf("Must call Write then Read in an alternating sequence")
|
||||
}
|
||||
var err error
|
||||
erw.conn, err = erw.dialer("unix", erw.path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return erw.conn.Write(p)
|
||||
}
|
||||
|
||||
// Close implements io.Closer by closing the Unix domain socket if one is open.
|
||||
func (erw *EmulatorReadWriteCloser) Close() error {
|
||||
if erw.conn == nil {
|
||||
return fmt.Errorf("Cannot call Close when no connection is open")
|
||||
}
|
||||
err := erw.conn.Close()
|
||||
erw.conn = nil
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/google/go-tpm/tpmutil/tbs"
|
||||
)
|
||||
|
||||
// winTPMBuffer is a ReadWriteCloser to access the TPM in Windows.
|
||||
type winTPMBuffer struct {
|
||||
context tbs.Context
|
||||
outBuffer []byte
|
||||
}
|
||||
|
||||
// Executes the TPM command specified by commandBuffer (at Normal Priority), returning the number
|
||||
// of bytes in the command and any error code returned by executing the TPM command. Command
|
||||
// response can be read by calling Read().
|
||||
func (rwc *winTPMBuffer) Write(commandBuffer []byte) (int, error) {
|
||||
// TPM spec defines longest possible response to be maxTPMResponse.
|
||||
rwc.outBuffer = rwc.outBuffer[:maxTPMResponse]
|
||||
|
||||
outBufferLen, err := rwc.context.SubmitCommand(
|
||||
tbs.NormalPriority,
|
||||
commandBuffer,
|
||||
rwc.outBuffer,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
rwc.outBuffer = rwc.outBuffer[:0]
|
||||
return 0, err
|
||||
}
|
||||
// Shrink outBuffer so it is length of response.
|
||||
rwc.outBuffer = rwc.outBuffer[:outBufferLen]
|
||||
return len(commandBuffer), nil
|
||||
}
|
||||
|
||||
// Provides TPM response from the command called in the last Write call.
|
||||
func (rwc *winTPMBuffer) Read(responseBuffer []byte) (int, error) {
|
||||
if len(rwc.outBuffer) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
lenCopied := copy(responseBuffer, rwc.outBuffer)
|
||||
// Cut out the piece of slice which was just read out, maintaining original slice capacity.
|
||||
rwc.outBuffer = append(rwc.outBuffer[:0], rwc.outBuffer[lenCopied:]...)
|
||||
return lenCopied, nil
|
||||
}
|
||||
|
||||
func (rwc *winTPMBuffer) Close() error {
|
||||
return rwc.context.Close()
|
||||
}
|
||||
|
||||
// OpenTPM creates a new instance of a ReadWriteCloser which can interact with a
|
||||
// Windows TPM.
|
||||
func OpenTPM() (io.ReadWriteCloser, error) {
|
||||
tpmContext, err := tbs.CreateContext(tbs.TPMVersion20, tbs.IncludeTPM12|tbs.IncludeTPM20)
|
||||
rwc := &winTPMBuffer{
|
||||
context: tpmContext,
|
||||
outBuffer: make([]byte, 0, maxTPMResponse),
|
||||
}
|
||||
return rwc, err
|
||||
}
|
||||
|
||||
// FromContext creates a new instance of a ReadWriteCloser which can
|
||||
// interact with a Windows TPM, using the specified TBS handle.
|
||||
func FromContext(ctx tbs.Context) io.ReadWriteCloser {
|
||||
return &winTPMBuffer{
|
||||
context: ctx,
|
||||
outBuffer: make([]byte, 0, maxTPMResponse),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tpmutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// maxBytesBufferSize sets a sane upper bound on the size of a U32Bytes
|
||||
// buffer. This limit exists to prevent a maliciously large size prefix
|
||||
// from resulting in a massive memory allocation, potentially causing
|
||||
// an OOM condition on the system.
|
||||
// We expect no buffer from a TPM to approach 1Mb in size.
|
||||
const maxBytesBufferSize = 1024 * 1024 // 1Mb.
|
||||
|
||||
// RawBytes is for Pack and RunCommand arguments that are already encoded.
|
||||
// Compared to []byte, RawBytes will not be prepended with slice length during
|
||||
// encoding.
|
||||
type RawBytes []byte
|
||||
|
||||
// U16Bytes is a byte slice with a 16-bit header
|
||||
type U16Bytes []byte
|
||||
|
||||
// TPMMarshal packs U16Bytes
|
||||
func (b *U16Bytes) TPMMarshal(out io.Writer) error {
|
||||
size := uint16(len([]byte(*b)))
|
||||
if err := binary.Write(out, binary.BigEndian, size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := out.Write(*b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != int(size) {
|
||||
return fmt.Errorf("unable to write all contents of U16Bytes")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TPMUnmarshal unpacks a U16Bytes
|
||||
func (b *U16Bytes) TPMUnmarshal(in io.Reader) error {
|
||||
var tmpSize uint16
|
||||
if err := binary.Read(in, binary.BigEndian, &tmpSize); err != nil {
|
||||
return err
|
||||
}
|
||||
size := int(tmpSize)
|
||||
|
||||
if len(*b) >= size {
|
||||
*b = (*b)[:size]
|
||||
} else {
|
||||
*b = append(*b, make([]byte, size-len(*b))...)
|
||||
}
|
||||
|
||||
n, err := in.Read(*b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != size {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// U32Bytes is a byte slice with a 32-bit header
|
||||
type U32Bytes []byte
|
||||
|
||||
// TPMMarshal packs U32Bytes
|
||||
func (b *U32Bytes) TPMMarshal(out io.Writer) error {
|
||||
size := uint32(len([]byte(*b)))
|
||||
if err := binary.Write(out, binary.BigEndian, size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := out.Write(*b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != int(size) {
|
||||
return fmt.Errorf("unable to write all contents of U32Bytes")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TPMUnmarshal unpacks a U32Bytes
|
||||
func (b *U32Bytes) TPMUnmarshal(in io.Reader) error {
|
||||
var tmpSize uint32
|
||||
if err := binary.Read(in, binary.BigEndian, &tmpSize); err != nil {
|
||||
return err
|
||||
}
|
||||
size := int(tmpSize)
|
||||
|
||||
if size > maxBytesBufferSize {
|
||||
return bytes.ErrTooLarge
|
||||
}
|
||||
|
||||
if len(*b) >= size {
|
||||
*b = (*b)[:size]
|
||||
} else {
|
||||
*b = append(*b, make([]byte, size-len(*b))...)
|
||||
}
|
||||
|
||||
n, err := in.Read(*b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != size {
|
||||
return fmt.Errorf("unable to read all contents in to U32Bytes")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tag is a command tag.
|
||||
type Tag uint16
|
||||
|
||||
// Command is an identifier of a TPM command.
|
||||
type Command uint32
|
||||
|
||||
// A commandHeader is the header for a TPM command.
|
||||
type commandHeader struct {
|
||||
Tag Tag
|
||||
Size uint32
|
||||
Cmd Command
|
||||
}
|
||||
|
||||
// ResponseCode is a response code returned by TPM.
|
||||
type ResponseCode uint32
|
||||
|
||||
// RCSuccess is response code for successful command. Identical for TPM 1.2 and
|
||||
// 2.0.
|
||||
const RCSuccess ResponseCode = 0x000
|
||||
|
||||
// A responseHeader is a header for TPM responses.
|
||||
type responseHeader struct {
|
||||
Tag Tag
|
||||
Size uint32
|
||||
Res ResponseCode
|
||||
}
|
||||
|
||||
// A Handle is a reference to a TPM object.
|
||||
type Handle uint32
|
||||
|
||||
type handleList []Handle
|
||||
|
||||
func (l *handleList) TPMMarshal(out io.Writer) error {
|
||||
return fmt.Errorf("TPMMarhsal on []Handle is not supported yet")
|
||||
}
|
||||
|
||||
func (l *handleList) TPMUnmarshal(in io.Reader) error {
|
||||
var numHandles uint16
|
||||
if err := binary.Read(in, binary.BigEndian, &numHandles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make len(e) match size exactly.
|
||||
size := int(numHandles)
|
||||
if len(*l) >= size {
|
||||
*l = (*l)[:size]
|
||||
} else {
|
||||
*l = append(*l, make([]Handle, size-len(*l))...)
|
||||
}
|
||||
return binary.Read(in, binary.BigEndian, *l)
|
||||
}
|
||||
|
||||
// SelfMarshaler allows custom types to override default encoding/decoding
|
||||
// behavior in Pack, Unpack and UnpackBuf.
|
||||
type SelfMarshaler interface {
|
||||
TPMMarshal(out io.Writer) error
|
||||
TPMUnmarshal(in io.Reader) error
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["tbs_windows.go"],
|
||||
importmap = "k8s.io/kops/vendor/github.com/google/go-tpm/tpmutil/tbs",
|
||||
importpath = "github.com/google/go-tpm/tpmutil/tbs",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,250 @@
|
|||
// Copyright (c) 2018, Google LLC All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package tbs provides an low-level interface directly mapping to Windows
|
||||
// Tbs.dll system library commands:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/TBS/tpm-base-services-portal
|
||||
// Public field descriptions contain links to the high-level Windows documentation.
|
||||
package tbs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Context references the current TPM context
|
||||
type Context uintptr
|
||||
|
||||
// Version of TPM being used by the application.
|
||||
type Version uint32
|
||||
|
||||
// Flag indicates TPM verisions that are supported by the application.
|
||||
type Flag uint32
|
||||
|
||||
// CommandPriority is used to determine which pending command to submit whenever the TPM is free.
|
||||
type CommandPriority uint32
|
||||
|
||||
// Command parameters:
|
||||
// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/shared/tbs.h
|
||||
const (
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/ns-tbs-tdtbs_context_params2
|
||||
// OR flags to use multiple.
|
||||
RequestRaw Flag = 1 << iota // Add flag to request raw context
|
||||
IncludeTPM12 // Add flag to support TPM 1.2
|
||||
IncludeTPM20 // Add flag to support TPM 2
|
||||
|
||||
TPMVersion12 Version = 1 // For TPM 1.2 applications
|
||||
TPMVersion20 Version = 2 // For TPM 2 applications or applications using multiple TPM versions
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/tbs/command-scheduling
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsip_submit_command#parameters
|
||||
LowPriority CommandPriority = 100 // For low priority application use
|
||||
NormalPriority CommandPriority = 200 // For normal priority application use
|
||||
HighPriority CommandPriority = 300 // For high priority application use
|
||||
SystemPriority CommandPriority = 400 // For system tasks that access the TPM
|
||||
|
||||
commandLocalityZero uint32 = 0 // Windows currently only supports TBS_COMMAND_LOCALITY_ZERO.
|
||||
)
|
||||
|
||||
// Error is the return type of all functions in this package.
|
||||
type Error uint32
|
||||
|
||||
func (err Error) Error() string {
|
||||
if description, ok := errorDescriptions[err]; ok {
|
||||
return fmt.Sprintf("TBS Error 0x%X: %s", uint32(err), description)
|
||||
}
|
||||
return fmt.Sprintf("Unrecognized TBS Error 0x%X", uint32(err))
|
||||
}
|
||||
|
||||
func getError(err uintptr) error {
|
||||
// tbs.dll uses 0x0 as the return value for success.
|
||||
if err == 0 {
|
||||
return nil
|
||||
}
|
||||
return Error(err)
|
||||
}
|
||||
|
||||
// TBS Return Codes:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/TBS/tbs-return-codes
|
||||
const (
|
||||
ErrInternalError Error = 0x80284001
|
||||
ErrBadParameter Error = 0x80284002
|
||||
ErrInvalidOutputPointer Error = 0x80284003
|
||||
ErrInvalidContext Error = 0x80284004
|
||||
ErrInsufficientBuffer Error = 0x80284005
|
||||
ErrIOError Error = 0x80284006
|
||||
ErrInvalidContextParam Error = 0x80284007
|
||||
ErrServiceNotRunning Error = 0x80284008
|
||||
ErrTooManyTBSContexts Error = 0x80284009
|
||||
ErrTooManyResources Error = 0x8028400A
|
||||
ErrServiceStartPending Error = 0x8028400B
|
||||
ErrPPINotSupported Error = 0x8028400C
|
||||
ErrCommandCanceled Error = 0x8028400D
|
||||
ErrBufferTooLarge Error = 0x8028400E
|
||||
ErrTPMNotFound Error = 0x8028400F
|
||||
ErrServiceDisabled Error = 0x80284010
|
||||
ErrNoEventLog Error = 0x80284011
|
||||
ErrAccessDenied Error = 0x80284012
|
||||
ErrProvisioningNotAllowed Error = 0x80284013
|
||||
ErrPPIFunctionUnsupported Error = 0x80284014
|
||||
ErrOwnerauthNotFound Error = 0x80284015
|
||||
)
|
||||
|
||||
var errorDescriptions = map[Error]string{
|
||||
ErrInternalError: "An internal software error occurred.",
|
||||
ErrBadParameter: "One or more parameter values are not valid.",
|
||||
ErrInvalidOutputPointer: "A specified output pointer is bad.",
|
||||
ErrInvalidContext: "The specified context handle does not refer to a valid context.",
|
||||
ErrInsufficientBuffer: "The specified output buffer is too small.",
|
||||
ErrIOError: "An error occurred while communicating with the TPM.",
|
||||
ErrInvalidContextParam: "A context parameter that is not valid was passed when attempting to create a TBS context.",
|
||||
ErrServiceNotRunning: "The TBS service is not running and could not be started.",
|
||||
ErrTooManyTBSContexts: "A new context could not be created because there are too many open contexts.",
|
||||
ErrTooManyResources: "A new virtual resource could not be created because there are too many open virtual resources.",
|
||||
ErrServiceStartPending: "The TBS service has been started but is not yet running.",
|
||||
ErrPPINotSupported: "The physical presence interface is not supported.",
|
||||
ErrCommandCanceled: "The command was canceled.",
|
||||
ErrBufferTooLarge: "The input or output buffer is too large.",
|
||||
ErrTPMNotFound: "A compatible Trusted Platform Module (TPM) Security Device cannot be found on this computer.",
|
||||
ErrServiceDisabled: "The TBS service has been disabled.",
|
||||
ErrNoEventLog: "The TBS event log is not available.",
|
||||
ErrAccessDenied: "The caller does not have the appropriate rights to perform the requested operation.",
|
||||
ErrProvisioningNotAllowed: "The TPM provisioning action is not allowed by the specified flags.",
|
||||
ErrPPIFunctionUnsupported: "The Physical Presence Interface of this firmware does not support the requested method.",
|
||||
ErrOwnerauthNotFound: "The requested TPM OwnerAuth value was not found.",
|
||||
}
|
||||
|
||||
// Tbs.dll provides an API for making calls to the TPM:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/TBS/tpm-base-services-portal
|
||||
var (
|
||||
tbsDLL = syscall.NewLazyDLL("Tbs.dll")
|
||||
tbsGetDeviceInfo = tbsDLL.NewProc("Tbsi_GetDeviceInfo")
|
||||
tbsCreateContext = tbsDLL.NewProc("Tbsi_Context_Create")
|
||||
tbsContextClose = tbsDLL.NewProc("Tbsip_Context_Close")
|
||||
tbsSubmitCommand = tbsDLL.NewProc("Tbsip_Submit_Command")
|
||||
tbsGetTCGLog = tbsDLL.NewProc("Tbsi_Get_TCG_Log")
|
||||
)
|
||||
|
||||
// Returns the address of the beginning of a slice or 0 for a nil slice.
|
||||
func sliceAddress(s []byte) uintptr {
|
||||
if len(s) == 0 {
|
||||
return 0
|
||||
}
|
||||
return uintptr(unsafe.Pointer(&(s[0])))
|
||||
}
|
||||
|
||||
// Declaration of TPM_DEVICE_INFO from tbs.h
|
||||
type DeviceInfo struct {
|
||||
StructVersion uint32
|
||||
TPMVersion Version
|
||||
TPMInterfaceType uint32
|
||||
TPMImpRevision uint32
|
||||
}
|
||||
|
||||
func GetDeviceInfo() (*DeviceInfo, error) {
|
||||
info := DeviceInfo{}
|
||||
// TBS_RESULT Tbsi_GetDeviceInfo(
|
||||
// UINT32 Size,
|
||||
// PVOID Info
|
||||
// );
|
||||
result, _, _ := tbsGetDeviceInfo.Call(
|
||||
unsafe.Sizeof(info),
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
)
|
||||
return &info, getError(result)
|
||||
}
|
||||
|
||||
// CreateContext creates a new TPM context:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsi_context_create
|
||||
func CreateContext(version Version, flag Flag) (Context, error) {
|
||||
var context Context
|
||||
params := struct {
|
||||
Version
|
||||
Flag
|
||||
}{version, flag}
|
||||
// TBS_RESULT Tbsi_Context_Create(
|
||||
// _In_ PCTBS_CONTEXT_PARAMS pContextParams,
|
||||
// _Out_ PTBS_HCONTEXT *phContext
|
||||
// );
|
||||
result, _, _ := tbsCreateContext.Call(
|
||||
uintptr(unsafe.Pointer(¶ms)),
|
||||
uintptr(unsafe.Pointer(&context)),
|
||||
)
|
||||
return context, getError(result)
|
||||
}
|
||||
|
||||
// Close closes an existing TPM context:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsip_context_close
|
||||
func (context Context) Close() error {
|
||||
// TBS_RESULT Tbsip_Context_Close(
|
||||
// _In_ TBS_HCONTEXT hContext
|
||||
// );
|
||||
result, _, _ := tbsContextClose.Call(uintptr(context))
|
||||
return getError(result)
|
||||
}
|
||||
|
||||
// SubmitCommand sends commandBuffer to the TPM, returning the number of bytes
|
||||
// written to responseBuffer. ErrInsufficientBuffer is returned if the
|
||||
// responseBuffer is too short. ErrInvalidOutputPointer is returned if the
|
||||
// responseBuffer is nil. On failure, the returned length is unspecified.
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsip_submit_command
|
||||
func (context Context) SubmitCommand(
|
||||
priority CommandPriority,
|
||||
commandBuffer []byte,
|
||||
responseBuffer []byte,
|
||||
) (uint32, error) {
|
||||
responseBufferLen := uint32(len(responseBuffer))
|
||||
|
||||
// TBS_RESULT Tbsip_Submit_Command(
|
||||
// _In_ TBS_HCONTEXT hContext,
|
||||
// _In_ TBS_COMMAND_LOCALITY Locality,
|
||||
// _In_ TBS_COMMAND_PRIORITY Priority,
|
||||
// _In_ const PCBYTE *pabCommand,
|
||||
// _In_ UINT32 cbCommand,
|
||||
// _Out_ PBYTE *pabResult,
|
||||
// _Inout_ UINT32 *pcbOutput
|
||||
// );
|
||||
result, _, _ := tbsSubmitCommand.Call(
|
||||
uintptr(context),
|
||||
uintptr(commandLocalityZero),
|
||||
uintptr(priority),
|
||||
sliceAddress(commandBuffer),
|
||||
uintptr(len(commandBuffer)),
|
||||
sliceAddress(responseBuffer),
|
||||
uintptr(unsafe.Pointer(&responseBufferLen)),
|
||||
)
|
||||
return responseBufferLen, getError(result)
|
||||
}
|
||||
|
||||
// GetTCGLog gets the system event log, returning the number of bytes written
|
||||
// to logBuffer. If logBuffer is nil, the size of the TCG log is returned.
|
||||
// ErrInsufficientBuffer is returned if the logBuffer is too short. On failure,
|
||||
// the returned length is unspecified.
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/Tbs/nf-tbs-tbsi_get_tcg_log
|
||||
func (context Context) GetTCGLog(logBuffer []byte) (uint32, error) {
|
||||
logBufferLen := uint32(len(logBuffer))
|
||||
|
||||
// TBS_RESULT Tbsi_Get_TCG_Log(
|
||||
// TBS_HCONTEXT hContext,
|
||||
// PBYTE pOutputBuf,
|
||||
// PUINT32 pOutputBufLen
|
||||
// );
|
||||
result, _, _ := tbsGetTCGLog.Call(
|
||||
uintptr(context),
|
||||
sliceAddress(logBuffer),
|
||||
uintptr(unsafe.Pointer(&logBufferLen)),
|
||||
)
|
||||
return logBufferLen, getError(result)
|
||||
}
|
|
@ -368,6 +368,17 @@ github.com/google/go-containerregistry/pkg/v1/stream
|
|||
github.com/google/go-containerregistry/pkg/v1/types
|
||||
# github.com/google/go-querystring v1.0.0
|
||||
github.com/google/go-querystring/query
|
||||
# github.com/google/go-tpm v0.3.2
|
||||
## explicit
|
||||
github.com/google/go-tpm/tpm2
|
||||
github.com/google/go-tpm/tpmutil
|
||||
github.com/google/go-tpm/tpmutil/tbs
|
||||
# github.com/google/go-tpm-tools v0.3.0-beta1
|
||||
## explicit
|
||||
github.com/google/go-tpm-tools/client
|
||||
github.com/google/go-tpm-tools/internal
|
||||
github.com/google/go-tpm-tools/proto/attest
|
||||
github.com/google/go-tpm-tools/proto/tpm
|
||||
# github.com/google/gofuzz v1.2.0
|
||||
github.com/google/gofuzz
|
||||
github.com/google/gofuzz/bytesource
|
||||
|
|
Loading…
Reference in New Issue