mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-23 21:23:41 +09:00
Support webauthn (#17957)
Migrate from U2F to Webauthn Co-authored-by: Andrew Thornton <art27@cantab.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
co-authored by
Andrew Thornton
6543
wxiaoguang
parent
8808293247
commit
35c3553870
+282
@@ -0,0 +1,282 @@
|
||||
package googletpm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// DecodeAttestationData decode a TPMS_ATTEST message. No error is returned if
|
||||
// the input has extra trailing data.
|
||||
func DecodeAttestationData(in []byte) (*AttestationData, error) {
|
||||
buf := bytes.NewBuffer(in)
|
||||
|
||||
var ad AttestationData
|
||||
if err := UnpackBuf(buf, &ad.Magic, &ad.Type); err != nil {
|
||||
return nil, fmt.Errorf("decoding Magic/Type: %v", err)
|
||||
}
|
||||
n, err := decodeName(buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding QualifiedSigner: %v", err)
|
||||
}
|
||||
ad.QualifiedSigner = *n
|
||||
if err := UnpackBuf(buf, &ad.ExtraData, &ad.ClockInfo, &ad.FirmwareVersion); err != nil {
|
||||
return nil, fmt.Errorf("decoding ExtraData/ClockInfo/FirmwareVersion: %v", err)
|
||||
}
|
||||
|
||||
// The spec specifies several other types of attestation data. We only need
|
||||
// parsing of Certify & Creation attestation data for now. If you need
|
||||
// support for other attestation types, add them here.
|
||||
switch ad.Type {
|
||||
case TagAttestCertify:
|
||||
if ad.AttestedCertifyInfo, err = decodeCertifyInfo(buf); err != nil {
|
||||
return nil, fmt.Errorf("decoding AttestedCertifyInfo: %v", err)
|
||||
}
|
||||
case TagAttestCreation:
|
||||
if ad.AttestedCreationInfo, err = decodeCreationInfo(buf); err != nil {
|
||||
return nil, fmt.Errorf("decoding AttestedCreationInfo: %v", err)
|
||||
}
|
||||
case TagAttestQuote:
|
||||
if ad.AttestedQuoteInfo, err = decodeQuoteInfo(buf); err != nil {
|
||||
return nil, fmt.Errorf("decoding AttestedQuoteInfo: %v", err)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
|
||||
}
|
||||
|
||||
return &ad, nil
|
||||
}
|
||||
|
||||
// AttestationData contains data attested by TPM commands (like Certify).
|
||||
type AttestationData struct {
|
||||
Magic uint32
|
||||
Type Tag
|
||||
QualifiedSigner Name
|
||||
ExtraData []byte
|
||||
ClockInfo ClockInfo
|
||||
FirmwareVersion uint64
|
||||
AttestedCertifyInfo *CertifyInfo
|
||||
AttestedQuoteInfo *QuoteInfo
|
||||
AttestedCreationInfo *CreationInfo
|
||||
}
|
||||
|
||||
// Tag is a command tag.
|
||||
type Tag uint16
|
||||
|
||||
type Name struct {
|
||||
Handle *Handle
|
||||
Digest *HashValue
|
||||
}
|
||||
|
||||
// A Handle is a reference to a TPM object.
|
||||
type Handle uint32
|
||||
type HashValue struct {
|
||||
Alg Algorithm
|
||||
Value []byte
|
||||
}
|
||||
|
||||
// ClockInfo contains TPM state info included in AttestationData.
|
||||
type ClockInfo struct {
|
||||
Clock uint64
|
||||
ResetCount uint32
|
||||
RestartCount uint32
|
||||
Safe byte
|
||||
}
|
||||
|
||||
// CertifyInfo contains Certify-specific data for TPMS_ATTEST.
|
||||
type CertifyInfo struct {
|
||||
Name Name
|
||||
QualifiedName Name
|
||||
}
|
||||
|
||||
// QuoteInfo represents a TPMS_QUOTE_INFO structure.
|
||||
type QuoteInfo struct {
|
||||
PCRSelection PCRSelection
|
||||
PCRDigest []byte
|
||||
}
|
||||
|
||||
// PCRSelection contains a slice of PCR indexes and a hash algorithm used in
|
||||
// them.
|
||||
type PCRSelection struct {
|
||||
Hash Algorithm
|
||||
PCRs []int
|
||||
}
|
||||
|
||||
// CreationInfo contains Creation-specific data for TPMS_ATTEST.
|
||||
type CreationInfo struct {
|
||||
Name Name
|
||||
// Most TPM2B_Digest structures contain a TPMU_HA structure
|
||||
// and get parsed to HashValue. This is never the case for the
|
||||
// digest in TPMS_CREATION_INFO.
|
||||
OpaqueDigest []byte
|
||||
}
|
||||
|
||||
func decodeName(in *bytes.Buffer) (*Name, error) {
|
||||
var nameBuf []byte
|
||||
if err := UnpackBuf(in, &nameBuf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := new(Name)
|
||||
switch len(nameBuf) {
|
||||
case 0:
|
||||
// No name is present.
|
||||
case 4:
|
||||
name.Handle = new(Handle)
|
||||
if err := UnpackBuf(bytes.NewBuffer(nameBuf), name.Handle); err != nil {
|
||||
return nil, fmt.Errorf("decoding Handle: %v", err)
|
||||
}
|
||||
default:
|
||||
var err error
|
||||
name.Digest, err = decodeHashValue(bytes.NewBuffer(nameBuf))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding Digest: %v", err)
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func decodeHashValue(in *bytes.Buffer) (*HashValue, error) {
|
||||
var hv HashValue
|
||||
if err := UnpackBuf(in, &hv.Alg); err != nil {
|
||||
return nil, fmt.Errorf("decoding Alg: %v", err)
|
||||
}
|
||||
hfn, ok := hashConstructors[hv.Alg]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported hash algorithm type 0x%x", hv.Alg)
|
||||
}
|
||||
hv.Value = make([]byte, hfn().Size())
|
||||
if _, err := in.Read(hv.Value); err != nil {
|
||||
return nil, fmt.Errorf("decoding Value: %v", err)
|
||||
}
|
||||
return &hv, nil
|
||||
}
|
||||
|
||||
// HashConstructor returns a function that can be used to make a
|
||||
// hash.Hash using the specified algorithm. An error is returned
|
||||
// if the algorithm is not a hash algorithm.
|
||||
func (a Algorithm) HashConstructor() (func() hash.Hash, error) {
|
||||
c, ok := hashConstructors[a]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("algorithm not supported: 0x%x", a)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var hashConstructors = map[Algorithm]func() hash.Hash{
|
||||
AlgSHA1: sha1.New,
|
||||
AlgSHA256: sha256.New,
|
||||
AlgSHA384: sha512.New384,
|
||||
AlgSHA512: sha512.New,
|
||||
}
|
||||
|
||||
// TPM Structure Tags. Tags are used to disambiguate structures, similar to Alg
|
||||
// values: tag value defines what kind of data lives in a nested field.
|
||||
const (
|
||||
TagNull Tag = 0x8000
|
||||
TagNoSessions Tag = 0x8001
|
||||
TagSessions Tag = 0x8002
|
||||
TagAttestCertify Tag = 0x8017
|
||||
TagAttestQuote Tag = 0x8018
|
||||
TagAttestCreation Tag = 0x801a
|
||||
TagHashCheck Tag = 0x8024
|
||||
)
|
||||
|
||||
func decodeCertifyInfo(in *bytes.Buffer) (*CertifyInfo, error) {
|
||||
var ci CertifyInfo
|
||||
|
||||
n, err := decodeName(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding Name: %v", err)
|
||||
}
|
||||
ci.Name = *n
|
||||
|
||||
n, err = decodeName(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding QualifiedName: %v", err)
|
||||
}
|
||||
ci.QualifiedName = *n
|
||||
|
||||
return &ci, nil
|
||||
}
|
||||
|
||||
func decodeCreationInfo(in *bytes.Buffer) (*CreationInfo, error) {
|
||||
var ci CreationInfo
|
||||
|
||||
n, err := decodeName(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding Name: %v", err)
|
||||
}
|
||||
ci.Name = *n
|
||||
|
||||
if err := UnpackBuf(in, &ci.OpaqueDigest); err != nil {
|
||||
return nil, fmt.Errorf("decoding Digest: %v", err)
|
||||
}
|
||||
|
||||
return &ci, nil
|
||||
}
|
||||
|
||||
func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
|
||||
var out QuoteInfo
|
||||
sel, err := decodeTPMLPCRSelection(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding PCRSelection: %v", err)
|
||||
}
|
||||
out.PCRSelection = sel
|
||||
if err := UnpackBuf(in, &out.PCRDigest); err != nil {
|
||||
return nil, fmt.Errorf("decoding PCRDigest: %v", err)
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func decodeTPMLPCRSelection(buf *bytes.Buffer) (PCRSelection, error) {
|
||||
var count uint32
|
||||
var sel PCRSelection
|
||||
if err := UnpackBuf(buf, &count); err != nil {
|
||||
return sel, err
|
||||
}
|
||||
switch count {
|
||||
case 0:
|
||||
sel.Hash = AlgUnknown
|
||||
return sel, nil
|
||||
case 1: // We only support decoding of a single PCRSelection.
|
||||
default:
|
||||
return sel, fmt.Errorf("decoding TPML_PCR_SELECTION list longer than 1 is not supported (got length %d)", count)
|
||||
}
|
||||
|
||||
// See comment in encodeTPMLPCRSelection for details on this format.
|
||||
var ts tpmsPCRSelection
|
||||
if err := UnpackBuf(buf, &ts.Hash, &ts.Size); err != nil {
|
||||
return sel, err
|
||||
}
|
||||
ts.PCRs = make([]byte, ts.Size)
|
||||
if _, err := buf.Read(ts.PCRs); err != nil {
|
||||
return sel, err
|
||||
}
|
||||
|
||||
sel.Hash = ts.Hash
|
||||
for i := 0; i < int(ts.Size); i++ {
|
||||
for j := 0; j < 8; j++ {
|
||||
set := ts.PCRs[i] & byte(1<<byte(j))
|
||||
if set == 0 {
|
||||
continue
|
||||
}
|
||||
sel.PCRs = append(sel.PCRs, 8*i+j)
|
||||
}
|
||||
}
|
||||
return sel, nil
|
||||
}
|
||||
|
||||
type tpmsPCRSelection struct {
|
||||
Hash Algorithm
|
||||
Size byte
|
||||
PCRs RawBytes
|
||||
}
|
||||
|
||||
// RawBytes is for Pack and RunCommand arguments that are already encoded.
|
||||
// Compared to []byte, RawBytes will not be prepended with slice length during
|
||||
// encoding.
|
||||
type RawBytes []byte
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package googletpm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// From github.com/google/go-tpm
|
||||
// Portions of existing package conflicted with existing build environment
|
||||
// and only needed very small amount of code for pubarea and certinfo structs
|
||||
// so copied them out to this package
|
||||
|
||||
// Supported Algorithms.
|
||||
const (
|
||||
AlgUnknown Algorithm = 0x0000
|
||||
AlgRSA Algorithm = 0x0001
|
||||
AlgSHA1 Algorithm = 0x0004
|
||||
AlgAES Algorithm = 0x0006
|
||||
AlgKeyedHash Algorithm = 0x0008
|
||||
AlgSHA256 Algorithm = 0x000B
|
||||
AlgSHA384 Algorithm = 0x000C
|
||||
AlgSHA512 Algorithm = 0x000D
|
||||
AlgNull Algorithm = 0x0010
|
||||
AlgRSASSA Algorithm = 0x0014
|
||||
AlgRSAES Algorithm = 0x0015
|
||||
AlgRSAPSS Algorithm = 0x0016
|
||||
AlgOAEP Algorithm = 0x0017
|
||||
AlgECDSA Algorithm = 0x0018
|
||||
AlgECDH Algorithm = 0x0019
|
||||
AlgECDAA Algorithm = 0x001A
|
||||
AlgKDF2 Algorithm = 0x0021
|
||||
AlgECC Algorithm = 0x0023
|
||||
AlgCTR Algorithm = 0x0040
|
||||
AlgOFB Algorithm = 0x0041
|
||||
AlgCBC Algorithm = 0x0042
|
||||
AlgCFB Algorithm = 0x0043
|
||||
AlgECB Algorithm = 0x0044
|
||||
)
|
||||
|
||||
// UnpackBuf recursively unpacks types from a reader just as encoding/binary
|
||||
// does under binary.BigEndian, but with one difference: it unpacks a byte
|
||||
// slice by first reading an integer with lengthPrefixSize bytes, then reading
|
||||
// that many bytes. It assumes that incoming values are pointers to values so
|
||||
// that, e.g., underlying slices can be resized as needed.
|
||||
func UnpackBuf(buf io.Reader, elts ...interface{}) error {
|
||||
for _, e := range elts {
|
||||
v := reflect.ValueOf(e)
|
||||
k := v.Kind()
|
||||
if k != reflect.Ptr {
|
||||
return fmt.Errorf("all values passed to Unpack must be pointers, got %v", k)
|
||||
}
|
||||
|
||||
if v.IsNil() {
|
||||
return errors.New("can't fill a nil pointer")
|
||||
}
|
||||
|
||||
iv := reflect.Indirect(v)
|
||||
switch iv.Kind() {
|
||||
case reflect.Struct:
|
||||
// Decompose the struct and copy over the values.
|
||||
for i := 0; i < iv.NumField(); i++ {
|
||||
if err := UnpackBuf(buf, iv.Field(i).Addr().Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
var size int
|
||||
_, isHandles := e.(*[]Handle)
|
||||
|
||||
switch {
|
||||
// []Handle always uses 2-byte length, even with TPM 1.2.
|
||||
case isHandles:
|
||||
var tmpSize uint16
|
||||
if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
|
||||
return err
|
||||
}
|
||||
size = int(tmpSize)
|
||||
// TPM 2.0
|
||||
case lengthPrefixSize == tpm20PrefixSize:
|
||||
var tmpSize uint16
|
||||
if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
|
||||
return err
|
||||
}
|
||||
size = int(tmpSize)
|
||||
// TPM 1.2
|
||||
case lengthPrefixSize == tpm12PrefixSize:
|
||||
var tmpSize uint32
|
||||
if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
|
||||
return err
|
||||
}
|
||||
size = int(tmpSize)
|
||||
default:
|
||||
return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", lengthPrefixSize)
|
||||
}
|
||||
|
||||
// A zero size is used by the TPM to signal that certain elements
|
||||
// are not present.
|
||||
if size == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Make len(e) match size exactly.
|
||||
switch b := e.(type) {
|
||||
case *[]byte:
|
||||
if len(*b) >= size {
|
||||
*b = (*b)[:size]
|
||||
} else {
|
||||
*b = append(*b, make([]byte, size-len(*b))...)
|
||||
}
|
||||
case *[]Handle:
|
||||
if len(*b) >= size {
|
||||
*b = (*b)[:size]
|
||||
} else {
|
||||
*b = append(*b, make([]Handle, size-len(*b))...)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("can't fill pointer to %T, only []byte or []Handle slices", e)
|
||||
}
|
||||
|
||||
if err := binary.Read(buf, binary.BigEndian, e); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := binary.Read(buf, binary.BigEndian, e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// lengthPrefixSize is the size in bytes of length prefix for byte slices.
|
||||
//
|
||||
// In TPM 1.2 this is 4 bytes.
|
||||
// In TPM 2.0 this is 2 bytes.
|
||||
var lengthPrefixSize int
|
||||
|
||||
const (
|
||||
tpm12PrefixSize = 4
|
||||
tpm20PrefixSize = 2
|
||||
)
|
||||
|
||||
// UseTPM20LengthPrefixSize makes Pack/Unpack use TPM 2.0 encoding for byte
|
||||
// arrays.
|
||||
func UseTPM20LengthPrefixSize() {
|
||||
lengthPrefixSize = tpm20PrefixSize
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
package googletpm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// DecodePublic decodes a TPMT_PUBLIC message. No error is returned if
|
||||
// the input has extra trailing data.
|
||||
func DecodePublic(buf []byte) (Public, error) {
|
||||
in := bytes.NewBuffer(buf)
|
||||
var pub Public
|
||||
var err error
|
||||
if err = UnpackBuf(in, &pub.Type, &pub.NameAlg, &pub.Attributes, &pub.AuthPolicy); err != nil {
|
||||
return pub, fmt.Errorf("decoding TPMT_PUBLIC: %v", err)
|
||||
}
|
||||
|
||||
switch pub.Type {
|
||||
case AlgRSA:
|
||||
pub.RSAParameters, err = decodeRSAParams(in)
|
||||
case AlgECC:
|
||||
pub.ECCParameters, err = decodeECCParams(in)
|
||||
default:
|
||||
err = fmt.Errorf("unsupported type in TPMT_PUBLIC: %v", pub.Type)
|
||||
}
|
||||
return pub, err
|
||||
}
|
||||
|
||||
// Public contains the public area of an object.
|
||||
type Public struct {
|
||||
Type Algorithm
|
||||
NameAlg Algorithm
|
||||
Attributes KeyProp
|
||||
AuthPolicy []byte
|
||||
|
||||
// If Type is AlgKeyedHash, then do not set these.
|
||||
// Otherwise, only one of the Parameters fields should be set. When encoding/decoding,
|
||||
// one will be picked based on Type.
|
||||
RSAParameters *RSAParams
|
||||
ECCParameters *ECCParams
|
||||
}
|
||||
|
||||
// Algorithm represents a TPM_ALG_ID value.
|
||||
type Algorithm uint16
|
||||
|
||||
// KeyProp is a bitmask used in Attributes field of key templates. Individual
|
||||
// flags should be OR-ed to form a full mask.
|
||||
type KeyProp uint32
|
||||
|
||||
// Key properties.
|
||||
const (
|
||||
FlagFixedTPM KeyProp = 0x00000002
|
||||
FlagFixedParent KeyProp = 0x00000010
|
||||
FlagSensitiveDataOrigin KeyProp = 0x00000020
|
||||
FlagUserWithAuth KeyProp = 0x00000040
|
||||
FlagAdminWithPolicy KeyProp = 0x00000080
|
||||
FlagNoDA KeyProp = 0x00000400
|
||||
FlagRestricted KeyProp = 0x00010000
|
||||
FlagDecrypt KeyProp = 0x00020000
|
||||
FlagSign KeyProp = 0x00040000
|
||||
|
||||
FlagSealDefault = FlagFixedTPM | FlagFixedParent
|
||||
FlagSignerDefault = FlagSign | FlagRestricted | FlagFixedTPM |
|
||||
FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth
|
||||
FlagStorageDefault = FlagDecrypt | FlagRestricted | FlagFixedTPM |
|
||||
FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth
|
||||
)
|
||||
|
||||
func decodeRSAParams(in *bytes.Buffer) (*RSAParams, error) {
|
||||
var params RSAParams
|
||||
var err error
|
||||
|
||||
if params.Symmetric, err = decodeSymScheme(in); err != nil {
|
||||
return nil, fmt.Errorf("decoding Symmetric: %v", err)
|
||||
}
|
||||
if params.Sign, err = decodeSigScheme(in); err != nil {
|
||||
return nil, fmt.Errorf("decoding Sign: %v", err)
|
||||
}
|
||||
var modBytes []byte
|
||||
if err := UnpackBuf(in, ¶ms.KeyBits, ¶ms.Exponent, &modBytes); err != nil {
|
||||
return nil, fmt.Errorf("decoding KeyBits, Exponent, Modulus: %v", err)
|
||||
}
|
||||
if params.Exponent == 0 {
|
||||
params.encodeDefaultExponentAsZero = true
|
||||
params.Exponent = defaultRSAExponent
|
||||
}
|
||||
params.Modulus = new(big.Int).SetBytes(modBytes)
|
||||
return ¶ms, nil
|
||||
}
|
||||
|
||||
const defaultRSAExponent = 1<<16 + 1
|
||||
|
||||
// RSAParams represents parameters of an RSA key pair.
|
||||
//
|
||||
// Symmetric and Sign may be nil, depending on key Attributes in Public.
|
||||
//
|
||||
// One of Modulus and ModulusRaw must always be non-nil. Modulus takes
|
||||
// precedence. ModulusRaw is used for key templates where the field named
|
||||
// "unique" must be a byte array of all zeroes.
|
||||
type RSAParams struct {
|
||||
Symmetric *SymScheme
|
||||
Sign *SigScheme
|
||||
KeyBits uint16
|
||||
// The default Exponent (65537) has two representations; the
|
||||
// 0 value, and the value 65537.
|
||||
// If encodeDefaultExponentAsZero is set, an exponent of 65537
|
||||
// will be encoded as zero. This is necessary to produce an identical
|
||||
// encoded bitstream, so Name digest calculations will be correct.
|
||||
encodeDefaultExponentAsZero bool
|
||||
Exponent uint32
|
||||
ModulusRaw []byte
|
||||
Modulus *big.Int
|
||||
}
|
||||
|
||||
// SymScheme represents a symmetric encryption scheme.
|
||||
type SymScheme struct {
|
||||
Alg Algorithm
|
||||
KeyBits uint16
|
||||
Mode Algorithm
|
||||
} // SigScheme represents a signing scheme.
|
||||
type SigScheme struct {
|
||||
Alg Algorithm
|
||||
Hash Algorithm
|
||||
Count uint32
|
||||
}
|
||||
|
||||
func decodeSigScheme(in *bytes.Buffer) (*SigScheme, error) {
|
||||
var scheme SigScheme
|
||||
if err := UnpackBuf(in, &scheme.Alg); err != nil {
|
||||
return nil, fmt.Errorf("decoding Alg: %v", err)
|
||||
}
|
||||
if scheme.Alg == AlgNull {
|
||||
return nil, nil
|
||||
}
|
||||
if err := UnpackBuf(in, &scheme.Hash); err != nil {
|
||||
return nil, fmt.Errorf("decoding Hash: %v", err)
|
||||
}
|
||||
if scheme.Alg.UsesCount() {
|
||||
if err := UnpackBuf(in, &scheme.Count); err != nil {
|
||||
return nil, fmt.Errorf("decoding Count: %v", err)
|
||||
}
|
||||
}
|
||||
return &scheme, nil
|
||||
}
|
||||
|
||||
// UsesCount returns true if a signature algorithm uses count value.
|
||||
func (a Algorithm) UsesCount() bool {
|
||||
return a == AlgECDAA
|
||||
}
|
||||
|
||||
func decodeKDFScheme(in *bytes.Buffer) (*KDFScheme, error) {
|
||||
var scheme KDFScheme
|
||||
if err := UnpackBuf(in, &scheme.Alg); err != nil {
|
||||
return nil, fmt.Errorf("decoding Alg: %v", err)
|
||||
}
|
||||
if scheme.Alg == AlgNull {
|
||||
return nil, nil
|
||||
}
|
||||
if err := UnpackBuf(in, &scheme.Hash); err != nil {
|
||||
return nil, fmt.Errorf("decoding Hash: %v", err)
|
||||
}
|
||||
return &scheme, nil
|
||||
}
|
||||
func decodeSymScheme(in *bytes.Buffer) (*SymScheme, error) {
|
||||
var scheme SymScheme
|
||||
if err := UnpackBuf(in, &scheme.Alg); err != nil {
|
||||
return nil, fmt.Errorf("decoding Alg: %v", err)
|
||||
}
|
||||
if scheme.Alg == AlgNull {
|
||||
return nil, nil
|
||||
}
|
||||
if err := UnpackBuf(in, &scheme.KeyBits, &scheme.Mode); err != nil {
|
||||
return nil, fmt.Errorf("decoding KeyBits, Mode: %v", err)
|
||||
}
|
||||
return &scheme, nil
|
||||
}
|
||||
func decodeECCParams(in *bytes.Buffer) (*ECCParams, error) {
|
||||
var params ECCParams
|
||||
var err error
|
||||
|
||||
if params.Symmetric, err = decodeSymScheme(in); err != nil {
|
||||
return nil, fmt.Errorf("decoding Symmetric: %v", err)
|
||||
}
|
||||
if params.Sign, err = decodeSigScheme(in); err != nil {
|
||||
return nil, fmt.Errorf("decoding Sign: %v", err)
|
||||
}
|
||||
if err := UnpackBuf(in, ¶ms.CurveID); err != nil {
|
||||
return nil, fmt.Errorf("decoding CurveID: %v", err)
|
||||
}
|
||||
if params.KDF, err = decodeKDFScheme(in); err != nil {
|
||||
return nil, fmt.Errorf("decoding KDF: %v", err)
|
||||
}
|
||||
var x, y []byte
|
||||
if err := UnpackBuf(in, &x, &y); err != nil {
|
||||
return nil, fmt.Errorf("decoding Point: %v", err)
|
||||
}
|
||||
params.Point.X = new(big.Int).SetBytes(x)
|
||||
params.Point.Y = new(big.Int).SetBytes(y)
|
||||
return ¶ms, nil
|
||||
}
|
||||
|
||||
// ECCParams represents parameters of an ECC key pair.
|
||||
//
|
||||
// Symmetric, Sign and KDF may be nil, depending on key Attributes in Public.
|
||||
type ECCParams struct {
|
||||
Symmetric *SymScheme
|
||||
Sign *SigScheme
|
||||
CurveID EllipticCurve
|
||||
KDF *KDFScheme
|
||||
Point ECPoint
|
||||
}
|
||||
|
||||
// EllipticCurve identifies specific EC curves.
|
||||
type EllipticCurve uint16
|
||||
|
||||
// ECC curves supported by TPM 2.0 spec.
|
||||
const (
|
||||
CurveNISTP192 = EllipticCurve(iota + 1)
|
||||
CurveNISTP224
|
||||
CurveNISTP256
|
||||
CurveNISTP384
|
||||
CurveNISTP521
|
||||
|
||||
CurveBNP256 = EllipticCurve(iota + 10)
|
||||
CurveBNP638
|
||||
|
||||
CurveSM2P256 = EllipticCurve(0x0020)
|
||||
)
|
||||
|
||||
// ECPoint represents a ECC coordinates for a point.
|
||||
type ECPoint struct {
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
// KDFScheme represents a KDF (Key Derivation Function) scheme.
|
||||
type KDFScheme struct {
|
||||
Alg Algorithm
|
||||
Hash Algorithm
|
||||
}
|
||||
Reference in New Issue
Block a user