pax_global_header00006660000000000000000000000064140676463450014531gustar00rootroot0000000000000052 comment=05baef61e123181de84de4de0de5100427f2fc80 go-tspi-0.3.0/000077500000000000000000000000001406764634500131135ustar00rootroot00000000000000go-tspi-0.3.0/.travis.yml000066400000000000000000000002121406764634500152170ustar00rootroot00000000000000language: go go: - 1.10.8 - 1.11.5 arch: - AMD64 - ppc64le install: true script: - go get golang.org/x/lint/golint - ./test go-tspi-0.3.0/CONTRIBUTING.md000066400000000000000000000021151406764634500153430ustar00rootroot00000000000000# How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. ## Community Guidelines This project follows [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). go-tspi-0.3.0/LICENSE000066400000000000000000000260751406764634500141320ustar00rootroot00000000000000Apache 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. go-tspi-0.3.0/README.md000066400000000000000000000033731406764634500144000ustar00rootroot00000000000000# go-tspi - Go bindings and support code for libtspi and tpm communication [![Build Status (Travis)](https://travis-ci.org/google/go-tspi.svg?branch=master)](https://travis-ci.org/google/go-tspi) This is a library providing a set of bindings for communication between code written in Go and libtspi, the library responsible for providing a TPM control interface. It consists of the following components: ## tspi The tspi bindings for Go. These are a low-level interface intended for use by people writing new TPM-using applications in Go. Code using these bindings must run on the same system as the TPM. For example: ```go // Create a new TSPI context context, err := tspi.NewContext() // Connect to the TPM daemon context.connect() // Obtain a handle to the TPM itself tpm := context.GetTPM() // Obtain the TPM event log log, err := tpm.GetEventLog() ``` ## attestation and verification Helper functions for performing attestation-related tasks ```go // Retrieve the EK certificate ekcert, err := attestation.GetEKCert(context) // Verify that the EK certificate is signed by a TPM vendor err = verification.VerifyEKCert(ekcert) if err != nil { log.Fatal("Unable to verify EK certificate!") } ``` ## tpmd Daemon for performing certain TPM operations at a higher level API or via a network. Takes the listening port number as the only argument. ## tpmclient Library for client applications communicating with tpmd. Avoids the need for individual applications to care about TSPI context or resource lifecycles themselves. ```go `// Connect to the TPM daemon on localhost port 12401 client := tpmclient.New("127.0.0.1:12401") // Extend a PCR with some data data := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} client.Extend(15, 0x1000, data, "Test extension")` ``` go-tspi-0.3.0/attestation/000077500000000000000000000000001406764634500154525ustar00rootroot00000000000000go-tspi-0.3.0/attestation/attestation.go000066400000000000000000000153201406764634500203410ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 attestation import ( "errors" "fmt" "github.com/google/go-tspi/tspi" "github.com/google/go-tspi/tspiconst" ) // This is used for object use authorization // We let it be well known because the // additional security gained is insignificant // compared to the inconveniences it can cause var wellKnownSecret [20]byte func pad(plaintext []byte, bsize int) ([]byte, error) { if bsize >= 256 { return nil, errors.New("bsize must be < 256") } pad := bsize - (len(plaintext) % bsize) if pad == 0 { pad = bsize } for i := 0; i < pad; i++ { plaintext = append(plaintext, byte(pad)) } return plaintext, nil } // AIKChallengeResponse takes the output from GenerateChallenge along with the // encrypted AIK key blob. The TPM then decrypts the asymmetric challenge with // its EK in order to obtain the AES key, and uses the AES key to decrypt the // symmetrically encrypted data. It verifies that this data blob corresponds // to the AIK it was given, and if so hands back the secret contained within // the symmetrically encrypted data. func AIKChallengeResponse(context *tspi.Context, aikblob []byte, asymchallenge []byte, symchallenge []byte) (secret []byte, err error) { srk, err := context.LoadKeyByUUID(tspiconst.TSS_PS_TYPE_SYSTEM, tspi.TSS_UUID_SRK) if err != nil { return nil, err } srkpolicy, err := srk.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, err } srkpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnownSecret[:]) tpm := context.GetTPM() tpmpolicy, err := context.CreatePolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, err } tpm.AssignPolicy(tpmpolicy) tpmpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnownSecret[:]) aik, err := context.LoadKeyByBlob(srk, aikblob) if err != nil { return nil, err } secret, err = tpm.ActivateIdentity(aik, asymchallenge, symchallenge) return secret, err } // CreateAIK asks the TPM to generate an Attestation Identity Key. It returns // the unencrypted public half of the AIK along with an encrypted blob // containing both halves of the key, and any error. func CreateAIK(context *tspi.Context) ([]byte, []byte, error) { n := make([]byte, 2048/8) for i := 0; i < 2048/8; i++ { n[i] = 0xff } srk, err := context.LoadKeyByUUID(tspiconst.TSS_PS_TYPE_SYSTEM, tspi.TSS_UUID_SRK) if err != nil { return nil, nil, err } keypolicy, err := srk.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, nil, err } err = keypolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnownSecret[:]) if err != nil { return nil, nil, err } tpm := context.GetTPM() tpmpolicy, err := tpm.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, nil, err } err = tpm.AssignPolicy(tpmpolicy) if err != nil { return nil, nil, err } err = tpmpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnownSecret[:]) if err != nil { return nil, nil, err } pcakey, err := context.CreateKey(tspiconst.TSS_KEY_TYPE_LEGACY | tspiconst.TSS_KEY_SIZE_2048) if err != nil { return nil, nil, err } err = pcakey.SetModulus(n) if err != nil { return nil, nil, err } aik, err := context.CreateKey(tspiconst.TSS_KEY_TYPE_IDENTITY | tspiconst.TSS_KEY_SIZE_2048) if err != nil { return nil, nil, err } _, err = tpm.CollateIdentityRequest(srk, pcakey, aik) if err != nil { return nil, nil, err } pubkey, err := aik.GetPubKeyBlob() if err != nil { return nil, nil, err } blob, err := aik.GetKeyBlob() if err != nil { return nil, nil, err } _, err = aik.GetModulus() return pubkey, blob, nil } // GetQuote consumes a nonce and the aik blob and returns the quote, // a signature, and any error func GetQuote(context *tspi.Context, aikblob, nonce []byte) ([]byte, []byte, error) { srk, err := context.LoadKeyByUUID(tspiconst.TSS_PS_TYPE_SYSTEM, tspi.TSS_UUID_SRK) if err != nil { return nil, nil, fmt.Errorf("LoadKeyByUUID failed: %v", err) } srkpolicy, err := srk.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, nil, fmt.Errorf("GetPolicy failed: %v", err) } srkpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnownSecret[:]) tpm := context.GetTPM() aik, err := context.LoadKeyByBlob(srk, aikblob) if err != nil { return nil, nil, fmt.Errorf("LoadKeyByBlob failed: %v", err) } pcrs, err := context.CreatePCRs(tspiconst.TSS_PCRS_STRUCT_DEFAULT) if err != nil { return nil, nil, fmt.Errorf("failed to get a reference to PCRs: %v", err) } // GetQuote will only quote the PCR values that are selected by SetPCRs() // We want all the PCR values so we pass a slice of 0 through 23 selectedPCRs := make([]int, 24) for i := 0; i < 24; i++ { selectedPCRs[i] = i } if err = pcrs.SetPCRs(selectedPCRs); err != nil { return nil, nil, fmt.Errorf("failed to set the PCR bitmap %v", err) } return tpm.GetQuote(aik, pcrs, nonce) } // GetEKCert reads the Endorsement Key certificate from the TPM's NVRAM and // returns it, along with any error generated. func GetEKCert(context *tspi.Context) (ekcert []byte, err error) { tpm := context.GetTPM() nv, err := context.CreateNV() if err != nil { return nil, err } policy, err := tpm.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, err } policy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnownSecret[:]) nv.SetIndex(0x1000f000) nv.AssignPolicy(policy) data, err := nv.ReadValue(0, 5) if err != nil { return nil, err } tag := (uint)((uint)(data[0])<<8 | (uint)(data[1])) if tag != 0x1001 { return nil, fmt.Errorf("invalid tag: %x", tag) } if data[2] != 0 { return nil, fmt.Errorf("invalid certificate") } ekbuflen := (uint)(uint(data[3])<<8 | (uint)(data[4])) offset := (uint)(5) data, err = nv.ReadValue(offset, 2) tag = (uint)((uint)(data[0])<<8 | (uint)(data[1])) if tag == 0x1002 { offset += 2 ekbuflen -= 2 } else if data[0] != 0x30 { return nil, fmt.Errorf("invalid header: %x", tag) } ekoffset := (uint)(0) var ekbuf []byte for ekoffset < ekbuflen { length := (uint)(ekbuflen - ekoffset) if length > 128 { length = 128 } data, err = nv.ReadValue(offset, length) if err != nil { return nil, err } ekbuf = append(ekbuf, data...) offset += length ekoffset += length } return ekbuf, nil } go-tspi-0.3.0/go.mod000066400000000000000000000002621406764634500142210ustar00rootroot00000000000000module github.com/google/go-tspi go 1.12 require ( github.com/google/certificate-transparency-go v1.0.21 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 // indirect ) go-tspi-0.3.0/go.sum000066400000000000000000000010231406764634500142420ustar00rootroot00000000000000github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= go-tspi-0.3.0/test000077500000000000000000000017231406764634500140230ustar00rootroot00000000000000#!/bin/bash -e # # source ./build TESTABLE="" FORMATTABLE="$TESTABLE attestation tpmd tspi verification tpmclient tpmown tspiconst" # user has not provided PKG override if [ -z "$PKG" ]; then TEST=$TESTABLE FMT=$FORMATTABLE # user has provided PKG override else # strip out slashes and dots from PKG=./foo/ TEST=${PKG//\//} TEST=${TEST//./} # only run gofmt on packages provided by user FMT="$TEST" fi # split TEST into an array and prepend REPO_PATH to each local package split=(${TEST// / }) TEST=${split[@]/#/${REPO_PATH}/} # TODO: add tests.. # echo "Running tests..." # go test ${COVER} $@ ${TEST} echo "Checking gofmt..." fmtRes=$(gofmt -l $FMT) if [ -n "${fmtRes}" ]; then echo -e "gofmt checking failed:\n${fmtRes}" exit 255 fi echo "Checking golint..." # tpmclient and tspiconst declare C style constants and don't pass golint. For # now ignore them. golint -set_exit_status \ ./attestation \ ./tpmd \ ./tpmown \ ./verification echo "Success" go-tspi-0.3.0/tpmclient/000077500000000000000000000000001406764634500151125ustar00rootroot00000000000000go-tspi-0.3.0/tpmclient/tpmclient.go000066400000000000000000000207171406764634500174470ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tpmclient import ( "bytes" "crypto/rand" "encoding/json" "fmt" "io" "io/ioutil" "net/http" "time" "github.com/google/go-tspi/tspiconst" "github.com/google/go-tspi/verification" ) // TPMClient represents a connection to a system running a daemon providing // access to TPM functionality type TPMClient struct { host string timeout time.Duration } const ( GetEKCertURL = "/v1/getEkcert" ExtendURL = "/v1/extend" QuoteURL = "/v1/quote" GenerateAikURL = "/v1/generateAik" GenerateKeyURL = "/v1/generateKey" AikChallengeURL = "/v1/aikChallenge" ) func (client *TPMClient) get(endpoint string) (*http.Response, error) { url := fmt.Sprintf("http://%s%s", client.host, endpoint) httpClient := &http.Client{ Timeout: client.timeout, } resp, err := httpClient.Get(url) return resp, err } func (client *TPMClient) post(endpoint string, data io.Reader) (*http.Response, error) { url := fmt.Sprintf("http://%s%s", client.host, endpoint) httpClient := &http.Client{ Timeout: client.timeout, } resp, err := httpClient.Post(url, "application/json", data) return resp, err } type EkcertResponse struct { EKCert []byte } // GetEKCert obtains the Endorsement Key certificate from the client TPM. This // is an X509 certificate containing the public half of the Endorsement Key // and a signature chain chaining back to a vendor-issued signing certificate. func (client *TPMClient) GetEKCert() (ekcert []byte, err error) { var ekcertData EkcertResponse ekresp, err := client.get(GetEKCertURL) if err != nil { return nil, fmt.Errorf("Can't obtain ekcert: %s", err) } defer ekresp.Body.Close() body, err := ioutil.ReadAll(ekresp.Body) if err != nil { return nil, fmt.Errorf("Can't read ekcert response: %s", err) } err = json.Unmarshal(body, &ekcertData) if err != nil { return nil, fmt.Errorf("Can't parse ekcert response: %s", err) } return ekcertData.EKCert, nil } type AikResponse struct { AIKBlob []byte AIKPub []byte } // GenerateAIK requests that the TPM generate a new Attestation Identity Key. // It returns an unencrypted copy of the public half of the AIK, along with // a TSPI key blob encrypted by the TPM. func (client *TPMClient) GenerateAIK() (aikpub []byte, aikblob []byte, err error) { var aikData AikResponse aikresp, err := client.post(GenerateAikURL, nil) if err != nil { return nil, nil, fmt.Errorf("Can't generate AIK: %s", err) } defer aikresp.Body.Close() body, err := ioutil.ReadAll(aikresp.Body) if err != nil { return nil, nil, fmt.Errorf("Can't read AIK response: %s", err) } err = json.Unmarshal(body, &aikData) if err != nil { return nil, nil, fmt.Errorf("Can't parse AIK response: %s (%s)", err, body) } aikpub = aikData.AIKPub aikblob = aikData.AIKBlob return aikpub, aikblob, nil } type KeyData struct { KeyFlags int } type KeyResponse struct { KeyBlob []byte KeyPub []byte } // GenerateKey requests that the TPM generate a new keypair func (client *TPMClient) GenerateKey(flags int) (keypub []byte, keyblob []byte, err error) { var keyData KeyData var keyResponse KeyResponse keyData.KeyFlags = flags request, err := json.Marshal(keyData) if err != nil { return nil, nil, fmt.Errorf("Can't construct request JSON: %s", err) } keyresp, err := client.post(GenerateKeyURL, bytes.NewBuffer(request)) if err != nil { return nil, nil, fmt.Errorf("Can't generate key: %s", err) } defer keyresp.Body.Close() body, err := ioutil.ReadAll(keyresp.Body) if err != nil { return nil, nil, fmt.Errorf("Can't read key response: %s", err) } err = json.Unmarshal(body, &keyResponse) if err != nil { return nil, nil, fmt.Errorf("Can't parse key response: %s (%s)", err, body) } keypub = keyResponse.KeyPub keyblob = keyResponse.KeyBlob return keypub, keyblob, nil } type ChallengeData struct { AIK []byte Asymenc []byte Symenc []byte } type ChallengeResponse struct { Response []byte } // ValidateAIK challenges the TPM to validate an AIK by using the provided // key blob to decrypt a secret encrypted with the public half of the // AIK. This will only be possible if the TPM is able to decrypt the // encrypted key blob. The AIK is used to decrypt asymenc, which then // provides the AES key used to encrypt symenc. Decrypting symenc provides // the original secret, which is then returned. func (client *TPMClient) ValidateAIK(aikblob []byte, asymenc []byte, symenc []byte) (secret []byte, err error) { var challenge ChallengeData var response ChallengeResponse challenge.AIK = aikblob challenge.Asymenc = asymenc challenge.Symenc = symenc request, err := json.Marshal(challenge) if err != nil { return nil, fmt.Errorf("Can't construct challenge JSON: %s", err) } chalresp, err := client.post(AikChallengeURL, bytes.NewBuffer(request)) if err != nil { return nil, fmt.Errorf("Can't perform AIK challenge: %s", err) } defer chalresp.Body.Close() body, err := ioutil.ReadAll(chalresp.Body) if err != nil { return nil, fmt.Errorf("Can't read AIK challenge response: %s", err) } err = json.Unmarshal(body, &response) if err != nil { return nil, fmt.Errorf("Can't parse AIK challenge response: %s", err) } return response.Response, nil } type ExtendInput struct { Pcr int Eventtype int Data []byte Event string } // Extend extends a TPM PCR with the provided data. If event is nil, data must // be pre-hashed with SHA1 and will be used to extend the PCR directly. If // event is not nil, data and event will be hashed to generate the extension // value. Event will then be stored in the TPM event log. func (client *TPMClient) Extend(pcr int, eventtype int, data []byte, event string) error { var extendData ExtendInput extendData.Pcr = pcr extendData.Eventtype = eventtype extendData.Data = data extendData.Event = event request, err := json.Marshal(extendData) if err != nil { return fmt.Errorf("Can't construct extension JSON: %s", err) } chalresp, err := client.post(ExtendURL, bytes.NewBuffer(request)) if err != nil { return fmt.Errorf("Can't perform PCR extension: %s", err) } defer chalresp.Body.Close() return nil } type QuoteData struct { AIK []byte PCRs []int Nonce []byte } type QuoteResponse struct { Data []byte Validation []byte PCRValues [][]byte Events []tspiconst.Log } // GetQuote obtains a PCR quote from the TPM. It takes the aikpub Tspi Key, the // encrypted AIK blob and a list of PCRs as arguments. The response will // contain an array of PCR values, an array of log entries and any error. func (client *TPMClient) GetQuote(aikpub []byte, aikblob []byte, pcrs []int) (pcrvals [][]byte, log []tspiconst.Log, err error) { var quoteRequest QuoteData var response QuoteResponse nonce := make([]byte, 20) _, err = rand.Read(nonce) if err != nil { return nil, nil, fmt.Errorf("Unable to generate nonce: %s", err) } quoteRequest.AIK = aikblob quoteRequest.PCRs = pcrs quoteRequest.Nonce = nonce request, err := json.Marshal(quoteRequest) if err != nil { return nil, nil, fmt.Errorf("Can't construct quote request JSON: %s", err) } chalresp, err := client.post(QuoteURL, bytes.NewBuffer(request)) if err != nil { return nil, nil, fmt.Errorf("Can't perform obtain quote: %s", err) } defer chalresp.Body.Close() body, err := ioutil.ReadAll(chalresp.Body) if err != nil { return nil, nil, fmt.Errorf("Can't read quote response: %s", err) } err = json.Unmarshal(body, &response) if err != nil { return nil, nil, fmt.Errorf("Can't parse quote response: %s", err) } aikmod := aikpub[28:] err = verification.QuoteVerify(response.Data, response.Validation, aikmod, response.PCRValues, nonce) if err != nil { return nil, nil, fmt.Errorf("Can't verify quote: %s", err) } return response.PCRValues, response.Events, nil } // New returns a TPMClient structure configured to connect to the provided // host with the provided timeout. func New(host string, timeout time.Duration) *TPMClient { return &TPMClient{ host: host, timeout: timeout, } } go-tspi-0.3.0/tpmd/000077500000000000000000000000001406764634500140575ustar00rootroot00000000000000go-tspi-0.3.0/tpmd/tpmd.go000066400000000000000000000217271406764634500153630ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" "sync" "github.com/google/go-tspi/attestation" "github.com/google/go-tspi/tpmclient" "github.com/google/go-tspi/tspi" "github.com/google/go-tspi/tspiconst" ) var wellKnown [20]byte var pcrmutex sync.RWMutex func setupContext() (*tspi.Context, *tspi.TPM, error) { context, err := tspi.NewContext() if err != nil { return nil, nil, err } context.Connect() tpm := context.GetTPM() tpmpolicy, err := context.CreatePolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, nil, err } tpm.AssignPolicy(tpmpolicy) tpmpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnown[:]) return context, tpm, nil } func cleanupContext(context *tspi.Context) { context.Close() } func loadSRK(context *tspi.Context) (*tspi.Key, error) { srk, err := context.LoadKeyByUUID(tspiconst.TSS_PS_TYPE_SYSTEM, tspi.TSS_UUID_SRK) if err != nil { return nil, err } srkpolicy, err := srk.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { return nil, err } srkpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnown[:]) return srk, nil } func getEkcert(rw http.ResponseWriter, request *http.Request) { var output tpmclient.EkcertResponse context, _, err := setupContext() defer cleanupContext(context) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } if request.Method != "GET" { rw.WriteHeader(http.StatusBadRequest) return } ekcert, err := attestation.GetEKCert(context) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write([]byte(err.Error())) return } output.EKCert = ekcert jsonresponse, err := json.Marshal(output) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write([]byte(err.Error())) return } rw.Write(jsonresponse) } func generateAik(rw http.ResponseWriter, request *http.Request) { var output tpmclient.AikResponse context, _, err := setupContext() defer cleanupContext(context) if request.Method != "POST" { rw.WriteHeader(http.StatusBadRequest) return } aikpub, aikblob, err := attestation.CreateAIK(context) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } output.AIKPub = aikpub output.AIKBlob = aikblob jsonresponse, err := json.Marshal(output) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } rw.Write(jsonresponse) } func generateKey(rw http.ResponseWriter, request *http.Request) { var input tpmclient.KeyData var output tpmclient.KeyResponse body, err := ioutil.ReadAll(request.Body) if request.Method != "POST" { rw.WriteHeader(http.StatusBadRequest) return } err = json.Unmarshal(body, &input) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write([]byte(err.Error())) return } context, _, err := setupContext() defer cleanupContext(context) srk, err := loadSRK(context) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } key, err := context.CreateKey(input.KeyFlags) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } err = key.GenerateKey(srk) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } keypub, err := key.GetPubKeyBlob() if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } keyblob, err := key.GetKeyBlob() if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } output.KeyPub = keypub output.KeyBlob = keyblob jsonresponse, err := json.Marshal(output) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } rw.Write(jsonresponse) } func aikChallenge(rw http.ResponseWriter, request *http.Request) { body, err := ioutil.ReadAll(request.Body) var input tpmclient.ChallengeData var output tpmclient.ChallengeResponse context, _, err := setupContext() defer cleanupContext(context) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } if request.Method != "POST" { rw.WriteHeader(http.StatusBadRequest) return } err = json.Unmarshal(body, &input) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write([]byte(err.Error())) return } response, err := attestation.AIKChallengeResponse(context, input.AIK, input.Asymenc, input.Symenc) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } output.Response = response jsonresponse, err := json.Marshal(output) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } rw.Write(jsonresponse) } func quote(rw http.ResponseWriter, request *http.Request) { body, err := ioutil.ReadAll(request.Body) var input tpmclient.QuoteData var output tpmclient.QuoteResponse context, tpm, err := setupContext() defer cleanupContext(context) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } if request.Method != "POST" { rw.WriteHeader(http.StatusBadRequest) return } err = json.Unmarshal(body, &input) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write([]byte(err.Error())) return } pcrs, err := context.CreatePCRs(tspiconst.TSS_PCRS_STRUCT_INFO) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } err = pcrs.SetPCRs(input.PCRs) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } srk, err := context.LoadKeyByUUID(tspiconst.TSS_PS_TYPE_SYSTEM, tspi.TSS_UUID_SRK) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } srkpolicy, err := srk.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } srkpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnown[:]) aik, err := context.LoadKeyByBlob(srk, input.AIK) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } pcrmutex.Lock() data, validation, err := tpm.GetQuote(aik, pcrs, input.Nonce) if err != nil { pcrmutex.Unlock() rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } pcrvalues, err := pcrs.GetPCRValues() if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) pcrmutex.Unlock() return } log, err := tpm.GetEventLog() pcrmutex.Unlock() if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } output.Data = data output.Validation = validation output.PCRValues = pcrvalues output.Events = log jsonoutput, err := json.Marshal(output) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } rw.Write(jsonoutput) } func extend(rw http.ResponseWriter, request *http.Request) { body, err := ioutil.ReadAll(request.Body) var data tpmclient.ExtendInput context, tpm, err := setupContext() defer cleanupContext(context) if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } if request.Method != "POST" { rw.WriteHeader(http.StatusBadRequest) return } err = json.Unmarshal(body, &data) if err != nil { rw.WriteHeader(http.StatusBadRequest) rw.Write([]byte(err.Error())) return } pcrmutex.Lock() err = tpm.ExtendPCR(data.Pcr, data.Data, data.Eventtype, []byte(data.Event)) pcrmutex.Unlock() if err != nil { rw.WriteHeader(http.StatusInternalServerError) rw.Write([]byte(err.Error())) return } rw.Write([]byte("OK")) } func main() { if len(os.Args) < 2 { fmt.Printf("Usage: %s port\n", os.Args[0]) return } socket := fmt.Sprintf(":%s", os.Args[1]) http.HandleFunc(tpmclient.ExtendURL, extend) http.HandleFunc(tpmclient.QuoteURL, quote) http.HandleFunc(tpmclient.GetEKCertURL, getEkcert) http.HandleFunc(tpmclient.GenerateAikURL, generateAik) http.HandleFunc(tpmclient.GenerateKeyURL, generateKey) http.HandleFunc(tpmclient.AikChallengeURL, aikChallenge) err := http.ListenAndServe(socket, nil) if err != nil { fmt.Printf("Unable to listen - %s\n", err) } } go-tspi-0.3.0/tpmown/000077500000000000000000000000001406764634500144375ustar00rootroot00000000000000go-tspi-0.3.0/tpmown/tpmown.go000066400000000000000000000034021406764634500163110ustar00rootroot00000000000000package main import ( "bytes" "io/ioutil" "log" "os" "os/exec" "github.com/google/go-tspi/tspi" "github.com/google/go-tspi/tspiconst" ) var wellKnown [20]byte func main() { enable := []byte("6") activate := []byte("3") val, err := ioutil.ReadFile("/sys/class/tpm/tpm0/device/enabled") if os.IsNotExist(err) { log.Fatalf("System has no tpm") } if bytes.Equal(val, []byte("0\n")) { ioutil.WriteFile("/sys/class/tpm/tpm0/device/ppi/request", enable, 0664) exec.Command("reboot", "").Run() } val, err = ioutil.ReadFile("/sys/class/tpm/tpm0/device/active") if bytes.Equal(val, []byte("0\n")) { ioutil.WriteFile("/sys/class/tpm/tpm0/device/ppi/request", activate, 0664) exec.Command("reboot", "").Run() } val, err = ioutil.ReadFile("/sys/class/tpm/tpm0/device/owned") if bytes.Equal(val, []byte("0\n")) { context, err := tspi.NewContext() if err != nil { log.Fatalf("Unable to create TSS context") } context.Connect() tpm := context.GetTPM() tpmpolicy, err := tpm.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { log.Fatalf("Unable to obtain TPM policy") } err = tpmpolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnown[:]) if err != nil { log.Fatalf("Unable to set TPM policy") } srk, err := context.CreateKey(tspiconst.TSS_KEY_TSP_SRK | tspiconst.TSS_KEY_AUTHORIZATION) if err != nil { log.Fatalf("Unable to create SRK") } keypolicy, err := srk.GetPolicy(tspiconst.TSS_POLICY_USAGE) if err != nil { log.Fatalf("Unable to obtain SRK policy") } err = keypolicy.SetSecret(tspiconst.TSS_SECRET_MODE_SHA1, wellKnown[:]) if err != nil { log.Fatalf("Unable to set SRK policy") } err = tpm.TakeOwnership(srk) if err != nil { log.Fatalf("Unable to take ownership of TPM: %v", err) } } } go-tspi-0.3.0/tspi/000077500000000000000000000000001406764634500140725ustar00rootroot00000000000000go-tspi-0.3.0/tspi/context.go000066400000000000000000000127401406764634500161110ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" import ( "crypto" "unsafe" ) // Context is a TSS context type Context struct { context C.TSS_HCONTEXT tpm TPM } // NewContext returns a TSS daemon context func NewContext() (*Context, error) { context := new(Context) err := tspiError(C.Tspi_Context_Create(&context.context)) return context, err } // Connect opens a connection between the context and the TSS daemon. It // returns an error on failure. func (context *Context) Connect() error { var tpmhandle C.TSS_HTPM err := tspiError(C.Tspi_Context_Connect(context.context, nil)) if err != nil { return err } C.Tspi_Context_GetTpmObject(context.context, &tpmhandle) context.tpm = TPM{handle: tpmhandle, context: context.context} return nil } // Close closes the connection between the context and the TSS daemon. It // returns an error on failure. func (context *Context) Close() error { err := tspiError(C.Tspi_Context_Close(context.context)) return err } // CreateNV creates a TSS object referring to a TPM NVRAM area. It returns a // reference to the object and any error. func (context *Context) CreateNV() (*NV, error) { var handle C.TSS_HNVSTORE err := tspiError(C.Tspi_Context_CreateObject(context.context, C.TSS_OBJECT_TYPE_NV, 0, (*C.TSS_HOBJECT)(&handle))) return &NV{handle: handle, context: context.context}, err } // CreateKey creates a TSS object referring to a TPM key. It returns a // reference to the object and any error. func (context *Context) CreateKey(flags int) (*Key, error) { var handle C.TSS_HKEY err := tspiError(C.Tspi_Context_CreateObject(context.context, C.TSS_OBJECT_TYPE_RSAKEY, (C.TSS_FLAG)(flags), (*C.TSS_HOBJECT)(&handle))) return &Key{handle: handle, context: context.context}, err } // LoadKeyByUUID loads the key referenced by UUID. The storetype argument // indicates whether the key should be obtained from the system or user // stores. It returns a reference to the key and any error. func (context *Context) LoadKeyByUUID(storetype int, uuid C.TSS_UUID) (*Key, error) { var handle C.TSS_HKEY err := tspiError(C.Tspi_Context_LoadKeyByUUID(context.context, (C.TSS_FLAG)(storetype), uuid, &handle)) return &Key{handle: handle, context: context.context}, err } // LoadKeyByBlob takes an encrypted key blob and reads it into the TPM. It // takes a reference to the parent key and the key blob, and returns a // reference to the key and any error. func (context *Context) LoadKeyByBlob(parent *Key, blob []byte) (*Key, error) { var handle C.TSS_HKEY err := tspiError(C.Tspi_Context_LoadKeyByBlob(context.context, parent.handle, (C.UINT32)(len(blob)), (*C.BYTE)(unsafe.Pointer(&blob[0])), &handle)) return &Key{handle: handle, context: context.context}, err } // GetTPM returns a reference to the TPM associated with this context func (context *Context) GetTPM() *TPM { return &context.tpm } // CreatePolicy creates an object referring to a TSS policy. It returns a // reference to the object plus any error. func (context *Context) CreatePolicy(flags int) (*Policy, error) { var handle C.TSS_HPOLICY err := tspiError(C.Tspi_Context_CreateObject(context.context, C.TSS_OBJECT_TYPE_POLICY, (C.TSS_FLAG)(flags), (*C.TSS_HOBJECT)(&handle))) return &Policy{handle: handle, context: context.context}, err } // CreatePCRs creates an object referring to a TSS PCR composite. It returns // a reference to the object plus any error. func (context *Context) CreatePCRs(flags int) (*PCRs, error) { var handle C.TSS_HPCRS err := tspiError(C.Tspi_Context_CreateObject(context.context, C.TSS_OBJECT_TYPE_PCRS, (C.TSS_FLAG)(flags), (*C.TSS_HOBJECT)(&handle))) return &PCRs{handle: handle, context: context.context}, err } // CreateHash creates a Hash object for the given hash algorithm. If using an algorithm other than crypto.SHA1 and // if you are signing with this hash then make sure the key is created with signing algorithm TSS_SS_RSASSAPKCS1V15_DER. func (context *Context) CreateHash(hash crypto.Hash) (*Hash, error) { var hashAlg C.TSS_FLAG if hash == crypto.SHA1 { hashAlg = C.TSS_HASH_SHA1 } else { hashAlg = C.TSS_HASH_OTHER } var handle C.TSS_HHASH err := tspiError(C.Tspi_Context_CreateObject(context.context, C.TSS_OBJECT_TYPE_HASH, hashAlg, (*C.TSS_HOBJECT)(&handle))) if err != nil { return nil, err } return &Hash{ context: context.context, handle: handle, hashAlg: hash, }, nil } // GetCapability reads the requested capability and subcapability from the TPM. // A list of capabilities and subcapabilities can be found under tspiconst/tpsiconst. // For usage information see Section 21.1 of the TPM1.2 main specification-part2. func (context *Context) GetCapability(capa int, subcaplen uint, subcap uint8) ([]byte, error) { var resplen C.uint var resp *C.BYTE err := tspiError(C.Tspi_TPM_GetCapability(context.tpm.handle, (C.TSS_FLAG)(capa), (C.uint)(subcaplen), (*C.BYTE)(unsafe.Pointer(&subcap)), &resplen, &resp)) return C.GoBytes(unsafe.Pointer(resp), C.int(resplen)), err } go-tspi-0.3.0/tspi/hash.go000066400000000000000000000065331406764634500153530ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" import ( "crypto" "errors" "unsafe" ) // Hash is a TSS hash type Hash struct { handle C.TSS_HHASH context C.TSS_HCONTEXT hashAlg crypto.Hash } // Update updates a TSS hash with the data provided. It returns an error on // failure. func (hash *Hash) Update(data []byte) error { err := tspiError(C.Tspi_Hash_UpdateHashValue(hash.handle, (C.UINT32)(len(data)), (*C.BYTE)(&data[0]))) return err } // Verify checks whether a hash matches the signature signed with the // provided key. It returns an error on failure. func (hash *Hash) Verify(key *Key, signature []byte) error { err := tspiError(C.Tspi_Hash_VerifySignature(hash.handle, key.handle, (C.UINT32)(len(signature)), (*C.BYTE)(&signature[0]))) return err } // https://golang.org/src/crypto/rsa/pkcs1v15.go#L204 var hashPrefixes = map[crypto.Hash][]byte{ crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix. crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, } // SetValue sets the value of the hash to the given bytes func (hash *Hash) SetValue(hashed []byte) error { var data []byte if hash.hashAlg == crypto.SHA1 { data = hashed } else { prefix, ok := hashPrefixes[hash.hashAlg] if !ok { return errors.New("unsupported hash algorithm") } data = append(prefix, hashed...) } return tspiError(C.Tspi_Hash_SetHashValue(hash.handle, (C.UINT32)(len(data)), (*C.BYTE)(&data[0]))) } // Sign uses the provided key to create a signature. func (hash *Hash) Sign(key *Key) ([]byte, error) { var dataLen C.UINT32 var cData *C.BYTE err := tspiError(C.Tspi_Hash_Sign(hash.handle, key.handle, &dataLen, &cData)) data := C.GoBytes(unsafe.Pointer(cData), (C.int)(dataLen)) C.Tspi_Context_FreeMemory(hash.context, cData) if err != nil { return nil, err } return data, nil } // Close closes the Hash object. func (hash *Hash) Close() error { err := tspiError(C.Tspi_Context_CloseObject(hash.context, hash.handle)) return err } go-tspi-0.3.0/tspi/key.go000066400000000000000000000223471406764634500152210ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" import ( "crypto/rsa" "crypto/sha1" "errors" "math/big" "unsafe" ) // ModulusFromBlob provides the modulus of a provided TSS key blob func ModulusFromBlob(blob []byte) []byte { return blob[28:] } // Key is a TSS key type Key struct { handle C.TSS_HKEY context C.TSS_HCONTEXT } // GetPolicy returns the policy associated with the key func (key *Key) GetPolicy(poltype int) (*Policy, error) { var policyHandle C.TSS_HPOLICY err := tspiError(C.Tspi_GetPolicyObject((C.TSS_HOBJECT)(key.handle), (C.TSS_FLAG)(poltype), &policyHandle)) return &Policy{handle: policyHandle, context: key.context}, err } // SetModulus sets the modulus of a public key to the provided value func (key *Key) SetModulus(n []byte) error { err := tspiError(C.Tspi_SetAttribData((C.TSS_HOBJECT)(key.handle), C.TSS_TSPATTRIB_RSAKEY_INFO, C.TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, (C.UINT32)(len(n)), (*C.BYTE)(unsafe.Pointer(&n[0])))) return err } // GetExponent returns the exponent of the public key func (key *Key) GetExponent() (uint32, error) { var dataLen C.UINT32 var cData *C.BYTE err := tspiError(C.Tspi_GetAttribData((C.TSS_HOBJECT)(key.handle), C.TSS_TSPATTRIB_RSAKEY_INFO, C.TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT, &dataLen, &cData)) data := C.GoBytes(unsafe.Pointer(cData), (C.int)(dataLen)) C.Tspi_Context_FreeMemory(key.context, cData) if err != nil { return 0, err } if len(data) > 4 { return 0, errors.New("Exponent doesn't fit in int") } var exponent uint32 for _, b := range data { exponent = (exponent << 8) + uint32(b) } return exponent, nil } // GetPublicKey returns a go-native *rsa.PublicKey instance of this key's public key func (key *Key) GetPublicKey() (*rsa.PublicKey, error) { modulus, err := key.GetModulus() if err != nil { return nil, err } exponent, err := key.GetExponent() if err != nil { return nil, err } pk := &rsa.PublicKey{ N: new(big.Int).SetBytes(modulus), E: int(exponent), } return pk, nil } // GetModulus returns the modulus of the public key func (key *Key) GetModulus() (modulus []byte, err error) { var dataLen C.UINT32 var cData *C.BYTE err = tspiError(C.Tspi_GetAttribData((C.TSS_HOBJECT)(key.handle), C.TSS_TSPATTRIB_RSAKEY_INFO, C.TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &dataLen, &cData)) data := C.GoBytes(unsafe.Pointer(cData), (C.int)(dataLen)) C.Tspi_Context_FreeMemory(key.context, cData) return data, err } // GetPubKeyBlob returns the public half of the key in TPM blob format func (key *Key) GetPubKeyBlob() (pubkey []byte, err error) { var dataLen C.UINT32 var cData *C.BYTE err = tspiError(C.Tspi_GetAttribData((C.TSS_HOBJECT)(key.handle), C.TSS_TSPATTRIB_KEY_BLOB, C.TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &dataLen, &cData)) data := C.GoBytes(unsafe.Pointer(cData), (C.int)(dataLen)) C.Tspi_Context_FreeMemory(key.context, cData) return data, err } // GetKeyBlob returns an encrypted blob containing the public and private // halves of the key func (key *Key) GetKeyBlob() ([]byte, error) { var dataLen C.UINT32 var cData *C.BYTE err := tspiError(C.Tspi_GetAttribData((C.TSS_HOBJECT)(key.handle), C.TSS_TSPATTRIB_KEY_BLOB, C.TSS_TSPATTRIB_KEYBLOB_BLOB, &dataLen, &cData)) data := C.GoBytes(unsafe.Pointer(cData), (C.int)(dataLen)) C.Tspi_Context_FreeMemory(key.context, cData) return data, err } // Bind encrypts some data using the TPM and returns it. func (key *Key) Bind(data []byte) ([]byte, error) { var encdata C.TSS_HENCDATA var dataLen C.UINT32 var cData *C.BYTE err := tspiError(C.Tspi_Context_CreateObject(key.context, C.TSS_OBJECT_TYPE_ENCDATA, C.TSS_ENCDATA_BIND, (*C.TSS_HOBJECT)(&encdata))) if err != nil { return nil, err } err = tspiError(C.Tspi_Data_Bind(encdata, key.handle, (C.UINT32)(len(data)), (*C.BYTE)(&data[0]))) if err != nil { return nil, err } err = tspiError(C.Tspi_GetAttribData((C.TSS_HOBJECT)(encdata), C.TSS_TSPATTRIB_ENCDATA_BLOB, C.TSS_TSPATTRIB_ENCDATABLOB_BLOB, &dataLen, &cData)) if err != nil { return nil, err } blob := C.GoBytes(unsafe.Pointer(cData), (C.int(dataLen))) C.Tspi_Context_FreeMemory(key.context, cData) return blob, nil } // Unbind decrypts data previously encrypted with this key func (key *Key) Unbind(data []byte) ([]byte, error) { var encdata C.TSS_HENCDATA var dataLen C.UINT32 var cData *C.BYTE err := tspiError(C.Tspi_Context_CreateObject(key.context, C.TSS_OBJECT_TYPE_ENCDATA, C.TSS_ENCDATA_BIND, (*C.TSS_HOBJECT)(&encdata))) if err != nil { return nil, err } err = tspiError(C.Tspi_SetAttribData((C.TSS_HOBJECT)(encdata), C.TSS_TSPATTRIB_ENCDATA_BLOB, C.TSS_TSPATTRIB_ENCDATABLOB_BLOB, (C.UINT32)(len(data)), (*C.BYTE)(unsafe.Pointer(&data[0])))) if err != nil { return nil, err } err = tspiError(C.Tspi_Data_Unbind(encdata, key.handle, &dataLen, &cData)) if err != nil { return nil, err } blob := C.GoBytes(unsafe.Pointer(cData), (C.int(dataLen))) C.Tspi_Context_FreeMemory(key.context, cData) return blob, nil } // Seal encrypts the data using the TPM such that it can only be decrypted // when the TPM's PCR values match the values set on the provided PCRs // object. If pcrs is nil, the data will be sealed to the TPM but may be // decrypted regardless of platform state. func (key *Key) Seal(data []byte, pcrs *PCRs) ([]byte, error) { var encdata C.TSS_HENCDATA var dataLen C.UINT32 var cData *C.BYTE var pcrhandle C.TSS_HPCRS if pcrs != nil { pcrhandle = pcrs.handle } err := tspiError(C.Tspi_Context_CreateObject(key.context, C.TSS_OBJECT_TYPE_ENCDATA, C.TSS_ENCDATA_SEAL, (*C.TSS_HOBJECT)(&encdata))) if err != nil { return nil, err } err = tspiError(C.Tspi_Data_Seal(encdata, key.handle, (C.UINT32)(len(data)), (*C.BYTE)(&data[0]), pcrhandle)) if err != nil { return nil, err } err = tspiError(C.Tspi_GetAttribData((C.TSS_HOBJECT)(encdata), C.TSS_TSPATTRIB_ENCDATA_BLOB, C.TSS_TSPATTRIB_ENCDATABLOB_BLOB, &dataLen, &cData)) if err != nil { return nil, err } blob := C.GoBytes(unsafe.Pointer(cData), (C.int(dataLen))) C.Tspi_Context_FreeMemory(key.context, cData) return blob, nil } // Unseal decrypts data previously encrypted with this key as long as the // PCR values match those the data was sealed against func (key *Key) Unseal(data []byte) ([]byte, error) { var encdata C.TSS_HENCDATA var dataLen C.UINT32 var cData *C.BYTE err := tspiError(C.Tspi_Context_CreateObject(key.context, C.TSS_OBJECT_TYPE_ENCDATA, C.TSS_ENCDATA_SEAL, (*C.TSS_HOBJECT)(&encdata))) if err != nil { return nil, err } err = tspiError(C.Tspi_SetAttribData((C.TSS_HOBJECT)(encdata), C.TSS_TSPATTRIB_ENCDATA_BLOB, C.TSS_TSPATTRIB_ENCDATABLOB_BLOB, (C.UINT32)(len(data)), (*C.BYTE)(unsafe.Pointer(&data[0])))) if err != nil { return nil, err } err = tspiError(C.Tspi_Data_Unseal(encdata, key.handle, &dataLen, &cData)) if err != nil { return nil, err } blob := C.GoBytes(unsafe.Pointer(cData), (C.int(dataLen))) C.Tspi_Context_FreeMemory(key.context, cData) return blob, nil } // SetSignatureScheme sets the signature scheme on a newly created key. The scheme parameter should be one of tspiconst.TSS_SS_RSASSAPKCS1V15_SHA1 // or tspiconst.TSS_SS_RSASSAPKCS1V15_DER func (key *Key) SetSignatureScheme(scheme int) error { return tspiError(C.Tspi_SetAttribUint32((C.TSS_HOBJECT)(key.handle), C.TSS_TSPATTRIB_KEY_INFO, C.TSS_TSPATTRIB_KEYINFO_SIGSCHEME, (C.UINT32)(scheme))) } // GenerateKey generates a key pair on the TPM, wrapping it with the provided // key func (key *Key) GenerateKey(wrapkey *Key) (err error) { err = tspiError(C.Tspi_Key_CreateKey((C.TSS_HKEY)(key.handle), (C.TSS_HKEY)(wrapkey.handle), 0)) return err } // Certify signs the public key with another key held by the TPM func (key *Key) Certify(certifykey *Key, challenge []byte) ([]byte, []byte, error) { var validation C.TSS_VALIDATION challengeHash := sha1.Sum(challenge[:]) validation.ulExternalDataLength = sha1.Size validation.rgbExternalData = (*C.BYTE)(&challengeHash[0]) err := tspiError(C.Tspi_Key_CertifyKey((C.TSS_HKEY)(key.handle), (C.TSS_HKEY)(certifykey.handle), &validation)) if err != nil { return nil, nil, err } data := C.GoBytes(unsafe.Pointer(validation.rgbData), (C.int)(validation.ulDataLength)) validationdata := C.GoBytes(unsafe.Pointer(validation.rgbValidationData), (C.int)(validation.ulValidationDataLength)) C.Tspi_Context_FreeMemory(key.context, validation.rgbData) C.Tspi_Context_FreeMemory(key.context, validation.rgbValidationData) return data, validationdata, nil } // AssignPolicy assigns a TSS policy to the key. func (key *Key) AssignPolicy(policy *Policy) error { err := tspiError(C.Tspi_Policy_AssignToObject(policy.handle, (C.TSS_HOBJECT)(key.handle))) return err } // Close closes the Key object. func (key *Key) Close() error { err := tspiError(C.Tspi_Context_CloseObject(key.context, key.handle)) return err } go-tspi-0.3.0/tspi/nv.go000066400000000000000000000034121406764634500150440ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" import "unsafe" // NV is a TSS NV object type NV struct { handle C.TSS_HNVSTORE context C.TSS_HCONTEXT } // ReadValue reads length bytes from offset in the TPM NVRAM space func (nv *NV) ReadValue(offset uint, length uint) ([]byte, error) { var cdata *C.BYTE defer C.Tspi_Context_FreeMemory(nv.context, cdata) err := tspiError(C.Tspi_NV_ReadValue(nv.handle, (C.UINT32)(offset), (*C.UINT32)(unsafe.Pointer(&length)), &cdata)) if err != nil { return nil, err } data := C.GoBytes(unsafe.Pointer(cdata), C.int(length)) return data, err } // SetIndex sets the TPM NVRAM index that will be referenced by ReadValue() func (nv *NV) SetIndex(index uint) error { err := tspiError(C.Tspi_SetAttribUint32((C.TSS_HOBJECT)(nv.handle), C.TSS_TSPATTRIB_NV_INDEX, 0, (C.UINT32)(index))) return err } // AssignPolicy assigns a policy to the TPM NVRAM region func (nv *NV) AssignPolicy(policy *Policy) error { err := tspiError(C.Tspi_Policy_AssignToObject(policy.handle, (C.TSS_HOBJECT)(nv.handle))) return err } // Close closes the NV object. func (nv *NV) Close() error { err := tspiError(C.Tspi_Context_CloseObject(nv.context, nv.handle)) return err } go-tspi-0.3.0/tspi/pcrs.go000066400000000000000000000036361406764634500154000ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" import "unsafe" // PCRs is a structure representing a PCR object and the PCR values type PCRs struct { handle C.TSS_HPCRS context C.TSS_HCONTEXT pcrs [24][]byte pcrset [24]bool } // SetPCRs takes an array of integers referring to PCRs. Any queries performed // with this PCR object will then query these PCRs. func (pcrs *PCRs) SetPCRs(pcrset []int) error { for pcr := range pcrs.pcrset { pcrs.pcrset[pcr] = false } for _, pcr := range pcrset { err := tspiError(C.Tspi_PcrComposite_SelectPcrIndex(pcrs.handle, (C.UINT32)(pcr))) if err != nil { return err } pcrs.pcrset[pcr] = true } return nil } // GetPCRValues obtains the PCR values for any PCRs that have been set. func (pcrs *PCRs) GetPCRValues() ([][]byte, error) { var buflen C.UINT32 var buf *C.BYTE for pcr := range pcrs.pcrs { if pcrs.pcrset[pcr] == false { continue } err := tspiError(C.Tspi_PcrComposite_GetPcrValue(pcrs.handle, (C.UINT32)(pcr), &buflen, &buf)) if err != nil { return nil, err } pcrs.pcrs[pcr] = C.GoBytes(unsafe.Pointer(buf), (C.int)(buflen)) C.Tspi_Context_FreeMemory(pcrs.context, buf) } return pcrs.pcrs[:], nil } // Close closes the PCRs object. func (pcrs *PCRs) Close() error { err := tspiError(C.Tspi_Context_CloseObject(pcrs.context, pcrs.handle)) return err } go-tspi-0.3.0/tspi/policy.go000066400000000000000000000023061406764634500157210ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" // Policy is a TSS policy object type Policy struct { handle C.TSS_HPOLICY context C.TSS_HCONTEXT } // SetSecret sets the secret for a policy. This policy may then be applied to // another object. func (policy *Policy) SetSecret(sectype int, secret []byte) error { err := tspiError(C.Tspi_Policy_SetSecret(policy.handle, (C.TSS_FLAG)(sectype), (C.UINT32)(len(secret)), (*C.BYTE)(&secret[0]))) return err } // Close closes the Policy object. func (policy *Policy) Close() error { err := tspiError(C.Tspi_Context_CloseObject(policy.context, policy.handle)) return err } go-tspi-0.3.0/tspi/tpm.go000066400000000000000000000173701406764634500152310ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include import "C" import ( "bufio" "crypto/sha1" "encoding/binary" "io" "os" "unsafe" "github.com/google/go-tspi/tspiconst" ) // TPM is a TSS TPM object type TPM struct { handle C.TSS_HTPM context C.TSS_HCONTEXT } // GetEventLog returns an array of structures representing the contents of the // TSS event log func (tpm *TPM) GetEventLog() ([]tspiconst.Log, error) { var count C.UINT32 var events *C.TSS_PCR_EVENT var event C.TSS_PCR_EVENT var log []tspiconst.Log f, err := os.Open("/sys/kernel/security/tpm0/binary_bios_measurements") if err != nil { return nil, err } firmware_events := bufio.NewReader(f) for { var entry tspiconst.Log var datalen int32 err := binary.Read(firmware_events, binary.LittleEndian, &entry.Pcr) if err == io.EOF { break } if err != nil { return nil, err } err = binary.Read(firmware_events, binary.LittleEndian, &entry.Eventtype) if err != nil { return nil, err } err = binary.Read(firmware_events, binary.LittleEndian, &entry.PcrValue) if err != nil { return nil, err } err = binary.Read(firmware_events, binary.LittleEndian, &datalen) if err != nil { return nil, err } data := make([]byte, datalen) err = binary.Read(firmware_events, binary.LittleEndian, &data) if err != nil { return nil, err } entry.Event = data[:] log = append(log, entry) } err = tspiError(C.Tspi_TPM_GetEventLog(tpm.handle, &count, &events)) if err != nil { return nil, err } if count == 0 { return log, nil } length := count * C.UINT32(unsafe.Sizeof(event)) slice := (*[1 << 26]C.TSS_PCR_EVENT)(unsafe.Pointer(events))[:length:length] for i := 0; i < int(count); i++ { var entry tspiconst.Log entry.Pcr = int32(slice[i].ulPcrIndex) entry.Eventtype = int32(slice[i].eventType) copy(entry.PcrValue[:], C.GoBytes(unsafe.Pointer(slice[i].rgbPcrValue), C.int(slice[i].ulPcrValueLength))) entry.Event = C.GoBytes(unsafe.Pointer(slice[i].rgbEvent), C.int(slice[i].ulEventLength)) log = append(log, entry) } C.Tspi_Context_FreeMemory(tpm.context, (*C.BYTE)(unsafe.Pointer(events))) return log, nil } // ExtendPCR extends a pcr. If event is nil, data must be pre-hashed with // SHA1. If event is not nil, event is used to populate the TSS event // log. If both data and event are provided, both will be used to create the // extend hash. func (tpm *TPM) ExtendPCR(pcr int, data []byte, eventtype int, event []byte) error { var outlen C.UINT32 var pcrval *C.BYTE var eventstruct C.TSS_PCR_EVENT var err error shasum := sha1.Sum(data) if event != nil { var pcrdata *C.BYTE var pcrdatalen C.UINT32 eventstruct.versionInfo.bMajor = 1 eventstruct.versionInfo.bMinor = 2 eventstruct.versionInfo.bRevMajor = 1 eventstruct.versionInfo.bRevMinor = 0 eventstruct.ulPcrIndex = C.UINT32(pcr) eventstruct.rgbPcrValue = (*C.BYTE)(&shasum[0]) eventstruct.eventType = C.TSS_EVENTTYPE(eventtype) eventstruct.ulEventLength = C.UINT32(len(event)) eventstruct.rgbEvent = (*C.BYTE)(&event[0]) if data == nil || len(data) == 0 { pcrdata = nil pcrdatalen = C.UINT32(0) } else { pcrdata = (*C.BYTE)(&data[0]) pcrdatalen = C.UINT32(len(data)) } err = tspiError(C.Tspi_TPM_PcrExtend(tpm.handle, C.UINT32(pcr), pcrdatalen, pcrdata, &eventstruct, &outlen, &pcrval)) } else { err = tspiError(C.Tspi_TPM_PcrExtend(tpm.handle, C.UINT32(pcr), C.UINT32(len(shasum)), (*C.BYTE)(&shasum[0]), nil, &outlen, &pcrval)) } C.Tspi_Context_FreeMemory(tpm.context, pcrval) return err } // GetPCRValues obtains the PCR values from the TPM. func (tpm *TPM) GetPCRValues() ([][]byte, error) { var ( buflen C.UINT32 buf *C.BYTE pcrs [24][]byte ) for pcr := 0; pcr < 24; pcr++ { err := tspiError(C.Tspi_TPM_PcrRead(tpm.handle, (C.UINT32)(pcr), &buflen, &buf)) if err != nil { return nil, err } pcrs[pcr] = C.GoBytes(unsafe.Pointer(buf), (C.int)(buflen)) C.Tspi_Context_FreeMemory(tpm.context, buf) } return pcrs[:], nil } //GetQuote takes an encrypted key blob representing the AIK, a set of PCRs //and a challenge and returns a blob containing a hash of the PCR hashes and //the challenge, and a validation blob signed by the AIK. func (tpm *TPM) GetQuote(aik *Key, pcrs *PCRs, challenge []byte) ([]byte, []byte, error) { var validation C.TSS_VALIDATION challangeHash := sha1.Sum(challenge[:]) validation.ulExternalDataLength = sha1.Size validation.rgbExternalData = (*C.BYTE)(C.CBytes(challangeHash[:])) defer C.free(unsafe.Pointer(validation.rgbExternalData)) err := tspiError(C.Tspi_TPM_Quote(tpm.handle, aik.handle, pcrs.handle, &validation)) if err != nil { return nil, nil, err } data := C.GoBytes(unsafe.Pointer(validation.rgbData), (C.int)(validation.ulDataLength)) validationOutput := C.GoBytes(unsafe.Pointer(validation.rgbValidationData), (C.int)(validation.ulValidationDataLength)) C.Tspi_Context_FreeMemory(tpm.context, validation.rgbData) C.Tspi_Context_FreeMemory(tpm.context, validation.rgbValidationData) return data, validationOutput, nil } // ActivateIdentity accepts an encrypted key blob representing the AIK and // two blobs representing the asymmetric and symmetric challenges associated // with the AIK. If the TPM is able to decrypt the challenges and the // challenges correspond to the AIK, the TPM will return the original // challenge secret. func (tpm *TPM) ActivateIdentity(aik *Key, asymblob []byte, symblob []byte) (secret []byte, err error) { var creds *C.BYTE var credlen C.UINT32 err = tspiError(C.Tspi_TPM_ActivateIdentity(tpm.handle, aik.handle, (C.UINT32)(len(asymblob)), (*C.BYTE)(&asymblob[0]), (C.UINT32)(len(symblob)), (*C.BYTE)(&symblob[0]), &credlen, &creds)) if err != nil { return nil, err } plaintext := C.GoBytes(unsafe.Pointer(creds), (C.int)(credlen)) C.Tspi_Context_FreeMemory(tpm.context, creds) return plaintext, nil } // GetPolicy returns the TSS policy associated with the TPM. func (tpm *TPM) GetPolicy(poltype int) (*Policy, error) { var policyHandle C.TSS_HPOLICY err := tspiError(C.Tspi_GetPolicyObject((C.TSS_HOBJECT)(tpm.handle), (C.TSS_FLAG)(poltype), &policyHandle)) return &Policy{handle: policyHandle, context: tpm.context}, err } // TakeOwnership transitions a TPM from unowned state to owned, installing the // encrypted key blob as the SRK. func (tpm *TPM) TakeOwnership(srk *Key) error { err := tspiError(C.Tspi_TPM_TakeOwnership(tpm.handle, srk.handle, 0)) return err } // AssignPolicy assigns a TSS policy to the TPM. func (tpm *TPM) AssignPolicy(policy *Policy) error { err := tspiError(C.Tspi_Policy_AssignToObject(policy.handle, (C.TSS_HOBJECT)(tpm.handle))) return err } // CollateIdentityRequest creates a signing request for the provided AIKq func (tpm *TPM) CollateIdentityRequest(srk *Key, pubkey *Key, aik *Key) ([]byte, error) { var certLen C.UINT32 var cCertReq *C.BYTE err := tspiError(C.Tspi_TPM_CollateIdentityRequest(tpm.handle, srk.handle, pubkey.handle, 0, nil, aik.handle, C.TSS_ALG_AES, &certLen, &cCertReq)) certReq := C.GoBytes(unsafe.Pointer(cCertReq), (C.int)(certLen)) C.Tspi_Context_FreeMemory(tpm.context, cCertReq) return certReq, err } // Close closes the TPM object. func (tpm *TPM) Close() error { err := tspiError(C.Tspi_Context_CloseObject(tpm.context, tpm.handle)) return err } go-tspi-0.3.0/tspi/tspi.go000066400000000000000000000404461406764634500154100ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspi // #include // #cgo LDFLAGS: -ltspi import "C" import "errors" import "fmt" func tspiError(tssRet C.TSS_RESULT) error { ret := (int)(tssRet) if ret == 0 { return nil } if (ret & 0xf000) != 0 { ret &= ^(0xf000) switch { case ret == C.TSS_E_FAIL: return errors.New("TSS_E_FAIL") case ret == C.TSS_E_BAD_PARAMETER: return errors.New("TSS_E_BAD_PARAMETER") case ret == C.TSS_E_INTERNAL_ERROR: return errors.New("TSS_E_INTERNAL_ERROR") case ret == C.TSS_E_OUTOFMEMORY: return errors.New("TSS_E_OUTOFMEMORY") case ret == C.TSS_E_NOTIMPL: return errors.New("TSS_E_NOTIMPL") case ret == C.TSS_E_KEY_ALREADY_REGISTERED: return errors.New("TSS_E_KEY_ALREADY_REGISTERED") case ret == C.TSS_E_TPM_UNEXPECTED: return errors.New("TSS_E_TPM_UNEXPECTED") case ret == C.TSS_E_COMM_FAILURE: return errors.New("TSS_E_COMM_FAILURE") case ret == C.TSS_E_TIMEOUT: return errors.New("TSS_E_TIMEOUT") case ret == C.TSS_E_TPM_UNSUPPORTED_FEATURE: return errors.New("TSS_E_TPM_UNSUPPORTED_FEATURE") case ret == C.TSS_E_CANCELED: return errors.New("TSS_E_CANCELED") case ret == C.TSS_E_PS_KEY_NOTFOUND: return errors.New("TSS_E_PS_KEY_NOTFOUND") case ret == C.TSS_E_PS_KEY_EXISTS: return errors.New("TSS_E_PS_KEY_EXISTS") case ret == C.TSS_E_PS_BAD_KEY_STATE: return errors.New("TSS_E_PS_BAD_KEY_STATE") case ret == C.TSS_E_INVALID_OBJECT_TYPE: return errors.New("TSS_E_INVALID_OBJECT_TYPE") case ret == C.TSS_E_NO_CONNECTION: return errors.New("TSS_E_NO_CONNECTION") case ret == C.TSS_E_CONNECTION_FAILED: return errors.New("TSS_E_CONNECTION_FAILED") case ret == C.TSS_E_CONNECTION_BROKEN: return errors.New("TSS_E_CONNECTION_BROKEN") case ret == C.TSS_E_HASH_INVALID_ALG: return errors.New("TSS_E_HASH_INVALID_ALG") case ret == C.TSS_E_HASH_INVALID_LENGTH: return errors.New("TSS_E_HASH_INVALID_LENGTH") case ret == C.TSS_E_HASH_NO_DATA: return errors.New("TSS_E_HASH_NO_DATA") case ret == C.TSS_E_INVALID_ATTRIB_FLAG: return errors.New("TSS_E_INVALID_ATTRIB_FLAG") case ret == C.TSS_E_INVALID_ATTRIB_SUBFLAG: return errors.New("TSS_E_INVALID_ATTRIB_SUBFLAG") case ret == C.TSS_E_INVALID_ATTRIB_DATA: return errors.New("TSS_E_INVALID_ATTRIB_DATA") case ret == C.TSS_E_INVALID_OBJECT_INITFLAG: return errors.New("TSS_E_INVALID_OBJECT_INITFLAG") case ret == C.TSS_E_NO_PCRS_SET: return errors.New("TSS_E_NO_PCRS_SET") case ret == C.TSS_E_KEY_NOT_LOADED: return errors.New("TSS_E_KEY_NOT_LOADED") case ret == C.TSS_E_KEY_NOT_SET: return errors.New("TSS_E_KEY_NOT_SET") case ret == C.TSS_E_VALIDATION_FAILED: return errors.New("TSS_E_VALIDATION_FAILED") case ret == C.TSS_E_TSP_AUTHREQUIRED: return errors.New("TSS_E_TSP_AUTHREQUIRED") case ret == C.TSS_E_TSP_AUTH2REQUIRED: return errors.New("TSS_E_TSP_AUTH2REQUIRED") case ret == C.TSS_E_TSP_AUTHFAIL: return errors.New("TSS_E_TSP_AUTHFAIL") case ret == C.TSS_E_TSP_AUTH2FAIL: return errors.New("TSS_E_TSP_AUTH2FAIL") case ret == C.TSS_E_KEY_NO_MIGRATION_POLICY: return errors.New("TSS_E_KEY_NO_MIGRATION_POLICY") case ret == C.TSS_E_POLICY_NO_SECRET: return errors.New("TSS_E_POLICY_NO_SECRET") case ret == C.TSS_E_INVALID_OBJ_ACCESS: return errors.New("TSS_E_INVALID_OBJ_ACCESS") case ret == C.TSS_E_INVALID_ENCSCHEME: return errors.New("TSS_E_INVALID_ENCSCHEME") case ret == C.TSS_E_INVALID_SIGSCHEME: return errors.New("TSS_E_INVALID_SIGSCHEME") case ret == C.TSS_E_ENC_INVALID_LENGTH: return errors.New("TSS_E_ENC_INVALID_LENGTH") case ret == C.TSS_E_ENC_NO_DATA: return errors.New("TSS_E_ENC_NO_DATA") case ret == C.TSS_E_ENC_INVALID_TYPE: return errors.New("TSS_E_ENC_INVALID_TYPE") case ret == C.TSS_E_INVALID_KEYUSAGE: return errors.New("TSS_E_INVALID_KEYUSAGE") case ret == C.TSS_E_VERIFICATION_FAILED: return errors.New("TSS_E_VERIFICATION_FAILED") case ret == C.TSS_E_HASH_NO_IDENTIFIER: return errors.New("TSS_E_HASH_NO_IDENTIFIER") case ret == C.TSS_E_INVALID_HANDLE: return errors.New("TSS_E_INVALID_HANDLE") case ret == C.TSS_E_SILENT_CONTEXT: return errors.New("TSS_E_SILENT_CONTEXT") case ret == C.TSS_E_EK_CHECKSUM: return errors.New("TSS_E_EK_CHECKSUM") case ret == C.TSS_E_DELEGATION_NOTSET: return errors.New("TSS_E_DELEGATION_NOTSET") case ret == C.TSS_E_DELFAMILY_NOTFOUND: return errors.New("TSS_E_DELFAMILY_NOTFOUND") case ret == C.TSS_E_DELFAMILY_ROWEXISTS: return errors.New("TSS_E_DELFAMILY_ROWEXISTS") case ret == C.TSS_E_VERSION_MISMATCH: return errors.New("TSS_E_VERSION_MISMATCH") case ret == C.TSS_E_DAA_AR_DECRYPTION_ERROR: return errors.New("TSS_E_DAA_AR_DECRYPTION_ERROR") case ret == C.TSS_E_DAA_AUTHENTICATION_ERROR: return errors.New("TSS_E_DAA_AUTHENTICATION_ERROR") case ret == C.TSS_E_DAA_CHALLENGE_RESPONSE_ERROR: return errors.New("TSS_E_DAA_CHALLENGE_RESPONSE_ERROR") case ret == C.TSS_E_DAA_CREDENTIAL_PROOF_ERROR: return errors.New("TSS_E_DAA_CREDENTIAL_PROOF_ERROR") case ret == C.TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR: return errors.New("TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR") case ret == C.TSS_E_DAA_ISSUER_KEY_ERROR: return errors.New("TSS_E_DAA_ISSUER_KEY_ERROR") case ret == C.TSS_E_DAA_PSEUDONYM_ERROR: return errors.New("TSS_E_DAA_PSEUDONYM_ERROR") case ret == C.TSS_E_INVALID_RESOURCE: return errors.New("TSS_E_INVALID_RESOURCE") case ret == C.TSS_E_NV_AREA_EXIST: return errors.New("TSS_E_NV_AREA_EXIST") case ret == C.TSS_E_NV_AREA_NOT_EXIST: return errors.New("TSS_E_NV_AREA_NOT_EXIST") case ret == C.TSS_E_TSP_TRANS_AUTHFAIL: return errors.New("TSS_E_TSP_TRANS_AUTHFAIL") case ret == C.TSS_E_TSP_TRANS_AUTHREQUIRED: return errors.New("TSS_E_TSP_TRANS_AUTHREQUIRED") case ret == C.TSS_E_TSP_TRANS_NOTEXCLUSIVE: return errors.New("TSS_E_TSP_TRANS_NOTEXCLUSIVE") case ret == C.TSS_E_TSP_TRANS_FAIL: return errors.New("TSS_E_TSP_TRANS_FAIL") case ret == C.TSS_E_TSP_TRANS_NO_PUBKEY: return errors.New("TSS_E_TSP_TRANS_NO_PUBKEY") case ret == C.TSS_E_NO_ACTIVE_COUNTER: return errors.New("TSS_E_NO_ACTIVE_COUNTER") } return fmt.Errorf("Unknown TSS error: %x", ret) } switch { case ret == C.TPM_E_NON_FATAL: return errors.New("TPM_E_NON_FATAL") case ret == C.TPM_E_AUTHFAIL: return errors.New("TPM_E_AUTHFAIL") case ret == C.TPM_E_BADINDEX: return errors.New("TPM_E_BADINDEX") case ret == C.TPM_E_BAD_PARAMETER: return errors.New("TPM_E_BAD_PARAMETER") case ret == C.TPM_E_AUDITFAILURE: return errors.New("TPM_E_AUDITFAILURE") case ret == C.TPM_E_CLEAR_DISABLED: return errors.New("TPM_E_CLEAR_DISABLED") case ret == C.TPM_E_DEACTIVATED: return errors.New("TPM_E_DEACTIVATED") case ret == C.TPM_E_DISABLED: return errors.New("TPM_E_DISABLED") case ret == C.TPM_E_DISABLED_CMD: return errors.New("TPM_E_DISABLED_CMD") case ret == C.TPM_E_FAIL: return errors.New("TPM_E_FAIL") case ret == C.TPM_E_BAD_ORDINAL: return errors.New("TPM_E_BAD_ORDINAL") case ret == C.TPM_E_INSTALL_DISABLED: return errors.New("TPM_E_INSTALL_DISABLED") case ret == C.TPM_E_INVALID_KEYHANDLE: return errors.New("TPM_E_INVALID_KEYHANDLE") case ret == C.TPM_E_KEYNOTFOUND: return errors.New("TPM_E_KEYNOTFOUND") case ret == C.TPM_E_INAPPROPRIATE_ENC: return errors.New("TPM_E_INAPPROPRIATE_ENC") case ret == C.TPM_E_MIGRATEFAIL: return errors.New("TPM_E_MIGRATEFAIL") case ret == C.TPM_E_INVALID_PCR_INFO: return errors.New("TPM_E_INVALID_PCR_INFO") case ret == C.TPM_E_NOSPACE: return errors.New("TPM_E_NOSPACE") case ret == C.TPM_E_NOSRK: return errors.New("TPM_E_NOSRK") case ret == C.TPM_E_NOTSEALED_BLOB: return errors.New("TPM_E_NOTSEALED_BLOB") case ret == C.TPM_E_OWNER_SET: return errors.New("TPM_E_OWNER_SET") case ret == C.TPM_E_RESOURCES: return errors.New("TPM_E_RESOURCES") case ret == C.TPM_E_SHORTRANDOM: return errors.New("TPM_E_SHORTRANDOM") case ret == C.TPM_E_SIZE: return errors.New("TPM_E_SIZE") case ret == C.TPM_E_WRONGPCRVAL: return errors.New("TPM_E_WRONGPCRVAL") case ret == C.TPM_E_BAD_PARAM_SIZE: return errors.New("TPM_E_BAD_PARAM_SIZE") case ret == C.TPM_E_SHA_THREAD: return errors.New("TPM_E_SHA_THREAD") case ret == C.TPM_E_SHA_ERROR: return errors.New("TPM_E_SHA_ERROR") case ret == C.TPM_E_FAILEDSELFTEST: return errors.New("TPM_E_FAILEDSELFTEST") case ret == C.TPM_E_AUTH2FAIL: return errors.New("TPM_E_AUTH2FAIL") case ret == C.TPM_E_BADTAG: return errors.New("TPM_E_BADTAG") case ret == C.TPM_E_IOERROR: return errors.New("TPM_E_IOERROR") case ret == C.TPM_E_ENCRYPT_ERROR: return errors.New("TPM_E_ENCRYPT_ERROR") case ret == C.TPM_E_DECRYPT_ERROR: return errors.New("TPM_E_DECRYPT_ERROR") case ret == C.TPM_E_INVALID_AUTHHANDLE: return errors.New("TPM_E_INVALID_AUTHHANDLE") case ret == C.TPM_E_NO_ENDORSEMENT: return errors.New("TPM_E_NO_ENDORSEMENT") case ret == C.TPM_E_INVALID_KEYUSAGE: return errors.New("TPM_E_INVALID_KEYUSAGE") case ret == C.TPM_E_WRONG_ENTITYTYPE: return errors.New("TPM_E_WRONG_ENTITYTYPE") case ret == C.TPM_E_INVALID_POSTINIT: return errors.New("TPM_E_INVALID_POSTINIT") case ret == C.TPM_E_INAPPROPRIATE_SIG: return errors.New("TPM_E_INAPPROPRIATE_SIG") case ret == C.TPM_E_BAD_KEY_PROPERTY: return errors.New("TPM_E_BAD_KEY_PROPERTY") case ret == C.TPM_E_BAD_MIGRATION: return errors.New("TPM_E_BAD_MIGRATION") case ret == C.TPM_E_BAD_SCHEME: return errors.New("TPM_E_BAD_SCHEME") case ret == C.TPM_E_BAD_DATASIZE: return errors.New("TPM_E_BAD_DATASIZE") case ret == C.TPM_E_BAD_MODE: return errors.New("TPM_E_BAD_MODE") case ret == C.TPM_E_BAD_PRESENCE: return errors.New("TPM_E_BAD_PRESENCE") case ret == C.TPM_E_BAD_VERSION: return errors.New("TPM_E_BAD_VERSION") case ret == C.TPM_E_NO_WRAP_TRANSPORT: return errors.New("TPM_E_NO_WRAP_TRANSPORT") case ret == C.TPM_E_AUDITFAIL_UNSUCCESSFUL: return errors.New("TPM_E_AUDITFAIL_UNSUCCESSFUL") case ret == C.TPM_E_AUDITFAIL_SUCCESSFUL: return errors.New("TPM_E_AUDITFAIL_SUCCESSFUL") case ret == C.TPM_E_NOTRESETABLE: return errors.New("TPM_E_NOTRESETABLE") case ret == C.TPM_E_NOTLOCAL: return errors.New("TPM_E_NOTLOCAL") case ret == C.TPM_E_BAD_TYPE: return errors.New("TPM_E_BAD_TYPE") case ret == C.TPM_E_INVALID_RESOURCE: return errors.New("TPM_E_INVALID_RESOURCE") case ret == C.TPM_E_NOTFIPS: return errors.New("TPM_E_NOTFIPS") case ret == C.TPM_E_INVALID_FAMILY: return errors.New("TPM_E_INVALID_FAMILY") case ret == C.TPM_E_NO_NV_PERMISSION: return errors.New("TPM_E_NO_NV_PERMISSION") case ret == C.TPM_E_REQUIRES_SIGN: return errors.New("TPM_E_REQUIRES_SIGN") case ret == C.TPM_E_KEY_NOTSUPPORTED: return errors.New("TPM_E_KEY_NOTSUPPORTED") case ret == C.TPM_E_AUTH_CONFLICT: return errors.New("TPM_E_AUTH_CONFLICT") case ret == C.TPM_E_AREA_LOCKED: return errors.New("TPM_E_AREA_LOCKED") case ret == C.TPM_E_BAD_LOCALITY: return errors.New("TPM_E_BAD_LOCALITY") case ret == C.TPM_E_READ_ONLY: return errors.New("TPM_E_READ_ONLY") case ret == C.TPM_E_PER_NOWRITE: return errors.New("TPM_E_PER_NOWRITE") case ret == C.TPM_E_FAMILYCOUNT: return errors.New("TPM_E_FAMILYCOUNT") case ret == C.TPM_E_WRITE_LOCKED: return errors.New("TPM_E_WRITE_LOCKED") case ret == C.TPM_E_BAD_ATTRIBUTES: return errors.New("TPM_E_BAD_ATTRIBUTES") case ret == C.TPM_E_INVALID_STRUCTURE: return errors.New("TPM_E_INVALID_STRUCTURE") case ret == C.TPM_E_KEY_OWNER_CONTROL: return errors.New("TPM_E_KEY_OWNER_CONTROL") case ret == C.TPM_E_BAD_COUNTER: return errors.New("TPM_E_BAD_COUNTER") case ret == C.TPM_E_NOT_FULLWRITE: return errors.New("TPM_E_NOT_FULLWRITE") case ret == C.TPM_E_CONTEXT_GAP: return errors.New("TPM_E_CONTEXT_GAP") case ret == C.TPM_E_MAXNVWRITES: return errors.New("TPM_E_MAXNVWRITES") case ret == C.TPM_E_NOOPERATOR: return errors.New("TPM_E_NOOPERATOR") case ret == C.TPM_E_RESOURCEMISSING: return errors.New("TPM_E_RESOURCEMISSING") case ret == C.TPM_E_DELEGATE_LOCK: return errors.New("TPM_E_DELEGATE_LOCK") case ret == C.TPM_E_DELEGATE_FAMILY: return errors.New("TPM_E_DELEGATE_FAMILY") case ret == C.TPM_E_DELEGATE_ADMIN: return errors.New("TPM_E_DELEGATE_ADMIN") case ret == C.TPM_E_TRANSPORT_NOTEXCLUSIVE: return errors.New("TPM_E_TRANSPORT_NOTEXCLUSIVE") case ret == C.TPM_E_OWNER_CONTROL: return errors.New("TPM_E_OWNER_CONTROL") case ret == C.TPM_E_DAA_RESOURCES: return errors.New("TPM_E_DAA_RESOURCES") case ret == C.TPM_E_DAA_INPUT_DATA0: return errors.New("TPM_E_DAA_INPUT_DATA0") case ret == C.TPM_E_DAA_INPUT_DATA1: return errors.New("TPM_E_DAA_INPUT_DATA1") case ret == C.TPM_E_DAA_ISSUER_SETTINGS: return errors.New("TPM_E_DAA_ISSUER_SETTINGS") case ret == C.TPM_E_DAA_TPM_SETTINGS: return errors.New("TPM_E_DAA_TPM_SETTINGS") case ret == C.TPM_E_DAA_STAGE: return errors.New("TPM_E_DAA_STAGE") case ret == C.TPM_E_DAA_ISSUER_VALIDITY: return errors.New("TPM_E_DAA_ISSUER_VALIDITY") case ret == C.TPM_E_DAA_WRONG_W: return errors.New("TPM_E_DAA_WRONG_W") case ret == C.TPM_E_BAD_HANDLE: return errors.New("TPM_E_BAD_HANDLE") case ret == C.TPM_E_BAD_DELEGATE: return errors.New("TPM_E_BAD_DELEGATE") case ret == C.TPM_E_BADCONTEXT: return errors.New("TPM_E_BADCONTEXT") case ret == C.TPM_E_TOOMANYCONTEXTS: return errors.New("TPM_E_TOOMANYCONTEXTS") case ret == C.TPM_E_MA_TICKET_SIGNATURE: return errors.New("TPM_E_MA_TICKET_SIGNATURE") case ret == C.TPM_E_MA_DESTINATION: return errors.New("TPM_E_MA_DESTINATION") case ret == C.TPM_E_MA_SOURCE: return errors.New("TPM_E_MA_SOURCE") case ret == C.TPM_E_MA_AUTHORITY: return errors.New("TPM_E_MA_AUTHORITY") case ret == C.TPM_E_PERMANENTEK: return errors.New("TPM_E_PERMANENTEK") case ret == C.TPM_E_BAD_SIGNATURE: return errors.New("TPM_E_BAD_SIGNATURE") case ret == C.TPM_E_NOCONTEXTSPACE: return errors.New("TPM_E_NOCONTEXTSPACE") case ret == C.TPM_E_RETRY: return errors.New("TPM_E_RETRY") case ret == C.TPM_E_NEEDS_SELFTEST: return errors.New("TPM_E_NEEDS_SELFTEST") case ret == C.TPM_E_DOING_SELFTEST: return errors.New("TPM_E_DOING_SELFTEST") case ret == C.TPM_E_DEFEND_LOCK_RUNNING: return errors.New("TPM_E_DEFEND_LOCK_RUNNING") } return fmt.Errorf("Unknown error: %x", ret) } var TSS_UUID_SRK = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 1}, } var TSS_UUID_SK = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 2}, } var TSS_UUID_RK = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 3}, } var TSS_UUID_CRK = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 8}, } var TSS_UUID_USK1 = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 4}, } var TSS_UUID_USK2 = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 5}, } var TSS_UUID_USK3 = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 6}, } var TSS_UUID_USK4 = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 7}, } var TSS_UUID_USK5 = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 9}, } var TSS_UUID_USK6 = C.TSS_UUID{ ulTimeLow: 0, usTimeMid: 0, usTimeHigh: 0, bClockSeqHigh: 0, bClockSeqLow: 0, rgbNode: [6]C.BYTE{0, 0, 0, 0, 0, 10}, } go-tspi-0.3.0/tspiconst/000077500000000000000000000000001406764634500151415ustar00rootroot00000000000000go-tspi-0.3.0/tspiconst/tspiconst.go000066400000000000000000001042471406764634500175260ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 tspiconst const ( TSS_OBJECT_TYPE_POLICY = 0x01 TSS_OBJECT_TYPE_RSAKEY = 0x02 TSS_OBJECT_TYPE_ENCDATA = 0x03 TSS_OBJECT_TYPE_PCRS = 0x04 TSS_OBJECT_TYPE_HASH = 0x05 TSS_OBJECT_TYPE_DELFAMILY = 0x06 TSS_OBJECT_TYPE_NV = 0x07 TSS_OBJECT_TYPE_MIGDATA = 0x08 TSS_OBJECT_TYPE_DAA_CERTIFICATE = 0x09 TSS_OBJECT_TYPE_DAA_ISSUER_KEY = 0x0a TSS_OBJECT_TYPE_DAA_ARA_KEY = 0x0b TSS_KEY_NO_AUTHORIZATION = 0x00000000 TSS_KEY_AUTHORIZATION = 0x00000001 TSS_KEY_AUTHORIZATION_PRIV_USE_ONLY = 0x00000002 TSS_KEY_NON_VOLATILE = 0x00000000 TSS_KEY_VOLATILE = 0x00000004 TSS_KEY_NOT_MIGRATABLE = 0x00000000 TSS_KEY_MIGRATABLE = 0x00000008 TSS_KEY_TYPE_DEFAULT = 0x00000000 TSS_KEY_TYPE_SIGNING = 0x00000010 TSS_KEY_TYPE_STORAGE = 0x00000020 TSS_KEY_TYPE_IDENTITY = 0x00000030 TSS_KEY_TYPE_AUTHCHANGE = 0x00000040 TSS_KEY_TYPE_BIND = 0x00000050 TSS_KEY_TYPE_LEGACY = 0x00000060 TSS_KEY_TYPE_MIGRATE = 0x00000070 TSS_KEY_TYPE_BITMASK = 0x000000F0 TSS_KEY_SIZE_DEFAULT = 0x00000000 TSS_KEY_SIZE_512 = 0x00000100 TSS_KEY_SIZE_1024 = 0x00000200 TSS_KEY_SIZE_2048 = 0x00000300 TSS_KEY_SIZE_4096 = 0x00000400 TSS_KEY_SIZE_8192 = 0x00000500 TSS_KEY_SIZE_16384 = 0x00000600 TSS_KEY_SIZE_BITMASK = 0x00000F00 TSS_KEY_NOT_CERTIFIED_MIGRATABLE = 0x00000000 TSS_KEY_CERTIFIED_MIGRATABLE = 0x00001000 TSS_KEY_STRUCT_DEFAULT = 0x00000000 TSS_KEY_STRUCT_KEY = 0x00004000 TSS_KEY_STRUCT_KEY12 = 0x00008000 TSS_KEY_STRUCT_BITMASK = 0x0001C000 TSS_KEY_EMPTY_KEY = 0x00000000 TSS_KEY_TSP_SRK = 0x04000000 TSS_KEY_TEMPLATE_BITMASK = 0xFC000000 TSS_ENCDATA_SEAL = 0x00000001 TSS_ENCDATA_BIND = 0x00000002 TSS_ENCDATA_LEGACY = 0x00000003 TSS_HASH_DEFAULT = 0x00000000 TSS_HASH_SHA1 = 0x00000001 TSS_HASH_OTHER = 0xFFFFFFFF TSS_POLICY_USAGE = 0x00000001 TSS_POLICY_MIGRATION = 0x00000002 TSS_POLICY_OPERATOR = 0x00000003 TSS_PCRS_STRUCT_DEFAULT = 0x00000000 TSS_PCRS_STRUCT_INFO = 0x00000001 TSS_PCRS_STRUCT_INFO_LONG = 0x00000002 TSS_PCRS_STRUCT_INFO_SHORT = 0x00000003 TSS_TSPATTRIB_CONTEXT_SILENT_MODE = 0x00000001 TSS_TSPATTRIB_CONTEXT_MACHINE_NAME = 0x00000002 TSS_TSPATTRIB_CONTEXT_VERSION_MODE = 0x00000003 TSS_TSPATTRIB_CONTEXT_TRANSPORT = 0x00000004 TSS_TSPATTRIB_CONTEXT_CONNECTION_VERSION = 0x00000005 TSS_TSPATTRIB_SECRET_HASH_MODE = 0x00000006 TSS_TSPATTRIB_CONTEXTTRANS_CONTROL = 0x00000008 TSS_TSPATTRIB_CONTEXTTRANS_MODE = 0x00000010 TSS_TSPATTRIB_CONTEXT_NOT_SILENT = 0x00000000 TSS_TSPATTRIB_CONTEXT_SILENT = 0x00000001 TSS_TSPATTRIB_CONTEXT_VERSION_AUTO = 0x00000001 TSS_TSPATTRIB_CONTEXT_VERSION_V1_1 = 0x00000002 TSS_TSPATTRIB_CONTEXT_VERSION_V1_2 = 0x00000003 TSS_TSPATTRIB_DISABLE_TRANSPORT = 0x00000016 TSS_TSPATTRIB_ENABLE_TRANSPORT = 0x00000032 TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION = 0x00000000 TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION = 0x00000001 TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL = 0x00000002 TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE = 0x00000004 TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH = 0x00000008 TSS_CONNECTION_VERSION_1_1 = 0x00000001 TSS_CONNECTION_VERSION_1_2 = 0x00000002 TSS_TSPATTRIB_SECRET_HASH_MODE_POPUP = 0x00000001 TSS_TSPATTRIB_HASH_MODE_NOT_NULL = 0x00000000 TSS_TSPATTRIB_HASH_MODE_NULL = 0x00000001 TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY = 0x00000001 TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY = 0x00000002 TSS_TSPATTRIB_TPM_ORDINAL_AUDIT_STATUS = 0x00000003 TSS_TSPATTRIB_TPM_CREDENTIAL = 0x00001000 TPM_CAP_PROP_TPM_CLEAR_ORDINAL_AUDIT = 0x00000000 TPM_CAP_PROP_TPM_SET_ORDINAL_AUDIT = 0x00000001 TSS_TPMATTRIB_EKCERT = 0x00000001 TSS_TPMATTRIB_TPM_CC = 0x00000002 TSS_TPMATTRIB_PLATFORMCERT = 0x00000003 TSS_TPMATTRIB_PLATFORM_CC = 0x00000004 TSS_TSPATTRIB_POLICY_CALLBACK_HMAC = 0x00000080 TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC = 0x00000100 TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP = 0x00000180 TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM = 0x00000200 TSS_TSPATTRIB_POLICY_SECRET_LIFETIME = 0x00000280 TSS_TSPATTRIB_POLICY_POPUPSTRING = 0x00000300 TSS_TSPATTRIB_POLICY_CALLBACK_SEALX_MASK = 0x00000380 TSS_TSPATTRIB_POLICY_DELEGATION_INFO = 0x00000001 TSS_TSPATTRIB_POLICY_DELEGATION_PCR = 0x00000002 TSS_SECRET_LIFETIME_ALWAYS = 0x00000001 TSS_SECRET_LIFETIME_COUNTER = 0x00000002 TSS_SECRET_LIFETIME_TIMER = 0x00000003 TSS_TSPATTRIB_POLSECRET_LIFETIME_ALWAYS = TSS_SECRET_LIFETIME_ALWAYS TSS_TSPATTRIB_POLSECRET_LIFETIME_COUNTER = TSS_SECRET_LIFETIME_COUNTER TSS_TSPATTRIB_POLSECRET_LIFETIME_TIMER = TSS_SECRET_LIFETIME_TIMER TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS = TSS_SECRET_LIFETIME_ALWAYS TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER = TSS_SECRET_LIFETIME_COUNTER TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER = TSS_SECRET_LIFETIME_TIMER TSS_TSPATTRIB_POLDEL_TYPE = 0x00000001 TSS_TSPATTRIB_POLDEL_INDEX = 0x00000002 TSS_TSPATTRIB_POLDEL_PER1 = 0x00000003 TSS_TSPATTRIB_POLDEL_PER2 = 0x00000004 TSS_TSPATTRIB_POLDEL_LABEL = 0x00000005 TSS_TSPATTRIB_POLDEL_FAMILYID = 0x00000006 TSS_TSPATTRIB_POLDEL_VERCOUNT = 0x00000007 TSS_TSPATTRIB_POLDEL_OWNERBLOB = 0x00000008 TSS_TSPATTRIB_POLDEL_KEYBLOB = 0x00000009 TSS_TSPATTRIB_POLDELPCR_LOCALITY = 0x00000001 TSS_TSPATTRIB_POLDELPCR_DIGESTATRELEASE = 0x00000002 TSS_TSPATTRIB_POLDELPCR_SELECTION = 0x00000003 TSS_DELEGATIONTYPE_NONE = 0x00000001 TSS_DELEGATIONTYPE_OWNER = 0x00000002 TSS_DELEGATIONTYPE_KEY = 0x00000003 TSS_SECRET_MODE_NONE = 0x00000800 TSS_SECRET_MODE_SHA1 = 0x00001000 TSS_SECRET_MODE_PLAIN = 0x00001800 TSS_SECRET_MODE_POPUP = 0x00002000 TSS_SECRET_MODE_CALLBACK = 0x00002800 TSS_TSPATTRIB_ENCDATA_BLOB = 0x00000008 TSS_TSPATTRIB_ENCDATA_PCR = 0x00000010 TSS_TSPATTRIB_ENCDATA_PCR_LONG = 0x00000018 TSS_TSPATTRIB_ENCDATA_SEAL = 0x00000020 TSS_TSPATTRIB_ENCDATABLOB_BLOB = 0x00000001 TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATCREATION = 0x00000002 TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATRELEASE = 0x00000003 TSS_TSPATTRIB_ENCDATAPCR_SELECTION = 0x00000004 TSS_TSPATTRIB_ENCDATAPCR_DIGEST_RELEASE = TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATRELEASE TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATCREATION = 0x00000005 TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATRELEASE = 0x00000006 TSS_TSPATTRIB_ENCDATAPCRLONG_CREATION_SELECTION = 0x00000007 TSS_TSPATTRIB_ENCDATAPCRLONG_RELEASE_SELECTION = 0x00000008 TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATCREATION = 0x00000009 TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATRELEASE = 0x0000000A TSS_TSPATTRIB_ENCDATASEAL_PROTECT_MODE = 0x00000001 TSS_TSPATTRIB_ENCDATASEAL_NOPROTECT = 0x00000000 TSS_TSPATTRIB_ENCDATASEAL_PROTECT = 0x00000001 TSS_TSPATTRIB_ENCDATASEAL_NO_PROTECT = TSS_TSPATTRIB_ENCDATASEAL_NOPROTECT TSS_TSPATTRIB_NV_INDEX = 0x00000001 TSS_TSPATTRIB_NV_PERMISSIONS = 0x00000002 TSS_TSPATTRIB_NV_STATE = 0x00000003 TSS_TSPATTRIB_NV_DATASIZE = 0x00000004 TSS_TSPATTRIB_NV_PCR = 0x00000005 TSS_TSPATTRIB_NVSTATE_READSTCLEAR = 0x00100000 TSS_TSPATTRIB_NVSTATE_WRITESTCLEAR = 0x00200000 TSS_TSPATTRIB_NVSTATE_WRITEDEFINE = 0x00300000 TSS_TSPATTRIB_NVPCR_READPCRSELECTION = 0x01000000 TSS_TSPATTRIB_NVPCR_READDIGESTATRELEASE = 0x02000000 TSS_TSPATTRIB_NVPCR_READLOCALITYATRELEASE = 0x03000000 TSS_TSPATTRIB_NVPCR_WRITEPCRSELECTION = 0x04000000 TSS_TSPATTRIB_NVPCR_WRITEDIGESTATRELEASE = 0x05000000 TSS_TSPATTRIB_NVPCR_WRITELOCALITYATRELEASE = 0x06000000 TSS_NV_TPM = 0x80000000 TSS_NV_PLATFORM = 0x40000000 TSS_NV_USER = 0x20000000 TSS_NV_DEFINED = 0x10000000 TSS_NV_MASK_TPM = 0x80000000 TSS_NV_MASK_PLATFORM = 0x40000000 TSS_NV_MASK_USER = 0x20000000 TSS_NV_MASK_DEFINED = 0x10000000 TSS_NV_MASK_RESERVED = 0x0f000000 TSS_NV_MASK_PURVIEW = 0x00ff0000 TSS_NV_MASK_INDEX = 0x0000ffff TSS_NV_INDEX_SESSIONS = 0x00011101 TSS_MIGATTRIB_MIGRATIONBLOB = 0x00000010 TSS_MIGATTRIB_MIGRATIONTICKET = 0x00000020 TSS_MIGATTRIB_AUTHORITY_DATA = 0x00000030 TSS_MIGATTRIB_MIG_AUTH_DATA = 0x00000040 TSS_MIGATTRIB_TICKET_DATA = 0x00000050 TSS_MIGATTRIB_PAYLOAD_TYPE = 0x00000060 TSS_MIGATTRIB_MIGRATION_XOR_BLOB = 0x00000101 TSS_MIGATTRIB_MIGRATION_REWRAPPED_BLOB = 0x00000102 TSS_MIGATTRIB_MIG_MSALIST_PUBKEY_BLOB = 0x00000103 TSS_MIGATTRIB_MIG_AUTHORITY_PUBKEY_BLOB = 0x00000104 TSS_MIGATTRIB_MIG_DESTINATION_PUBKEY_BLOB = 0x00000105 TSS_MIGATTRIB_MIG_SOURCE_PUBKEY_BLOB = 0x00000106 TSS_MIGATTRIB_MIG_REWRAPPED_BLOB = TSS_MIGATTRIB_MIGRATION_REWRAPPED_BLOB TSS_MIGATTRIB_MIG_XOR_BLOB = TSS_MIGATTRIB_MIGRATION_XOR_BLOB TSS_MIGATTRIB_AUTHORITY_DIGEST = 0x00000301 TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC = 0x00000302 TSS_MIGATTRIB_AUTHORITY_MSALIST = 0x00000303 TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST = 0x00000401 TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST = 0x00000402 TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST = 0x00000403 TSS_MIGATTRIB_TICKET_SIG_DIGEST = 0x00000501 TSS_MIGATTRIB_TICKET_SIG_VALUE = 0x00000502 TSS_MIGATTRIB_TICKET_SIG_TICKET = 0x00000503 TSS_MIGATTRIB_TICKET_RESTRICT_TICKET = 0x00000504 TSS_MIGATTRIB_PT_MIGRATE_RESTRICTED = 0x00000601 TSS_MIGATTRIB_PT_MIGRATE_EXTERNAL = 0x00000602 TSS_TSPATTRIB_HASH_IDENTIFIER = 0x00001000 TSS_TSPATTRIB_ALG_IDENTIFIER = 0x00002000 TSS_TSPATTRIB_PCRS_INFO = 0x00000001 TSS_TSPATTRIB_PCRSINFO_PCRSTRUCT = 0x00000001 TSS_TSPATTRIB_DELFAMILY_STATE = 0x00000001 TSS_TSPATTRIB_DELFAMILY_INFO = 0x00000002 TSS_TSPATTRIB_DELFAMILYSTATE_LOCKED = 0x00000001 TSS_TSPATTRIB_DELFAMILYSTATE_ENABLED = 0x00000002 TSS_TSPATTRIB_DELFAMILYINFO_LABEL = 0x00000003 TSS_TSPATTRIB_DELFAMILYINFO_VERCOUNT = 0x00000004 TSS_TSPATTRIB_DELFAMILYINFO_FAMILYID = 0x00000005 TSS_DELEGATE_INCREMENTVERIFICATIONCOUNT = 1 TSS_DELEGATE_CACHEOWNERDELEGATION_OVERWRITEEXISTING = 1 TSS_TSPATTRIB_DAACRED_COMMIT = 0x00000001 TSS_TSPATTRIB_DAACRED_ATTRIB_GAMMAS = 0x00000002 TSS_TSPATTRIB_DAACRED_CREDENTIAL_BLOB = 0x00000003 TSS_TSPATTRIB_DAACRED_CALLBACK_SIGN = 0x00000004 TSS_TSPATTRIB_DAACRED_CALLBACK_VERIFYSIGNATURE = 0x00000005 TSS_TSPATTRIB_DAACOMMIT_NUMBER = 0x00000001 TSS_TSPATTRIB_DAACOMMIT_SELECTION = 0x00000002 TSS_TSPATTRIB_DAACOMMIT_COMMITMENTS = 0x00000003 TSS_TSPATTRIB_DAAATTRIBGAMMAS_BLOB = 0xffffffff TSS_TSPATTRIB_DAAISSUERKEY_BLOB = 0x00000001 TSS_TSPATTRIB_DAAISSUERKEY_PUBKEY = 0x00000002 TSS_TSPATTRIB_DAAISSUERKEYBLOB_PUBLIC_KEY = 0x00000001 TSS_TSPATTRIB_DAAISSUERKEYBLOB_SECRET_KEY = 0x00000002 TSS_TSPATTRIB_DAAISSUERKEYBLOB_KEYBLOB = 0x00000003 TSS_TSPATTRIB_DAAISSUERKEYBLOB_PROOF = 0x00000004 TSS_TSPATTRIB_DAAISSUERKEYPUBKEY_NUM_ATTRIBS = 0x00000001 TSS_TSPATTRIB_DAAISSUERKEYPUBKEY_NUM_PLATFORM_ATTRIBS = 0x00000002 TSS_TSPATTRIB_DAAISSUERKEYPUBKEY_NUM_ISSUER_ATTRIBS = 0x00000003 TSS_TSPATTRIB_DAAARAKEY_BLOB = 0x00000001 TSS_TSPATTRIB_DAAARAKEYBLOB_PUBLIC_KEY = 0x00000001 TSS_TSPATTRIB_DAAARAKEYBLOB_SECRET_KEY = 0x00000002 TSS_TSPATTRIB_DAAARAKEYBLOB_KEYBLOB = 0x00000003 TSS_FLAG_DAA_PSEUDONYM_PLAIN = 0x00000000 TSS_FLAG_DAA_PSEUDONYM_ENCRYPTED = 0x00000001 TSS_TSPATTRIB_KEY_BLOB = 0x00000040 TSS_TSPATTRIB_KEY_INFO = 0x00000080 TSS_TSPATTRIB_KEY_UUID = 0x000000C0 TSS_TSPATTRIB_KEY_PCR = 0x00000100 TSS_TSPATTRIB_RSAKEY_INFO = 0x00000140 TSS_TSPATTRIB_KEY_REGISTER = 0x00000180 TSS_TSPATTRIB_KEY_PCR_LONG = 0x000001c0 TSS_TSPATTRIB_KEY_CONTROLBIT = 0x00000200 TSS_TSPATTRIB_KEY_CMKINFO = 0x00000400 TSS_TSPATTRIB_KEYBLOB_BLOB = 0x00000008 TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY = 0x00000010 TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY = 0x00000028 TSS_TSPATTRIB_KEYINFO_SIZE = 0x00000080 TSS_TSPATTRIB_KEYINFO_USAGE = 0x00000100 TSS_TSPATTRIB_KEYINFO_KEYFLAGS = 0x00000180 TSS_TSPATTRIB_KEYINFO_AUTHUSAGE = 0x00000200 TSS_TSPATTRIB_KEYINFO_ALGORITHM = 0x00000280 TSS_TSPATTRIB_KEYINFO_SIGSCHEME = 0x00000300 TSS_TSPATTRIB_KEYINFO_ENCSCHEME = 0x00000380 TSS_TSPATTRIB_KEYINFO_MIGRATABLE = 0x00000400 TSS_TSPATTRIB_KEYINFO_REDIRECTED = 0x00000480 TSS_TSPATTRIB_KEYINFO_VOLATILE = 0x00000500 TSS_TSPATTRIB_KEYINFO_AUTHDATAUSAGE = 0x00000580 TSS_TSPATTRIB_KEYINFO_VERSION = 0x00000600 TSS_TSPATTRIB_KEYINFO_CMK = 0x00000680 TSS_TSPATTRIB_KEYINFO_KEYSTRUCT = 0x00000700 TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT = 0x00000780 TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT = 0x00001000 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS = 0x00002000 TSS_TSPATTRIB_KEYINFO_RSA_KEYSIZE = 0x00003000 TSS_TSPATTRIB_KEYINFO_RSA_PRIMES = 0x00004000 TSS_TSPATTRIB_KEYPCR_DIGEST_ATCREATION = 0x00008000 TSS_TSPATTRIB_KEYPCR_DIGEST_ATRELEASE = 0x00010000 TSS_TSPATTRIB_KEYPCR_SELECTION = 0x00018000 TSS_TSPATTRIB_KEYREGISTER_USER = 0x02000000 TSS_TSPATTRIB_KEYREGISTER_SYSTEM = 0x04000000 TSS_TSPATTRIB_KEYREGISTER_NO = 0x06000000 TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATCREATION = 0x00040000 TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATRELEASE = 0x00080000 TSS_TSPATTRIB_KEYPCRLONG_CREATION_SELECTION = 0x000C0000 TSS_TSPATTRIB_KEYPCRLONG_RELEASE_SELECTION = 0x00100000 TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATCREATION = 0x00140000 TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATRELEASE = 0x00180000 TSS_TSPATTRIB_KEYINFO_CMK_MA_APPROVAL = 0x00000010 TSS_TSPATTRIB_KEYINFO_CMK_MA_DIGEST = 0x00000020 TSS_KEY_SIZEVAL_512BIT = 0x0200 TSS_KEY_SIZEVAL_1024BIT = 0x0400 TSS_KEY_SIZEVAL_2048BIT = 0x0800 TSS_KEY_SIZEVAL_4096BIT = 0x1000 TSS_KEY_SIZEVAL_8192BIT = 0x2000 TSS_KEY_SIZEVAL_16384BIT = 0x4000 TSS_KEYUSAGE_BIND = 0x00 TSS_KEYUSAGE_IDENTITY = 0x01 TSS_KEYUSAGE_LEGACY = 0x02 TSS_KEYUSAGE_SIGN = 0x03 TSS_KEYUSAGE_STORAGE = 0x04 TSS_KEYUSAGE_AUTHCHANGE = 0x05 TSS_KEYUSAGE_MIGRATE = 0x06 TSS_KEYFLAG_REDIRECTION = 0x00000001 TSS_KEYFLAG_MIGRATABLE = 0x00000002 TSS_KEYFLAG_VOLATILEKEY = 0x00000004 TSS_KEYFLAG_CERTIFIED_MIGRATABLE = 0x00000008 TSS_ALG_RSA = 0x20 TSS_ALG_DES = 0x21 TSS_ALG_3DES = 0x22 TSS_ALG_SHA = 0x23 TSS_ALG_HMAC = 0x24 TSS_ALG_AES128 = 0x25 TSS_ALG_AES192 = 0x26 TSS_ALG_AES256 = 0x27 TSS_ALG_XOR = 0x28 TSS_ALG_MGF1 = 0x29 TSS_ALG_AES = TSS_ALG_AES128 TSS_ALG_DEFAULT = 0xfe TSS_ALG_DEFAULT_SIZE = 0xff TSS_SS_NONE = 0x10 TSS_SS_RSASSAPKCS1V15_SHA1 = 0x11 TSS_SS_RSASSAPKCS1V15_DER = 0x12 TSS_SS_RSASSAPKCS1V15_INFO = 0x13 TSS_ES_NONE = 0x10 TSS_ES_RSAESPKCSV15 = 0x11 TSS_ES_RSAESOAEP_SHA1_MGF1 = 0x12 TSS_ES_SYM_CNT = 0x13 TSS_ES_SYM_OFB = 0x14 TSS_ES_SYM_CBC_PKCS5PAD = 0x15 TSS_PS_TYPE_USER = 1 TSS_PS_TYPE_SYSTEM = 2 TSS_MS_MIGRATE = 0x20 TSS_MS_REWRAP = 0x21 TSS_MS_MAINT = 0x22 TSS_MS_RESTRICT_MIGRATE = 0x23 TSS_MS_RESTRICT_APPROVE_DOUBLE = 0x24 TSS_MS_RESTRICT_MIGRATE_EXTERNAL = 0x25 TSS_KEYAUTH_AUTH_NEVER = 0x10 TSS_KEYAUTH_AUTH_ALWAYS = 0x11 TSS_KEYAUTH_AUTH_PRIV_USE_ONLY = 0x12 TSS_TPMSTATUS_DISABLEOWNERCLEAR = 0x00000001 TSS_TPMSTATUS_DISABLEFORCECLEAR = 0x00000002 TSS_TPMSTATUS_DISABLED = 0x00000003 TSS_TPMSTATUS_DEACTIVATED = 0x00000004 TSS_TPMSTATUS_OWNERSETDISABLE = 0x00000005 TSS_TPMSTATUS_SETOWNERINSTALL = 0x00000006 TSS_TPMSTATUS_DISABLEPUBEKREAD = 0x00000007 TSS_TPMSTATUS_ALLOWMAINTENANCE = 0x00000008 TSS_TPMSTATUS_PHYSPRES_LIFETIMELOCK = 0x00000009 TSS_TPMSTATUS_PHYSPRES_HWENABLE = 0x0000000A TSS_TPMSTATUS_PHYSPRES_CMDENABLE = 0x0000000B TSS_TPMSTATUS_PHYSPRES_LOCK = 0x0000000C TSS_TPMSTATUS_PHYSPRESENCE = 0x0000000D TSS_TPMSTATUS_PHYSICALDISABLE = 0x0000000E TSS_TPMSTATUS_CEKP_USED = 0x0000000F TSS_TPMSTATUS_PHYSICALSETDEACTIVATED = 0x00000010 TSS_TPMSTATUS_SETTEMPDEACTIVATED = 0x00000011 TSS_TPMSTATUS_POSTINITIALISE = 0x00000012 TSS_TPMSTATUS_TPMPOST = 0x00000013 TSS_TPMSTATUS_TPMPOSTLOCK = 0x00000014 TSS_TPMSTATUS_DISABLEPUBSRKREAD = 0x00000016 TSS_TPMSTATUS_MAINTENANCEUSED = 0x00000017 TSS_TPMSTATUS_OPERATORINSTALLED = 0x00000018 TSS_TPMSTATUS_OPERATOR_INSTALLED = TSS_TPMSTATUS_OPERATORINSTALLED TSS_TPMSTATUS_FIPS = 0x00000019 TSS_TPMSTATUS_ENABLEREVOKEEK = 0x0000001A TSS_TPMSTATUS_ENABLE_REVOKEEK = TSS_TPMSTATUS_ENABLEREVOKEEK TSS_TPMSTATUS_NV_LOCK = 0x0000001B TSS_TPMSTATUS_TPM_ESTABLISHED = 0x0000001C TSS_TPMSTATUS_RESETLOCK = 0x0000001D TSS_TPMSTATUS_DISABLE_FULL_DA_LOGIC_INFO = 0x0000001D TSS_TPMCAP_ORD = 0x10 TSS_TPMCAP_ALG = 0x11 TSS_TPMCAP_FLAG = 0x12 TSS_TPMCAP_PROPERTY = 0x13 TSS_TPMCAP_VERSION = 0x14 TSS_TPMCAP_VERSION_VAL = 0x15 TSS_TPMCAP_NV_LIST = 0x16 TSS_TPMCAP_NV_INDEX = 0x17 TSS_TPMCAP_MFR = 0x18 TSS_TPMCAP_SYM_MODE = 0x19 TSS_TPMCAP_HANDLE = 0x1a TSS_TPMCAP_TRANS_ES = 0x1b TSS_TPMCAP_AUTH_ENCRYPT = 0x1c TSS_TPMCAP_SET_PERM_FLAGS = 0x1d TSS_TPMCAP_SET_VENDOR = 0x1e TSS_TPMCAP_DA_LOGIC = 0x1f TSS_TPMCAP_PROP_PCR = 0x10 TSS_TPMCAP_PROP_DIR = 0x11 TSS_TPMCAP_PROP_MANUFACTURER = 0x12 TSS_TPMCAP_PROP_SLOTS = 0x13 TSS_TPMCAP_PROP_KEYS = TSS_TPMCAP_PROP_SLOTS TSS_TPMCAP_PROP_FAMILYROWS = 0x14 TSS_TPMCAP_PROP_DELEGATEROWS = 0x15 TSS_TPMCAP_PROP_OWNER = 0x16 TSS_TPMCAP_PROP_MAXKEYS = 0x18 TSS_TPMCAP_PROP_AUTHSESSIONS = 0x19 TSS_TPMCAP_PROP_MAXAUTHSESSIONS = 0x1a TSS_TPMCAP_PROP_TRANSESSIONS = 0x1b TSS_TPMCAP_PROP_MAXTRANSESSIONS = 0x1c TSS_TPMCAP_PROP_SESSIONS = 0x1d TSS_TPMCAP_PROP_MAXSESSIONS = 0x1e TSS_TPMCAP_PROP_CONTEXTS = 0x1f TSS_TPMCAP_PROP_MAXCONTEXTS = 0x20 TSS_TPMCAP_PROP_DAASESSIONS = 0x21 TSS_TPMCAP_PROP_MAXDAASESSIONS = 0x22 TSS_TPMCAP_PROP_DAA_INTERRUPT = 0x23 TSS_TPMCAP_PROP_COUNTERS = 0x24 TSS_TPMCAP_PROP_MAXCOUNTERS = 0x25 TSS_TPMCAP_PROP_ACTIVECOUNTER = 0x26 TSS_TPMCAP_PROP_MIN_COUNTER = 0x27 TSS_TPMCAP_PROP_TISTIMEOUTS = 0x28 TSS_TPMCAP_PROP_STARTUPEFFECTS = 0x29 TSS_TPMCAP_PROP_MAXCONTEXTCOUNTDIST = 0x2a TSS_TPMCAP_PROP_CMKRESTRICTION = 0x2b TSS_TPMCAP_PROP_DURATION = 0x2c TSS_TPMCAP_PROP_MAXNVAVAILABLE = 0x2d TSS_TPMCAP_PROP_INPUTBUFFERSIZE = 0x2e TSS_TPMCAP_PROP_REVISION = 0x2f TSS_TPMCAP_PROP_LOCALITIES_AVAIL = 0x32 TSS_RT_KEY = 0x00000010 TSS_RT_AUTH = 0x00000020 TSS_RT_TRANS = 0x00000030 TSS_RT_COUNTER = 0x00000040 TSS_TCSCAP_ALG = 0x00000001 TSS_TCSCAP_VERSION = 0x00000002 TSS_TCSCAP_CACHING = 0x00000003 TSS_TCSCAP_PERSSTORAGE = 0x00000004 TSS_TCSCAP_MANUFACTURER = 0x00000005 TSS_TCSCAP_PLATFORM_CLASS = 0x00000006 TSS_TCSCAP_TRANSPORT = 0x00000007 TSS_TCSCAP_PLATFORM_INFO = 0x00000008 TSS_TCSCAP_PROP_KEYCACHE = 0x00000100 TSS_TCSCAP_PROP_AUTHCACHE = 0x00000101 TSS_TCSCAP_PROP_MANUFACTURER_STR = 0x00000102 TSS_TCSCAP_PROP_MANUFACTURER_ID = 0x00000103 TSS_TCSCAP_PLATFORM_VERSION = 0x00001100 TSS_TCSCAP_PLATFORM_TYPE = 0x00001101 TSS_TCSCAP_TRANS_EXCLUSIVE = 0x00002100 TSS_TCSCAP_PROP_HOST_PLATFORM = 0x00003001 TSS_TCSCAP_PROP_ALL_PLATFORMS = 0x00003002 TSS_TSPCAP_ALG = 0x00000010 TSS_TSPCAP_VERSION = 0x00000011 TSS_TSPCAP_PERSSTORAGE = 0x00000012 TSS_TSPCAP_MANUFACTURER = 0x00000013 TSS_TSPCAP_RETURNVALUE_INFO = 0x00000015 TSS_TSPCAP_PLATFORM_INFO = 0x00000016 TSS_TSPCAP_PROP_MANUFACTURER_STR = 0x00000102 TSS_TSPCAP_PROP_MANUFACTURER_ID = 0x00000103 TSS_TSPCAP_PLATFORM_TYPE = 0x00000201 TSS_TSPCAP_PLATFORM_VERSION = 0x00000202 TSS_TSPCAP_PROP_RETURNVALUE_INFO = 0x00000201 TSS_EV_CODE_CERT = 0x00000001 TSS_EV_CODE_NOCERT = 0x00000002 TSS_EV_XML_CONFIG = 0x00000003 TSS_EV_NO_ACTION = 0x00000004 TSS_EV_SEPARATOR = 0x00000005 TSS_EV_ACTION = 0x00000006 TSS_EV_PLATFORM_SPECIFIC = 0x00000007 TSS_TSPCAP_RANDOMLIMIT = 0x00001000 TSS_PCRS_DIRECTION_CREATION = 1 TSS_PCRS_DIRECTION_RELEASE = 2 TSS_BLOB_STRUCT_VERSION = 0x01 TSS_BLOB_TYPE_KEY = 0x01 TSS_BLOB_TYPE_PUBKEY = 0x02 TSS_BLOB_TYPE_MIGKEY = 0x03 TSS_BLOB_TYPE_SEALEDDATA = 0x04 TSS_BLOB_TYPE_BOUNDDATA = 0x05 TSS_BLOB_TYPE_MIGTICKET = 0x06 TSS_BLOB_TYPE_PRIVATEKEY = 0x07 TSS_BLOB_TYPE_PRIVATEKEY_MOD1 = 0x08 TSS_BLOB_TYPE_RANDOM_XOR = 0x09 TSS_BLOB_TYPE_CERTIFY_INFO = 0x0A TSS_BLOB_TYPE_KEY_1_2 = 0x0B TSS_BLOB_TYPE_CERTIFY_INFO_2 = 0x0C TSS_BLOB_TYPE_CMK_MIG_KEY = 0x0D TSS_BLOB_TYPE_CMK_BYTE_STREAM = 0x0E TSS_CMK_DELEGATE_SIGNING = 1 << 31 TSS_CMK_DELEGATE_STORAGE = 1 << 30 TSS_CMK_DELEGATE_BIND = 1 << 29 TSS_CMK_DELEGATE_LEGACY = 1 << 28 TSS_CMK_DELEGATE_MIGRATE = 1 << 27 TSS_DAA_LENGTH_N = 256 TSS_DAA_LENGTH_F = 13 TSS_DAA_LENGTH_E = 46 TSS_DAA_LENGTH_E_PRIME = 15 TSS_DAA_LENGTH_V = 317 TSS_DAA_LENGTH_SAFETY = 10 TSS_DAA_LENGTH_HASH = 20 TSS_DAA_LENGTH_S = 128 TSS_DAA_LENGTH_GAMMA = 204 TSS_DAA_LENGTH_RHO = 26 TSS_DAA_LENGTH_MFG1_GAMMA = 214 TSS_DAA_LENGTH_MGF1_AR = 25 TPM_ALG_RSA = 0x00000001 TPM_ALG_DES = 0x00000002 TPM_ALG_3DES = 0x00000003 TPM_ALG_SHA = 0x00000004 TPM_ALG_HMAC = 0x00000005 TPM_ALG_AES = 0x00000006 TPM_ALG_AES128 = TPM_ALG_AES TPM_ALG_MGF1 = 0x00000007 TPM_ALG_AES192 = 0x00000008 TPM_ALG_AES256 = 0x00000009 TPM_ALG_XOR = 0x0000000A TPM_SS_NONE = 0x0001 TPM_SS_RSASSAPKCS1v15_SHA1 = 0x0002 TPM_SS_RSASSAPKCS1v15_DER = 0x0003 TPM_SS_RSASSAPKCS1v15_INFO = 0x0004 TPM_ES_NONE = 0x0001 TPM_ES_RSAESPKCSv15 = 0x0002 TPM_ES_RSAESOAEP_SHA1_MGF1 = 0x0003 TPM_ES_SYM_CNT = 0x0004 TPM_ES_SYM_CTR = TPM_ES_SYM_CNT TPM_ES_SYM_OFB = 0x0005 TPM_ES_SYM_CBC_PKCS5PAD = 0x00FF ) // Log represents an entry from the TSS event log. Pcr is the register that // was extended by the event. Eventtype is the type of the event. PcrValue // is the value that was hashed into the TPM. Event is the raw event data. type Log struct { Pcr int32 Eventtype int32 PcrValue [20]byte Event []byte } go-tspi-0.3.0/verification/000077500000000000000000000000001406764634500155755ustar00rootroot00000000000000go-tspi-0.3.0/verification/verification.go000066400000000000000000000753021406764634500206150ustar00rootroot00000000000000// Copyright 2015 CoreOS, Inc. // // 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 verification import ( "bytes" "crypto" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/rsa" "crypto/sha1" "encoding/binary" "encoding/pem" "errors" "fmt" "math/big" "github.com/google/certificate-transparency-go/x509" "github.com/google/go-tspi/tspiconst" ) func pad(plaintext []byte, bsize int) ([]byte, error) { if bsize >= 256 { return nil, errors.New("bsize must be < 256") } pad := bsize - (len(plaintext) % bsize) if pad == 0 { pad = bsize } for i := 0; i < pad; i++ { plaintext = append(plaintext, byte(pad)) } return plaintext, nil } // GenerateChallengeEx takes the EK (rsa.PublicKey), the public half of // the AIK to be challenged and a secret. It then symmetrically encrypts the // secret with a randomly generated AES key and Asymmetrically encrypts the // AES key with the public half of the EK. These can then be provided to the // TPM in order to ensure that the AIK is under the control of the TPM. It // returns the asymmetrically and symmetrically encrypted data, along with // any error. func GenerateChallengeEx(pubkey *rsa.PublicKey, aikpub []byte, secret []byte) (asymenc []byte, symenc []byte, err error) { aeskey := make([]byte, 16) iv := make([]byte, 16) _, err = rand.Read(aeskey) if err != nil { return nil, nil, err } _, err = rand.Read(iv) if err != nil { return nil, nil, err } asymplain := []byte{0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0x00, 0x10} asymplain = append(asymplain, aeskey...) hash := sha1.Sum(aikpub) asymplain = append(asymplain, hash[:]...) label := []byte{'T', 'C', 'P', 'A'} asymenc, err = rsa.EncryptOAEP(sha1.New(), rand.Reader, pubkey, asymplain, label) block, err := aes.NewCipher(aeskey) if err != nil { return nil, nil, err } cbc := cipher.NewCBCEncrypter(block, iv) secret, err = pad(secret, len(iv)) if err != nil { return nil, nil, err } symenc = make([]byte, len(secret)) cbc.CryptBlocks(symenc, secret) symheader := new(bytes.Buffer) err = binary.Write(symheader, binary.BigEndian, (uint32)(len(symenc)+len(iv))) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint32)(tspiconst.TPM_ALG_AES)) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint16)(tspiconst.TPM_ES_SYM_CBC_PKCS5PAD)) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint16)(tspiconst.TPM_SS_NONE)) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint32)(12)) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint32)(128)) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint32)(len(iv))) if err != nil { return nil, nil, err } err = binary.Write(symheader, binary.BigEndian, (uint32)(0)) if err != nil { return nil, nil, err } header := make([]byte, 28) err = binary.Read(symheader, binary.BigEndian, &header) header = append(header, iv...) header = append(header, symenc...) symenc = header return asymenc, symenc, nil } // GenerateChallenge takes a copy of the EK certificate, the public half of // the AIK to be challenged and a secret. It then symmetrically encrypts the // secret with a randomly generated AES key and Asymmetrically encrypts the // AES key with the public half of the EK. These can then be provided to the // TPM in order to ensure that the AIK is under the control of the TPM. It // returns the asymmetrically and symmetrically encrypted data, along with // any error. func GenerateChallenge(ekcert []byte, aikpub []byte, secret []byte) (asymenc []byte, symenc []byte, err error) { /* * Some EK certificates use RSAES-OAEP public keys. * This is currently not supported by crypto/x509 but * we are working with them to find a solution. * https://github.com/golang/go/issues/30416 */ cert, err := x509.ParseCertificate(ekcert) if err != nil { return nil, nil, fmt.Errorf("ParseCertificate failed: %v", err) } pubkey := cert.PublicKey.(*rsa.PublicKey) return GenerateChallengeEx(pubkey, aikpub, secret) } // VerifyEKCert verifies that the provided EK certificate is signed by a // trusted manufacturer. func VerifyEKCert(ekcert []byte) error { trustedCerts := map[string]string{ "STM1": `-----BEGIN CERTIFICATE----- MIIDzDCCArSgAwIBAgIEAAAAATANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJD SDEeMBwGA1UEChMVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMRswGQYDVQQDExJTVE0g VFBNIEVLIFJvb3QgQ0EwHhcNMDkwNzI4MDAwMDAwWhcNMjkxMjMxMDAwMDAwWjBV MQswCQYDVQQGEwJDSDEeMBwGA1UEChMVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMSYw JAYDVQQDEx1TVE0gVFBNIEVLIEludGVybWVkaWF0ZSBDQSAwMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJQYnWO8iw955vWqakWNr3YyazQnNzqV97+l Qa+wUKMVY+lsyhAyOyXO31j4+clvsj6+JhNEwQtcnpkSc+TX60eZvLhgZPUgRVuK B9w4GUVyg/db593QUmP8K41Is8E+l32CQdcVh9go0toqf/oS/za1TDFHEHLlB4dC joKkfr3/hkGA9XJaoUopO2ELt4Otop12aw1BknoiTh1+YbzrZtAlIwK2TX99GW3S IjaCi+fLoXyK2Fmx8vKnr9JfNL888xK9BQfhZzKmbKm/eLD1e1CFRs1B3z2gd3ax pW5j1OIkSBMOIUeip5+7xvYo2gor5mxatB+rzSvrWup9AwIcymMCAwEAAaOBrjCB qzAdBgNVHQ4EFgQU88kVdKbnc/8TvwxrrXp7Zc8ceCAwHwYDVR0jBBgwFoAUb+bF bAe3bIsKgZKDXMtBHva00ScwRQYDVR0gAQH/BDswOTA3BgRVHSAAMC8wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cuc3QuY29tL1RQTS9yZXBvc2l0b3J5LzAOBgNVHQ8B Af8EBAMCAAQwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEA uZqViou3aZDGvaAn29gghOkj04SkEWViZR3dU3DGrA+5ZX+zr6kZduus3Hf0bVHT I318PZGTml1wm6faDRomE8bI5xADWhPiCQ1Gf7cFPiqaPkq7mgdC6SGlQtRAfoP8 ISUJlih0UtsqBWGql4lpk5G6YmvAezguWmMR0/O5Cx5w8YKfXkwAhegGmMGIoJFO oSzJrS7jK2GnGCuRG65OQVC5HiQY2fFF0JePLWG/D56djNxMbPNGTHF3+yBWg0DU 0xJKYKGFdjFcw0Wi0m2j49Pv3JD1f78c2Z3I/65pkklZGu4awnKQcHeGIbdYF0hQ LtDSBV4DR9q5GVxSR9JPgQ== -----END CERTIFICATE-----`, "STM2": `-----BEGIN CERTIFICATE----- MIIDzDCCArSgAwIBAgIEAAAAAzANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJD SDEeMBwGA1UEChMVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMRswGQYDVQQDExJTVE0g VFBNIEVLIFJvb3QgQ0EwHhcNMTEwMTIxMDAwMDAwWhcNMjkxMjMxMDAwMDAwWjBV MQswCQYDVQQGEwJDSDEeMBwGA1UEChMVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMSYw JAYDVQQDEx1TVE0gVFBNIEVLIEludGVybWVkaWF0ZSBDQSAwMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJO3ihn/uHgV3HrlPZpv8+1+xg9ccLf3pVXJ oT5n8PHHixN6ZRBmf/Ng85/ODZzxnotC64WD8GHMLyQ0Cna3MJF+MGJZ5R5JkuJR B4CtgTPwcTVZIsCuup0aDWnPzYqHwvfaiD2FD0aaxCnTKIjWU9OztTD2I61xW2LK EY4Vde+W3C7WZgS5TpqkbhJzy2NJj6oSMDKklfI3X8jVf7bngMcCR3X3NcIo349I Dt1r1GfwB+oWrhogZVnMFJKAoSYP8aQrLDVl7SQOAgTXz2IDD6bo1jga/8Kb72dD h8D2qrkqWh7Hwdas3jqqbb9uiq6O2dJJY86FjffjXPo3jGlFjTsCAwEAAaOBrjCB qzAdBgNVHQ4EFgQUVx+Aa0fM55v6NZR87Yi40QBa4J4wHwYDVR0jBBgwFoAUb+bF bAe3bIsKgZKDXMtBHvaO0ScwRQYDVR0gAQH/BDswOTA3BgRVHSAAMC8wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cuc3QuY29tL1RQTS9yZXBvc2l0b3J5LzAOBgNVHQ8B Af8EBAMCAAQwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAQEA 4gllWq44PFWcv0JgMPOtyXDQx30YB5vBpjS0in7f/Y/r+1Dd8q3EZwNOwYApe+Lp /ldNqCXw4XzmO8ZCVWOdQdVOqHZuSOhe++Jn0S7M4z2/1PQ6EbRczGfw3dlX63Ec cEnrn6YMcgPC63Q+ID53vbTS3gpeX/SGpngtVwnzpuJ5rBajqSQUo5jBTBtuGQpO Ko6Eu7U6Ouz7BVgOSn0mLbfSRb77PjOLZ3+97gSiMmV0iofS7ufemYqA8sF7ZFv/ lM2eOe/eeS56Jw+IPsnEU0Tf8Tn9hnEig1KP8VByRTWAJgiEOgX2nTs5iJbyZeIZ RUjDHQQ5onqhgjpfRsC95g== -----END CERTIFICATE-----`, "NTC1": `-----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIGAK3jXfbVMA0GCSqGSIb3DQEBBQUAMFIxUDAcBgNVBAMT FU5UQyBUUE0gRUsgUm9vdCBDQSAwMTAlBgNVBAoTHk51dm90b24gVGVjaG5vbG9n eSBDb3Jwb3JhdGlvbjAJBgNVBAYTAlRXMB4XDTEyMDcxMTE2MjkzMFoXDTMyMDcx MTE2MjkzMFowUjFQMBwGA1UEAxMVTlRDIFRQTSBFSyBSb290IENBIDAxMCUGA1UE ChMeTnV2b3RvbiBUZWNobm9sb2d5IENvcnBvcmF0aW9uMAkGA1UEBhMCVFcwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDoNqxhtD4yUtXhqKQGGZemoKJy uj1RnWvmNgzItLeejNU8B6fOnpMQyoS4K72tMhhFRK2jV9RYzyJMSjEwyX0ASTO1 2yMti2UJQS60d36eGwk8WLgrFnnITlemshi01h9t1MOmay3TO1LLH/3/VDKJ+jbd cbfIO2bBquN8r3/ojYUaNSPj6pK1mmsMoJXF4dGRSEwb/4ozBIw5dugm1MEq4Zj3 GZ0YPg5wyLRugQbt7DkUOX4FGuK5p/C0u5zX8u33EGTrDrRz3ye3zO+aAY1xXF/m qwEqgxX5M8f0/DXTTO/CfeIksuPeOzujFtXfi5Cy64eeIZ0nAUG3jbtnGjoFAgMB AAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqG SIb3DQEBBQUAA4IBAQBBQznOPJAsD4Yvyt/hXtVJSgBX/+rRfoaqbdt3UMbUPJYi pUoTUgaTx02DVRwommO+hLx7CS++1F2zorWC8qQyvNbg7iffQbbjWitt8NPE6kCr q0Y5g7M/LkQDd5N3cFfC15uFJOtlj+A2DGzir8dlXU/0qNq9dBFbi+y+Y3rAT+wK fktmN82UT861wTUzDvnXO+v7H5DYXjUU8kejPW6q+GgsccIbVTOdHNNWbMrcD9yf oS91nMZ/+/n7IfFWXNN82qERsrvOFCDsbIzUOR30N0IP++oqGfwAbKFfCOCFUz6j jpXUdJlh22tp12UMsreibmi5bsWYBgybwSbRgvzE -----END CERTIFICATE-----`, "NTC2": `-----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIGAPadBmPZMA0GCSqGSIb3DQEBBQUAMFIxUDAcBgNVBAMT FU5UQyBUUE0gRUsgUm9vdCBDQSAwMjAlBgNVBAoTHk51dm90b24gVGVjaG5vbG9n eSBDb3Jwb3JhdGlvbjAJBgNVBAYTAlRXMB4XDTEyMDcxMTE2MzMyNFoXDTMyMDcx MTE2MzMyNFowUjFQMBwGA1UEAxMVTlRDIFRQTSBFSyBSb290IENBIDAyMCUGA1UE ChMeTnV2b3RvbiBUZWNobm9sb2d5IENvcnBvcmF0aW9uMAkGA1UEBhMCVFcwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSagWxaANT1YA2YUSN7sq7yzOT 1ymbIM+WijhE5AGcLwLFoJ9fmaQrYL6fAW2EW/Q3yu97Q9Ysr8yYZ2XCCfxfseEr Vs80an8Nk6LkTDz8+0Hm0Cct0klvNUAZEIvWpmgHZMvGijXyOcp4z494d8B28Ynb I7x0JMXZZQQKQi+WfuHtntF+2osYScweocipPrGeONLKU9sngWZ2vnnvw1SBneTa irxq0Q0SD6Bx9jtxvdf87euk8JzfPhX8jp8GEeAjmLwGR+tnOQrDmczGNmp7YYNN R+Q7NZVoYWHw5jaoZnNxbouWUXZZxFqDsB/ndCKWtsIzRYPuWcqrFcmUN4SVAgMB AAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqG SIb3DQEBBQUAA4IBAQAIkdDSErzPLPYrVthw4lKjW4tRYelUicMPEHKjQeVUAAS5 y9XTzB4DWISDAFsgtQjqHJj0xCG+vpY0Rmn2FCO/0YpP+YBQkdbJOsiyXCdFy9e4 gGjQ24gw1B+rr84+pkI51y952NYBdoQDeb7diPe+24U94f//DYt/JQ8cJua4alr3 2Pohhh5TxCXXfU2EHt67KyqBSxCSy9m4OkCOGLHL2X5nQIdXVj178mw6DSAwyhwR n3uJo5MvUEoQTFZJKGSXfab619mIgzEr+YHsIQToqf44VfDMDdM+MFiXQ3a5fLii hEKQ9DhBPtpHAbhFA4jhCiG9HA8FdEplJ+M4uxNz -----END CERTIFICATE-----`, "IFX1": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIEMV64bDANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0wNTEwMjAxMzQ3NDNaFw0yNTEwMjAxMzQ3NDNaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAwMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALftPhYN t4rE+JnU/XOPICbOBLvfo6iA7nuq7zf4DzsAWBdsZEdFJQfaK331ihG3IpQnlQ2i YtDim289265f0J4OkPFpKeFU27CsfozVaNUm6UR/uzwA8ncxFc3iZLRMRNLru/Al VG053ULVDQMVx2iwwbBSAYO9pGiGbk1iMmuZaSErMdb9v0KRUyZM7yABiyDlM3cz UQX5vLWV0uWqxdGoHwNva5u3ynP9UxPTZWHZOHE6+14rMzpobs6Ww2RR8BgF96rh 4rRAZEl8BXhwiQq4STvUXkfvdpWH4lzsGcDDtrB6Nt3KvVNvsKz+b07Dk+Xzt+EH NTf3Byk2HlvX+scCAwEAAaOCATswggE3MB0GA1UdDgQWBBQ4k8292HPEIzMV4bE7 qWoNI8wQxzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBABJ1+Ap3rNlxZ0FW0aIgdzktbNHlvXWNxFdYIBbM OKjmbOos0Y4O60eKPu259XmMItCUmtbzF3oKYXq6ybARUT2Lm+JsseMF5VgikSlU BJALqpKVjwAds81OtmnIQe2LSu4xcTSavpsL4f52cUAu/maMhtSgN9mq5roYptq9 DnSSDZrX4uYiMPl//rBaNDBflhJ727j8xo9CCohF3yQUoQm7coUgbRMzyO64yMIO 3fhb+Vuc7sNwrMOz3VJN14C3JMoGgXy0c57IP/kD5zGRvljKEvrRC2I147+fPeLS DueRMS6lblvRKiZgmGAg7YaKOkOaEmVDMQ+fTo2Po7hI5wc= -----END CERTIFICATE-----`, "IFX2": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIEaItIgTANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0wNjEyMjExMDM0MDBaFw0yNjEyMjExMDM0MDBaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAwMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK6KnP5R 8ppq9TtPu3mAs3AFxdWhzK5ks+BixGR6mpzyXG64Bjl4xzBXeBIVtlBZXYvIAJ5s eCTEEsnZc9eKNJeFLdmXQ/siRrTeonyxoS4aL1mVEQebLUz2gN9J6j1ewly+OvGk jEYouGCzA+fARzLeRIrhuhBI0kUChbH7VM8FngJsbT4xKB3EJ6Wttma25VSimkAr SPS6dzUDRS1OFCWtAtHJW6YjBnA4wgR8WfpXsnjeNpwEEB+JciWu1VAueLNI+Kis RiferCfsgWRvHkR6RQf04h+FlhnYHJnf1ktqcEi1oYAjLsbYOAwqyoU1Pev9cS28 EA6FTJcxjuHhH9ECAwEAAaOCATswggE3MB0GA1UdDgQWBBRDMlr1UAQGVIkwzamm fceAZ7l4ATAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBAIZAaYGzf9AYv6DqoUNx6wdpayhCeX75/IHuFQ/d gLzat9Vd6qNKdAByskpOjpE0KRauEzD/BhTtkEJDazPSmVP1QxAPjqGaD+JjqhS/ Q6aY+1PSDi2zRIDA66V2yFJDcUBTtShbdTg144YSkVSY5UCKhQrsdg8yAbs7saAB LHzVebTXffjmkTk5GZk26d/AZQRjfssta1N/TWhWTfuZtwYvjZmgDPeCfr6AOPLr pVJz+ntzUKGpQ+5mwDJXMZ0qeiFIgXUlU0D+lfuajc/x9rgix9cM+o7amgDlRi1T 55Uu2vzUQ9jLUaISFaTTMag+quBDhx8BDVu+igLp5hvBtxQ= -----END CERTIFICATE-----`, "IFX3": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIEH7fYljANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0wNzA0MTMxNjQ0MjRaFw0yNzA0MTMxNjQ0MjRaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAwMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJWdPAuH z/p1tIwB1QXlPD/PjedZ4uBZdwPH5tI3Uve0TzbR/mO5clx/loWn7nZ5cHkH1nhB R67JEFY0a9GithPfITh0XRxPcisLBE/SoqZ90KHFaS+N6SwOpdCP0GlUg1OesKCF 79Z6fXrkTZsVpPqdawdZK+oUsDO9z9U6xqV7bwsS75Y+QiHsm6UTgAkSNQnuFMP3 NqQyDi/BaWaYRGQ6K8pM7Y7e1h21z/+5X7LncZXU8hgpYpu2zQPg96IkYboVUKL4 00snaPcOvfagsBUGlBltNfz7geaSuWTCdwEiwlkCYZqCtbkAj5FiStajrzP72BfT 2fshIv+5eF7Qp5ECAwEAAaOCATswggE3MB0GA1UdDgQWBBTGyypNtylL6RFyT1BB MQtMQvibsjAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBAGN1bkh4J90DGcOPP2BlwE6ejJ0iDKf1zF+7CLu5 WS5K4dvuzsWUoQ5eplUt1LrIlorLr46mLokZD0RTG8t49Rcw4AvxMgWk7oYk69q2 0MGwXwgZ5OQypHaPwslmddLcX+RyEvjrdGpQx3E/87ZrQP8OKnmqI3pBlB8QwCGL SV9AERaGDpzIHoObLlUjgHuD6aFekPfeIu1xbN25oZCWmqFVIhkKxWE1Xu+qqHIA dnCFhoIWH3ie9OsJh/iDRaANYYGyplIibDx1FJA8fqiBiBBKUlPoJvbqmZs4meMd OoeOuCvQ7op28UtaoV6H6BSYmN5dOgW7r1lX2Re0nd84NGE= -----END CERTIFICATE-----`, "IFX4": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIEDhD4wDANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0wNzEyMDMxMzA3NTVaFw0yNzEyMDMxMzA3NTVaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAwNDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN3UBmDk jJzzJ+WCgrq4tILtE9KJPMGHwvCsbJOlo7eHiEb8JQzGK1prkPQ3dowFRXPnqONP WUa36/J3R32xgvuZHqAdliZCt8IUb9qYhDenuXo1SSqJ8LWp30QIJ0vnkaQ2TCkO bveZZR3hK2OZKRTkFaV/iy2RH+Qs4JAe3diD8mlIu2gXAXnKJSkrzW6gbMzrlTOi RCuGcatpy7Hfmodbz/0Trbuwtc3dyJZ3Ko1z9bz2Oirjh93RrmYjbtL0HhkAjMOR 83GLrzwUddSqmxtXXX8j5i+/gmE3AO71swOIESdGugxaKUzJ1jTqWKMZcx0E6BFI lDIfKk0fJlSxHfECAwEAAaOCATswggE3MB0GA1UdDgQWBBSIs8E/YQXRBCKfWsDr SZVkrNRzvTAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBAFtqClQNBLOzcGZUpsBqlz3frzM45iiBpxosG1Re IgoAgtIBEtl609TG51tmpm294KqpfKZVO+xNzovm8k/heGb0jmYf+q1ggrk2qT4v Qy2jgE0jbP/P8WWq8NHC13uMcBUGPaka7yofEDDwz7TcduQyJVfG2pd1vflnzP0+ iiJpfCk3CAQQnb+B7zsOp7jHNwpvHP+FhNwZaikaa0OdR/ML9da1sOOW3oJSTEjW SMLuhaZHtcVgitvtOVvCI/aq47rNJku3xQ7c/s8FHnFzQQ+Q4TExbP20SrqQIlL/ 9sFAb7/nKYNauusakiF3pfvMrJOJigNfJyIcWaGfyyQtVVI= -----END CERTIFICATE-----`, "IFX5": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIEVuRoqzANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0wOTEyMTExMDM4NDJaFw0yOTEyMTExMDM4NDJaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAwNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL79zMCO bjkg7gCWEuyGO49CisF/QrGoz9adW1FBuSW8U9IOlvWXNsvoasC1mhrsfkRRojuU mWifxxxcVfOI9v1SbRfJ+i6lG21IcVe6ywLJdDliT+3vzvrb/2hU/XjCCMDWb/Pw aZslV5iL4QEiKxvRIiWMYHW0MkkL7mzRBDVN/Vz3ZiL5Lpq7awiKuX9OXpS2a1wf qSGAlm2TxjU884q9Ky85JJugn0Q/C3dc8aaFPKLHlRs6rIvN1l0LwB1b5EWPzTPJ d9EhRPFJOAbJS66nSgX06Fl7eWB71ow6w/25otLQCbpy6OrF8wBVMtPMHqFb1c32 PaaNzpCBnIU7vaMCAwEAAaOCATswggE3MB0GA1UdDgQWBBS7z3zBhCExZtq1vlOo cBTd00jYzDAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBAHomNJtmFNtRJI2+s6ZwdzCTHXXIcR/T+N/lfPbE hIUG4Kg+3uQMP7zBi22m3I3Kk9SXsjLqV5mnsQUGMGlF7jw5W5Q+d6NSJz4taw9D 2DsiUxE/i5vrjWiUaWxv2Eckd4MUexe5Qz8YSh4FPqLB8FZnAlgx2kfdzRIUjkMq EgFK8ZRSUjXdczvsud68YPVMIZTxK0L8POGJ6RYiDrjTelprfZ4pKKZ79XwxwAIo pG6emUEf+doRT0KoHoCHr9vvWCWKhojqlQ6jflPZcEsNBMbq5KHVN77vOU58OKx1 56v3EaqrZenVFt8+n6h2NzhOmg2quQXIr0V9jEg8GAMehDs= -----END CERTIFICATE-----`, "IFX8": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIEfGoY6jANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0xMjA3MTcwOTI0NTJaFw0zMDEwMTgyMzU5NTlaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAwODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOJaIJu6 r/betrMgWJ/JZ5j8ytoAA9RWq0cw7+W0e5L2kDLJMM288wYT+iEbfwx6sWSLAl7q okXYDtTB9MFNhQ5ZWFLslFXbYigtXJxwANcSdPISTF1Czn6LLi1fu1EHddwCXFC8 xaX0iGgQ9pZklvAy2ijK9BPHquWisisEiWZNRT9dCVylzOR3+p2YOC3ZrRmg7Bj+ DkC7dltTTO6dPR+LNOFe01pJlpZdF4YHcu4EC10gRu0quZz1LtDZWFKezK7rg5Rj LSAJbKOsGXjl6hQXMtADEX9Vlz1vItD21OYCNRsu6VdipiL0bl0aAio4BV3GMyjk 0gHnQwCk9k/YPU8CAwEAAaOCATswggE3MB0GA1UdDgQWBBRMS01kiQjkW/5aENNj h6aIrsHPeDAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBALMiDyQ9WKH/eTI84Mk8KYk+TXXEwf+fhgeCvxOQ G0FTSmOpJaNIzxWXr/gDbY3dO0ODjWRKYvhimZUuV+ckMA+wZX2C6o8g5njpWIOH pSAa+W35ijArh0Zt3MASJ46avd+fnQGTdzT0hK46gx6n2KixLvaZsR3JtuwUFYlQ wzmz/UsbBNEoPiR8p5E0Zf5GEGiTqkmBVYyS6XA34axpMMRHy0wI7AGs0gVihwUM rr0iWOu+GAcrm11lcYzqJvuEkfenAF62ufA2Ktv+Ut2xiRC0jUIp73CeplAJsqBr camV3pJn3qYPI5c1njMRYnoRFWQbrOR5ADWDQLFQPYRrJmg= -----END CERTIFICATE-----`, "IFX15": `-----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIER3V5aDANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJE RTEQMA4GA1UECBMHQmF2YXJpYTEhMB8GA1UEChMYSW5maW5lb24gVGVjaG5vbG9n aWVzIEFHMQwwCgYDVQQLEwNBSU0xGzAZBgNVBAMTEklGWCBUUE0gRUsgUm9vdCBD QTAeFw0xMjExMTQxNDQzMzRaFw0zMDEwMTgyMzU5NTlaMHcxCzAJBgNVBAYTAkRF MQ8wDQYDVQQIEwZTYXhvbnkxITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2ll cyBBRzEMMAoGA1UECxMDQUlNMSYwJAYDVQQDEx1JRlggVFBNIEVLIEludGVybWVk aWF0ZSBDQSAxNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKS6pgcg OQWSozVbMkdf9jZkpGdT4U735zs0skfpjoKK2CgpLMO/+oGKbObm/DQPRQO/oxvq jJNBKz55QBgKd+MoQ6t+2J8mcQ91Nfwqnm1C4r+c4zezJ1Utk/KIYNqpFDAzefBA /lK8IxQ6kmzxcIFE4skaFsSgkearSZGG6sA9A51yxwvs8yUrQF51ICEUM7wDb4cM 53utaFdm6p6m9UZGSmmrdTiemOkuuwtl8IUQXfuk9lFyQsACBTM95Hrts0IzI6hX QeTwSL4JqyEnKP9vbtT4eXzWNycqSYBf0+Uo/HHZo9WuVDUaA4I9zcmD0qCvSOT0 NAj4ifJ7SPGInU0CAwEAAaOCATswggE3MB0GA1UdDgQWBBR4pAnEV95pJvbfQsYR TrflaptW5zAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADBYBgNV HSABAf8ETjBMMEoGC2CGSAGG+EUBBy8BMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvaW5kZXguaHRtbDCBlwYDVR0jBIGP MIGMgBRW65FEhWPWcrOu1EWWC/eUDlRCpqFxpG8wbTELMAkGA1UEBhMCREUxEDAO BgNVBAgTB0JhdmFyaWExITAfBgNVBAoTGEluZmluZW9uIFRlY2hub2xvZ2llcyBB RzEMMAoGA1UECxMDQUlNMRswGQYDVQQDExJJRlggVFBNIEVLIFJvb3QgQ0GCAQMw DQYJKoZIhvcNAQEFBQADggEBAAnZDdJZs5QgAXnl0Jo5sCqktZcwcK+V1+uhsqrT Z7OJ9Ze1YJ9XB14KxRfmck7Erl5HVc6PtUcLnR0tuJKKKqm7dTe4sQEFYd5usjrW KSG6y7BOH7AdonocILY9OIxuNwxMAqhK8LIjkkRCeOWSvCqLnaLtrP52C0fBkTTM SWX7YnsutXEpwhro3Qsnm9hL9s3s/WoIuNKUcLFH/qWKztpxXnF0zip73gcZbwEy 1GPQQpYnxFJ2R2ab2RHlO+3Uf3FDxn+eRLXNl95ZZ6GE4OIIpKEg2urIiig0HmGA ijO6JfJxT30H9QNsx78sjYs7pOfMw6DfiqJ8Fx82GcCUOyM= -----END CERTIFICATE-----`, } trustedKeys := map[string]string{ "ATM1": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5a+4yXtubUnGJPz7ZVjW spGhe5Tr9BhrWQ9QOfDoVlkmi+tg2Gqc9qA9R39WhiiEmKuQ3+4XIvO+XFFrVCv+ 8YuEnBIIu46FEX1LBG7LnUJbkgAV0pzHMWOghLhDIGcGg/6kO9fH+7KcwfwNah+Z Lkfbfis3cm09RlOG8RSq8LyK8Zc07QH2M7L/8PFnRRQ5MnAgW7vuk8h/M62TTy+y DVuWl/jnh3vrKgVMoOyL/iM3EdFHIV+r/lJOI/HRAlkieCRGiJ1kJI4tQpUXiL+t K2iB1yAxnqcSQzWWxlNuu6sAUV2tI+qMVM2o6eT1f/MM7+b4nmyuBrdOIO5dvTek 7wIDAQAB -----END PUBLIC KEY-----`, "ATM10": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1HEeCn82r8Vrg64howvt s/2Yj5yuXhEv7FwUaISo7rYFnAbstyMVGNsL24reRW7aiyj65iHEojx1Car3Jlu8 hYfTqiagFmEK/qe8erEatwg5jFQ0GdK3a9Tw7nhYZjjpe98sRjL/DQlI5NiKClPF 4ZNqI418MGmzmPN/QNxRnKJAr5LTE8FZCMShm5V9ege72oLj4VfPuz29fQLBZWJA 2+NUy6gCpcUShejGfm9DTGBk0m3wruqyXuzKzJ4U0Xo5nTqp7ZV/JLbSWnTJxs72 hZ4D1nbi0paPQgcK5FYbIwQ1WuEpN5QMfilsAZFbokQnQa+jX2Rzleoa0mURVEnG TQIDAQAB -----END PUBLIC KEY-----`, "ATM11": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqrS1Ei1VvLxVYWNv/s35 aYmHa5MOnvQybgW/i1XuINZuPQqYNw02wrWRA5eft2ts+FkJDvbz6edtqH30Cjx+ pmE9OvotY7O7rboruz2W2PpcQ0/inLUixNiq/A8giKRWJaTNsiF6VLNEWEe5sf3r e6+C/ZQUfwupM56bU0JrIMxEgp8SCFguQsNwcq2txtr1ujgX4PN6DOet6BcrTpsY vxKhQPbL/Tfl/kMqYVzqqyrBGgkg8+2FRxO6bVSJCwryrA37ZwkgJl3k/qibTFzw JVfJnGaT57L/TUVJRwADtVN+oJFcQamR7N6VIuohx7fp7U8t8nrKhZpIwK405hLE 1wIDAQAB -----END PUBLIC KEY-----`, "ATM12": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1R4fVBbUI7tsaRuS0VvH TiouZ7L/HAokHIsozeLKamistnoCNKMyz40pwGenK8l0XnvJveoAlT+3tbKmmeo7 iR1QP28shN8ggnObHZpBN2cPiySh0A8uYIEXY3sJMrNZ/h2MMbjYD2nUyreVpuj+ mytSbvmB1eqcj9p4JBY1aqwXBrm0DqxZXJsVNBkjJ7c9kFy3ze8yccTFKx/wXe7v PHgoWKA7RLtM2i/ppJdQgT/IubOrhZTyWPpvLQDpNf0p/SDmByw3/RzinPFlxUmA eBzvTDwM7jEsZIUQGDZIBhifK45VLLrQiDTTOL8eVw9D8H0zn8AJu7cF9w9oYQj6 fQIDAQAB -----END PUBLIC KEY-----`, "ATM13": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwSvUzUQRjD3KyZMJu5CZ sHVLqAN0mBT86nivjCV+RhHsR0uSU110NKjb2IHXM3fYaJlgvZRTAQJ3c8jPc0bV tC0+521QKKt86OLi0+nrNT2QzLtrJgx6eRoYiu9se2F0u/zB+PHQ0R8qVOI1xw0W FVK2w2+mRT3WN4Udp0Rn6LKPRXCq59JPfuD7hNBVmwp9uzj2TLp8ljMRSbChRjek u9H4G+b2qa4wf2g9R5/Eqq5cMwYsD4357cuhlfqWQxD61J93ro2Hf5+30JrZF2yo /TX5ocdQqnvLeape1KZGTDrikNXD9eIhR53yT4aBAK/RB8scsbwjn5tnoIBO0GAE wwIDAQAB -----END PUBLIC KEY-----`, "ATM2": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6e/oMMyv7NPlNKo9A7ls wJDkE14LZGSsKiRyzyJe2qHCoBwsZEq3QV2w4ducngcOysRaczDd8Cku9Z332dbi 9Tq6RZapk/eL7mcBF/XBNu7Wft3PDRTzs8gpM3xFHo59+OAjeax3TE8yR6Phiipp 42uI9f184vQsgwzEWNz6kMUP5mwe3Hm9y8RlTzrpJAtVtW9w7LmoSeOHHgzsEGG9 q5F2PkY6X0Ft9eDQaIOlTofkSHzvG2VLv8MJINMjnXrPnvF8dqG38lzAIvDfJKKx E5MjY2aoFc1dfISQDv4sYx02b6jwfDl8pFCrwCzH7cWmIE0hD2BV2LpurURTi+kk MQIDAQAB -----END PUBLIC KEY-----`, "ATM3": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmFAUATJ/8xIeuFW0aKNZ cwCtDLDOQoGIez+sg64EmJ+rEKNHfPQj7ee3UxiARWoLvmrMwMZFHXVuHb6Q6QUB H2OmUZfhcBXm94ZbXrFQyDxosR3lU+JZu5JK0X76kZAQtiBI2/UkJMt0xRUm1P7p InKnqk9HYw2HpwrCYZII78R2N8bfGJAXOpz1oOpI7jVHewtJY/gun1jgXuOwNW+1 ouDaUrB/8t9m0lvsoeqduq0Nhvl4AL6kxVFp4sSX3gFuSORcbFP4hu7UMJy6g59d bsgpulbltd2+HDqxEa4VPOe3IlC4iUso091vq+V49ThYOZ0TXFjk1dNdcTFuK2O8 kQIDAQAB -----END PUBLIC KEY-----`, "ATM4": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxtl1salu/2SXeqCGMtac 0GMCqx6Qeh4KtrviPfGVdObksuyGRPPuaW25/oYNGLlf2x/kDlknB2eZFMiW8otK XV+xO50uFcxoTHXZ1wnMD8x6CgM0z0j3DQ5d0eu5sRRDd7GHYEpuvMj0x8pgkZk+ C+Ux2hWlj8xEiEDH8q5wyP5AX92GkpoUAL0e4vUV7/cCEBcsLOs8Oq6rKzmig82k sDiL/Tn/8TtsSmUAwT/FzM/gi79x0D1hHtXyLOFPDIrOy3d3cz5QMOSSLDHGjmoa DBF0+rcBRJCCU2iBtfIMBevJO1IBUmj/EgerHWWaf5pNNJAL62eAeeaWKm5OaX6b VQIDAQAB -----END PUBLIC KEY-----`, "ATM5": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqg1FjhOQ/GsqgUL+WSBc fYr3hkxxl1EBaCIqiolc1R5TmZabaHoCUIJmhwXfFGhFvhZrI0AcEqIYANLgY0ri vn4h6vV+rrwtxM1X7X8hmT+AdvxL2p9lOCp7XNpQ2Rw+o/2JhuBSUv+opW7K6wPu mwUpy4gL+dAozZyBjan5Co9sP5Yh3kdG3+ezRsfxf3CnS76NhjHglK9AWUdM1c6m FGqTP+fU9ySTpoabrnDUzIcedu5OsMZa5L1LeLKHrqrbM3b995aU9RPrIQoO3x+B Sau9Ab0d614zpD0TeWwjBT7Y5rIg14bIx7DiA+4kGRE5fHZtpdSWpgJmlkcObSSd vQIDAQAB -----END PUBLIC KEY-----`, "ATM6": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw9s9ykpgzH1Birz8JVmH c/jXNSaFsDQYM9hcS3513P7arS+r/musmUqfdybY/GQ8+YqAA6IZq+xlGZ7WUEmx vo/Hlnm/FQj3epZGD3ruApm+8dLV4Hvs4RjZCS8cfpkRZygh+nRdrZ3aAwZRjQbh vl8mAJOQ2Rp9ANaZMzYjre7adkuqIFDa83nKgn4XkMIft+MthOvcMYmZtSL64gvA NZ7PiryB2cMhS+0yAMGK/Oqm0ELIRk8wqAR/l3txRVxoQEqA9fBk2bvGNiWva92c hxCLpEX9+CcZWvUeH6Up5a2EDxw8BgxE0L6sqjINWn2uN0x7jlKysg+XEyo7qUpM RQIDAQAB -----END PUBLIC KEY-----`, "ATM7": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlYRfDD3bMJB7w6Fl+Kez oIaEkzz+2VCeF8v3ohsNnSKCgcx8uk7Seyp50bEtLB6vOzwgcM5WjFItKyYLZaHt P43q3iHsvISjAGNcYGcQ3NrM4ia6pc2geVraupldPTdQFOQjwd+0P/Q2/RMbWY6g +sbjIDtItEc1vhf6bI3TinT+bGxxXdR9B6qWgLNc/H31wsBNN2nPv1K4wE8MWfAV 7hcK2NoIc1zGEY+IiWPtXSu48zmvS2lxKWWYuiHBwCt5ns/U7M8XSjkaj7SbhD02 yKwiMavu7SMAceSWWMBuhjgm9/zfMAPKO9weQixVCeuXspByefsekPuk5ohbWOS/ bwIDAQAB -----END PUBLIC KEY-----`, "ATM8": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylXag4JmzoqaTK8eCcSj DSOGRcrX8IK/fBawgEWKAgPy/yu+8FGXXK10XDeI1fmlAefDr7349Cn+v9/y+Mff XIduKCqR5ZP9M1+fBk7k5l4x2SeC9NfIMG+c0yJ6m1kEmsSN04nlKk8foo54L7DY +Kkjfh6EPxyzxsMDqqTrMifBThF2kqo5KUBDdBjIkOUH1dbLWGjEgUpKocCu2M41 U7jmjToatkA+d3V+PyQRF4/lJkTYiv6Jy1Zl1qpEkLvR0qKrzoHkOij7zBpQ/46B 2BW1pARjU7AIp3NtfS5THL59mpXxpuyj6y2h0wxNVRkPZpnVA0ZWHgz9J4TcIgAN PwIDAQAB -----END PUBLIC KEY-----`, "ATM9": `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxa0XBIlBj9t5bYB81Cea mlV3I3rTathgyUn2VL7/wng2vK5x7BB3a1wjXt5k/uwR/M5tfIDOSjug/SdDfTWk ZRe82Ij/oYJOytcrFzEzouIZVA7t/uKdXzRwz7dZ6LPnNVkp8GiWUDCDpTNNmnvi eZcjqofajDcc0EC720NT+NqmkAJd0qYMs+i4TA2om2C2Lxpkq+YdJp2pJOCCQquC wmLXB8OxrddjX4QW5mHzigx4fanC/GJcXuRQPXqLruHZlWmUqU7Sl6yZEluItHbB ri4BxD3Q7eXH0sM3rZGUCLr3lMPXjGsfpogZT4zLr075QIxtwe5OUpnslU61c34X BwIDAQAB -----END PUBLIC KEY-----`, } cert, err := x509.ParseCertificate(ekcert) if err != nil { return fmt.Errorf("Unable to parse EKCert: %s", err) } for vendor, certificate := range trustedCerts { block, _ := pem.Decode([]byte(certificate)) testcert, err := x509.ParseCertificate(block.Bytes) if err != nil { return fmt.Errorf("Unable to parse %s: %s", vendor, err) } err = testcert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature) if err == nil { return nil } } for vendor, key := range trustedKeys { block, _ := pem.Decode([]byte(key)) pubkey, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return fmt.Errorf("Unable to parse %s: %s", vendor, err) } hashdata := sha1.Sum(cert.RawTBSCertificate[:]) err = rsa.VerifyPKCS1v15(pubkey.(*rsa.PublicKey), crypto.SHA1, hashdata[:], cert.Signature) if err == nil { return nil } } return fmt.Errorf("No matching certificate found") } // QuoteVerify verifies that a quote was genuinely provided by the TPM. It // takes the quote data, quote validation blob, public half of the AIK, // current PCR values and the nonce used in the original quote request. It // then verifies that the validation block is a valid signature for the // quote data, that the secrets are the same (in order to avoid replay // attacks), and that the PCR values are the same. It returns an error if // any stage of the validation fails. func QuoteVerify(data []byte, validation []byte, aikpub []byte, pcrvalues [][]byte, secret []byte) error { n := big.NewInt(0) n.SetBytes(aikpub) e := 65537 pKey := rsa.PublicKey{N: n, E: int(e)} dataHash := sha1.Sum(data[:]) err := rsa.VerifyPKCS1v15(&pKey, crypto.SHA1, dataHash[:], validation) if err != nil { return err } pcrHash := data[8:28] nonceHash := data[28:48] secretHash := sha1.Sum(secret[:]) if bytes.Equal(secretHash[:], nonceHash) == false { return fmt.Errorf("Secret doesn't match") } pcrComposite := []byte{0x00, 0x02, 0xff, 0xff, 0x00, 0x00, 0x01, 0x40} for i := 0; i < 16; i++ { pcrComposite = append(pcrComposite, pcrvalues[i]...) } pcrCompositeHash := sha1.Sum(pcrComposite[:]) if bytes.Equal(pcrCompositeHash[:], pcrHash) == false { return fmt.Errorf("PCR values don't match") } return nil } // KeyVerify verifies that a key certification request was genuinely // provided by the TPM. It takes the certification data, certification // validation blob, the public half of the AIK, the public half of the key // to be certified and the nonce used in the original quote request. It then // verifies that the validation block is a valid signature for the // certification data, that the certification data matches the certified key // and that the secrets are the same (in order to avoid replay attacks). It // returns an error if any stage of the validation fails. func KeyVerify(data []byte, validation []byte, aikpub []byte, keypub []byte, secret []byte) error { n := big.NewInt(0) n.SetBytes(aikpub) e := 65537 pKey := rsa.PublicKey{N: n, E: int(e)} dataHash := sha1.Sum(data[:]) err := rsa.VerifyPKCS1v15(&pKey, crypto.SHA1, dataHash[:], validation) if err != nil { return err } keyHash := data[43:63] nonceHash := data[63:83] secretHash := sha1.Sum(secret[:]) if bytes.Equal(secretHash[:], nonceHash) == false { return fmt.Errorf("Secret doesn't match") } certHash := sha1.Sum(keypub[:]) if bytes.Equal(certHash[:], keyHash) == false { return fmt.Errorf("Key doesn't match") } return nil }