rebase: vendor files required for kmip

Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
Rakshith R
2022-08-16 15:18:06 +05:30
committed by mergify[bot]
parent 0c33a33d5c
commit e72ed593be
186 changed files with 39195 additions and 203 deletions

6
vendor/github.com/gemalto/kmip-go/.dockerignore generated vendored Normal file
View File

@ -0,0 +1,6 @@
.idea
.git
Dockerfile
docker-compose.yml
.dockerignore
build

6
vendor/github.com/gemalto/kmip-go/.gitignore generated vendored Normal file
View File

@ -0,0 +1,6 @@
.idea
scratch
build
vendor
/pykmip-server/server.log
/pykmip-server/server.db

235
vendor/github.com/gemalto/kmip-go/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,235 @@
# This file contains all available configuration options
# with their default values.
# options for analysis running
run:
tests: true
skip-files:
- requests.go
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: colored-line-number
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
print-linter-name: true
# all available settings of specific linters
linters-settings:
govet:
# report about shadowed variables
check-shadowing: false
dupl:
# tokens count to trigger issue, 150 by default
threshold: 100
exhaustive:
default-signifies-exhaustive: true
goconst:
# minimal length of string constant, 3 by default
min-len: 3
# minimal occurrences count to trigger, 3 by default
min-occurrences: 3
depguard:
list-type: blacklist
include-go-root: false
packages:
- github.com/magiconair/properties/assert
- gopkg.in/go-playground/assert.v1
- github.com/pborman/uuid #replace with github.com/google/uuid
inTests:
- github.com/davecgh/go-spew/spew
- github.com/stretchr/testify
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
gocritic:
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
disabled-checks:
- commentFormatting
revive:
ignore-generated-header: true
wsl:
allow-cuddle-declarations: true
allow-separated-leading-comment: true
allow-assign-and-anything: true
linters:
# to try out individual linters: golangci-lint run -E gocyclo,gosimple
enable:
# default linters
- staticcheck
- deadcode
- errcheck
- gosimple
- govet
- ineffassign
- structcheck
- unused
- varcheck
# additional linters
- asciicheck
- bidichk
## - bodyclose # its all false positives with requester and sling, which both close the body already
- containedctx
- contextcheck
# - cyclop # need to analyze findings
- decorder
- depguard
## - dogsled # checks for too many blank identifiers. don't care
- dupl
- durationcheck
- errchkjson
- errname
- errorlint
- exhaustive
- exportloopref
- forbidigo
- forcetypeassert
## - funlen # checks function length. don't care
# - gci # not sure why this is complaining
## - gochecknoglobals # too common
- gochecknoinits
# - gocognit # too many findings, will take time to evaluate
- goconst
- gocritic
## - gocyclo # checks cyclomatic complexity. don't care
# - godot # too many false positives
# - godox # doesn't allow TODO comments. We allow those to be committed.
# - goerr113 # good practice, but it doesn't recognize that we're already wrapping errors with merry
## - gofmt # checks code is formatted, handled by make prep
- gofumpt
- goheader
## - goimports # checks import order. We're not using goimports
# - gomnd # too aggressive
- gomoddirectives
# - gomodguard
- goprintffuncname
- gosec
- grouper
- ifshort
- importas
# - ireturn # there are valid use cases for this pattern. too strict.
## - lll # checks line length. not enforced
# - maintidx # look at this later
- makezero
## - maligned # optimizies struct field order, but structs are usually ordered for legibility
- misspell
- nakedret
# - nestif # need to evaluate the findings
- nilerr
- nilnil
# - nlreturn # a little too aggressive. wsl covers the same ground.
- noctx
- nolintlint
# - paralleltest # look at this later
# - prealloc # slice optimizations, but promotes too much premature optimization
- predeclared
- promlinter
- revive
- rowserrcheck
- sqlclosecheck
- stylecheck
- tagliatelle
- thelper
- tparallel
- unconvert
- unparam
# - varnamelen # take a look later
- wastedassign
- whitespace
# - wrapcheck # way too aggressive
- wsl
## - unparam # too many false positives
## - whitespace # not enforced
disable-all: true
# presets:
# - bugs
# - unused
# fast: false
issues:
# List of regexps of issue texts to exclude, empty list by default.
# But independently from this option we use default exclude patterns,
# it can be disabled by `exclude-use-default: false`. To list all
# excluded by default patterns execute `golangci-lint run --help`
# exclude:
# - abcdef
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
# Explicitly exclude the typecheck plugin. There is some bug in golangci which is
# enabling this checker, even though it isn't listed above.
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- exportloopref
- gochecknoinits
- gochecknoglobals
- wsl
- nlreturn
- errchkjson
- forcetypeassert
- path: cmd
linters:
# init(), globals, and prints are pretty common in main packages
- gochecknoinits
- gochecknoglobals
- forbidigo
# Exclude known linters from partially hard-vendored code,
# which is impossible to exclude via "nolint" comments.
# - path: internal/hmac/
# text: "weak cryptographic primitive"
# linters:
# - gosec
# Exclude some staticcheck messages
# - linters:
# - staticcheck
# text: "SA9003:"
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
# Default value for this option is true.
# exclude-use-default: false
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
# max-issues-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
# max-same-issues: 0
# Show only new issues: if there are unstaged changes or untracked files,
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
# It's a super-useful option for integration of golangci-lint into existing
# large codebase. It's not practical to fix all existing issues at the moment
# of integration: much better don't allow issues in new code.
# Default is false.
new: false
# Show only new issues created after git revision `REV`
# new-from-rev: REV
# Show only new issues created in git patch with set file path.
# new-from-patch: path/to/patch/file

10
vendor/github.com/gemalto/kmip-go/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,10 @@
FROM golang:alpine
RUN apk --no-cache add make git curl bash fish
WORKDIR /project
COPY ./ /project
RUN make tools
CMD make

21
vendor/github.com/gemalto/kmip-go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Gemalto OSS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

104
vendor/github.com/gemalto/kmip-go/Makefile generated vendored Normal file
View File

@ -0,0 +1,104 @@
SHELL = bash
BUILD_FLAGS =
TEST_FLAGS =
COMPOSE ?= docker-compose
all: fmt build up test lint
build:
go build $(BUILD_FLAGS) ./...
builddir:
mkdir -p -m 0777 build
install:
go install ./cmd/ppkmip
go install ./cmd/kmipgen
ppkmip: builddir
GOOS=darwin GOARCH=amd64 go build -o build/ppkmip-macos ./cmd/ppkmip
GOOS=windows GOARCH=amd64 go build -o build/ppkmip-windows.exe ./cmd/ppkmip
GOOS=linux GOARCH=amd64 go build -o build/ppkmip-linux ./cmd/ppkmip
kmipgen:
go install ./cmd/kmipgen
lint:
golangci-lint run
clean:
rm -rf build/*
fmt:
gofumpt -w -l .
# generates go code structures representing all the enums, mask, and tags defined
# in the KMIP spec. The source specifications are stored in kmip14/kmip_1_4.json
# and ttls/kmip20/kmip_2_0_additions.json. The generated .go files are named *_generated.go
#
# the kmipgen tool (defined in cmd/kmipgen) is used to generate the source. This tool can
# be used independently to generate source for future specs or vendor extensions.
#
# this target only needs to be run if the json files are changed. The generated
# go files should be committed to source control.
generate:
go generate ./...
test:
go test $(BUILD_FLAGS) $(TEST_FLAGS) ./...
# creates a test coverage report, and produces json test output. useful for ci.
cover: builddir
go test $(TEST_FLAGS) -v -covermode=count -coverprofile=build/coverage.out -json ./...
go tool cover -html=build/coverage.out -o build/coverage.html
# brings up the projects dependencies in a compose stack
up:
$(COMPOSE) build --pull pykmip-server
$(COMPOSE) run --rm dependencies
# brings down the projects dependencies
down:
$(COMPOSE) down -v --remove-orphans
# runs the build inside a docker container. useful for ci to completely encapsulate the
# build environment.
docker:
$(COMPOSE) build --pull builder
$(COMPOSE) run --rm builder make all cover
# opens a shell into the build environment container. Useful for troubleshooting the
# containerized build.
bash:
$(COMPOSE) build --pull builder
$(COMPOSE) run --rm builder bash
# opens a shell into the build environment container. Useful for troubleshooting the
# containerized build.
fish:
$(COMPOSE) build --pull builder
$(COMPOSE) run --rm builder fish
tidy:
go mod tidy
# use go mod to update all dependencies
update:
go get -u ./...
go mod tidy
# install tools used by the build. typically only needs to be run once
# to initialize a workspace.
tools: kmipgen
go install mvdan.cc/gofumpt@latest
go install golang.org/x/tools/cmd/cover@latest
sh -c "$$(wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh || echo exit 2)" -- -b $(shell go env GOPATH)/bin $(GOLANGCI_LINT_VERSION)
pykmip-server: up
$(COMPOSE) exec pykmip-server tail -f server.log
gen-certs:
openssl req -x509 -newkey rsa:4096 -keyout pykmip-server/server.key -out pykmip-server/server.cert -days 3650 -nodes -subj '/CN=localhost'
.PHONY: all build builddir run artifacts vet lint clean fmt test testall testreport up down pull builder runc ci bash fish image prep vendor.update vendor.ensure tools buildtools migratetool db.migrate

50
vendor/github.com/gemalto/kmip-go/README.md generated vendored Normal file
View File

@ -0,0 +1,50 @@
kmip-go [![GoDoc](https://godoc.org/github.com/gemalto/kmip-go?status.png)](https://godoc.org/github.com/gemalto/kmip-go) [![Go Report Card](https://goreportcard.com/badge/github.com/gemalto/kmip-go)](https://goreportcard.com/report/gemalto/kmip-go) [![Build](https://github.com/gemalto/kmip-go/workflows/Build/badge.svg)](https://github.com/gemalto/kmip-go/actions?query=branch%3Amaster+workflow%3ABuild+)
=======
kmip-go is a go implemenation of KMIP protocol primitives. It supports marshaling data in TTLV, XML, or JSON
encodings to and from go values and structs. It can be used to implement KMIP clients or servers.
Installation
------------
go get github.com/gemalto/kmip-go
Or, to just install the `ppkmip` pretty printing tool:
go install github.com/gemalto/kmip-go/cmd/ppkmip
Packages
--------
The `ttlv` package implements the core encoder and decoder logic.
The `kmip14` package contains constants for all the tags, types, enumerations and bitmasks defined in the KMIP 1.4
specification. It also contains mappings from these values to the normalized names used in the JSON and XML
encodings, and the canonical names used in Attribute structures.
The `kmip14` definitions are all automatically registered with `ttlv.DefaultRegistry`.
The `kmip20` package adds additional enumeration values from the 2.0 specification. It is meant to be registered
on top of the 1.4 definitions.
The root package defines golang structures for some of the significant Structure definitions in the 1.4
specification, like Attributes, Request, Response, etc. It is incomplete, but can be used as an example
for defining other structures. It also contains an example of a client and server.
`cmd/kmipgen` is a code generation tool which generates the tag and enum constants from a JSON specification
input. It can also be used independently in your own code to generate additional tags and constants. `make install`
to build and install the tool. See `kmip14/kmip_1_4.go` for an example of using the tool.
`cmd/kmipgen` is a tool for pretty printing kmip values. It can accept KMIP input from stdin or files, encoded
in TTLV, XML, or JSON, and output in a variety of formats. `make install` to intall the tool, and
`ppkmip --help` to see usage.
Contributing
------------
To build, be sure to have a recent go SDK, and make. Run `make tools` to install other dependencies.
There is also a dockerized build, which only requires make and docker-compose: `make docker`. You can also
do `make fish` or `make bash` to shell into the docker build container.
Merge requests are welcome! Before submitting, please run `make` and make sure all tests pass and there are
no linter findings.

70
vendor/github.com/gemalto/kmip-go/attributes.go generated vendored Normal file
View File

@ -0,0 +1,70 @@
package kmip
import (
"github.com/gemalto/kmip-go/kmip14"
)
// 3
// Name 3.2 Table 57
//
// The Name attribute is a structure (see Table 57) used to identify and locate an object.
// This attribute is assigned by the client, and the Name Value is intended to be in a form that
// humans are able to interpret. The key management system MAY specify rules by which the client
// creates valid names. Clients are informed of such rules by a mechanism that is not specified by
// this standard. Names SHALL be unique within a given key management domain,
// but are NOT REQUIRED to be globally unique.
type Name struct {
NameValue string
NameType kmip14.NameType
}
// Cryptographic Parameters 3.6 Table 65
//
// The Cryptographic Parameters attribute is a structure (see Table 65) that contains a set of OPTIONAL
// fields that describe certain cryptographic parameters to be used when performing cryptographic operations
// using the object. Specific fields MAY pertain only to certain types of Managed Cryptographic Objects. The
// Cryptographic Parameters attribute of a Certificate object identifies the cryptographic parameters of the
// public key contained within the Certificate.
//
// The Cryptographic Algorithm is also used to specify the parameters for cryptographic operations. For operations
// involving digital signatures, either the Digital Signature Algorithm can be specified or the Cryptographic
// Algorithm and Hashing Algorithm combination can be specified.
//
// Random IV can be used to request that the KMIP server generate an appropriate IV for a
// cryptographic operation that uses an IV. The generated Random IV is returned in the response
// to the cryptographic operation.
//
// IV Length is the length of the Initialization Vector in bits. This parameter SHALL be provided when the
// specified Block Cipher Mode supports variable IV lengths such as CTR or GCM.
//
// Tag Length is the length of the authentication tag in bytes. This parameter SHALL be provided when the
// Block Cipher Mode is GCM or CCM.
//
// The IV used with counter modes of operation (e.g., CTR and GCM) cannot repeat for a given cryptographic key.
// To prevent an IV/key reuse, the IV is often constructed of three parts: a fixed field, an invocation field,
// and a counter as described in [SP800-38A] and [SP800-38D]. The Fixed Field Length is the length of the fixed
// field portion of the IV in bits. The Invocation Field Length is the length of the invocation field portion of
// the IV in bits. The Counter Length is the length of the counter portion of the IV in bits.
//
// Initial Counter Value is the starting counter value for CTR mode (for [RFC3686] it is 1).
type CryptographicParameters struct {
BlockCipherMode kmip14.BlockCipherMode `ttlv:",omitempty"`
PaddingMethod kmip14.PaddingMethod `ttlv:",omitempty"`
HashingAlgorithm kmip14.HashingAlgorithm `ttlv:",omitempty"`
KeyRoleType kmip14.KeyRoleType `ttlv:",omitempty"`
DigitalSignatureAlgorithm kmip14.DigitalSignatureAlgorithm `ttlv:",omitempty"`
CryptographicAlgorithm kmip14.CryptographicAlgorithm `ttlv:",omitempty"`
RandomIV bool `ttlv:",omitempty"`
IVLength int `ttlv:",omitempty"`
TagLength int `ttlv:",omitempty"`
FixedFieldLength int `ttlv:",omitempty"`
InvocationFieldLength int `ttlv:",omitempty"`
CounterLength int `ttlv:",omitempty"`
InitialCounterValue int `ttlv:",omitempty"`
SaltLength int `ttlv:",omitempty"`
MaskGenerator kmip14.MaskGenerator `ttlv:",omitempty" default:"1"` // defaults to MGF1
MaskGeneratorHashingAlgorithm kmip14.HashingAlgorithm `ttlv:",omitempty" default:"4"` // defaults to SHA-1
PSource []byte `ttlv:",omitempty"`
TrailerField int `ttlv:",omitempty"`
}

473
vendor/github.com/gemalto/kmip-go/base_objects.go generated vendored Normal file
View File

@ -0,0 +1,473 @@
package kmip
import (
"math/big"
"github.com/gemalto/kmip-go/kmip14"
"github.com/gemalto/kmip-go/ttlv"
)
// 2.1 Base Objects
//
// These objects are used within the messages of the protocol, but are not objects managed by the key
// management system. They are components of Managed Objects.
// Attribute 2.1.1 Table 2
//
// An Attribute object is a structure (see Table 2) used for sending and receiving Managed Object attributes.
// The Attribute Name is a text-string that is used to identify the attribute. The Attribute Index is an index
// number assigned by the key management server. The Attribute Index is used to identify the particular instance.
// Attribute Indices SHALL start with 0. The Attribute Index of an attribute SHALL NOT change when other instances
// are added or deleted. Single-instance Attributes (attributes which an object MAY only have at most one instance
// thereof) SHALL have an Attribute Index of 0. The Attribute Value is either a primitive data type or structured
// object, depending on the attribute.
//
// When an Attribute structure is used to specify or return a particular instance of an Attribute and the Attribute
// Index is not specified it SHALL be assumed to be 0.
type Attribute struct {
// AttributeName should contain the canonical name of a tag, e.g. "Cryptographic Algorithm"
AttributeName string
// AttributeIndex is typically 0 when clients use this struct to create objects or add attributes. Clients
// only need to set this if modifying or deleting an existing attribute.
AttributeIndex int `ttlv:",omitempty"`
AttributeValue interface{}
}
func NewAttributeFromTag(tag ttlv.Tag, idx int, val interface{}) Attribute {
return Attribute{
AttributeName: tag.CanonicalName(),
AttributeIndex: idx,
AttributeValue: val,
}
}
// Credential 2.1.2 Table 3
//
// A Credential is a structure (see Table 3) used for client identification purposes and is not managed by the
// key management system (e.g., user id/password pairs, Kerberos tokens, etc.). It MAY be used for authentication
// purposes as indicated in [KMIP-Prof].
//
// TODO: add an unmarshal impl to Credential to handle decoding the right kind
// of credential based on the credential type value
type Credential struct {
CredentialType kmip14.CredentialType
CredentialValue interface{}
}
// UsernameAndPasswordCredentialValue 2.1.2 Table 4
//
// If the Credential Type in the Credential is Username and Password, then Credential Value is a
// structure as shown in Table 4. The Username field identifies the client, and the Password field
// is a secret that authenticates the client.
type UsernameAndPasswordCredentialValue struct {
Username string
Password string `ttlv:",omitempty"`
}
// DeviceCredentialValue 2.1.2 Table 5
//
// If the Credential Type in the Credential is Device, then Credential Value is a structure as shown in
// Table 5. One or a combination of the Device Serial Number, Network Identifier, Machine Identifier,
// and Media Identifier SHALL be unique. Server implementations MAY enforce policies on uniqueness for
// individual fields. A shared secret or password MAY also be used to authenticate the client.
// The client SHALL provide at least one field.
type DeviceCredentialValue struct {
DeviceSerialNumber string `ttlv:",omitempty"`
Password string `ttlv:",omitempty"`
DeviceIdentifier string `ttlv:",omitempty"`
NetworkIdentifier string `ttlv:",omitempty"`
MachineIdentifier string `ttlv:",omitempty"`
MediaIdentifier string `ttlv:",omitempty"`
}
// AttestationCredentialValue 2.1.2 Table 6
//
// If the Credential Type in the Credential is Attestation, then Credential Value is a structure
// as shown in Table 6. The Nonce Value is obtained from the key management server in a Nonce Object.
// The Attestation Credential Object can contain a measurement from the client or an assertion from a
// third party if the server is not capable or willing to verify the attestation data from the client.
// Neither type of attestation data (Attestation Measurement or Attestation Assertion) is necessary to
// allow the server to accept either. However, the client SHALL provide attestation data in either the
// Attestation Measurement or Attestation Assertion fields.
type AttestationCredentialValue struct {
Nonce Nonce
AttestationType kmip14.AttestationType
AttestationMeasurement []byte `ttlv:",omitempty"`
AttestationAssertion []byte `ttlv:",omitempty"`
}
// KeyBlock 2.1.3 Table 7
//
// A Key Block object is a structure (see Table 7) used to encapsulate all of the information that is
// closely associated with a cryptographic key. It contains a Key Value of one of the following Key Format Types:
//
// · Raw This is a key that contains only cryptographic key material, encoded as a string of bytes.
// · Opaque This is an encoded key for which the encoding is unknown to the key management system.
// It is encoded as a string of bytes.
// · PKCS1 This is an encoded private key, expressed as a DER-encoded ASN.1 PKCS#1 object.
// · PKCS8 This is an encoded private key, expressed as a DER-encoded ASN.1 PKCS#8 object, supporting both
// the RSAPrivateKey syntax and EncryptedPrivateKey.
// · X.509 This is an encoded object, expressed as a DER-encoded ASN.1 X.509 object.
// · ECPrivateKey This is an ASN.1 encoded elliptic curve private key.
// · Several Transparent Key types These are algorithm-specific structures containing defined values
// for the various key types, as defined in Section 2.1.7.
// · Extensions These are vendor-specific extensions to allow for proprietary or legacy key formats.
//
// The Key Block MAY contain the Key Compression Type, which indicates the format of the elliptic curve public
// key. By default, the public key is uncompressed.
//
// The Key Block also has the Cryptographic Algorithm and the Cryptographic Length of the key contained
// in the Key Value field. Some example values are:
//
// · RSA keys are typically 1024, 2048 or 3072 bits in length.
// · 3DES keys are typically from 112 to 192 bits (depending upon key length and the presence of parity bits).
// · AES keys are 128, 192 or 256 bits in length.
//
// The Key Block SHALL contain a Key Wrapping Data structure if the key in the Key Value field is
// wrapped (i.e., encrypted, or MACed/signed, or both).
type KeyBlock struct {
KeyFormatType kmip14.KeyFormatType
KeyCompressionType kmip14.KeyCompressionType `ttlv:",omitempty"`
KeyValue *KeyValue `ttlv:",omitempty"`
CryptographicAlgorithm kmip14.CryptographicAlgorithm `ttlv:",omitempty"`
CryptographicLength int `ttlv:",omitempty"`
KeyWrappingData *KeyWrappingData
}
// KeyValue 2.1.4 Table 8
//
// The Key Value is used only inside a Key Block and is either a Byte String or a structure (see Table 8):
//
// · The Key Value structure contains the key material, either as a byte string or as a Transparent Key
// structure (see Section 2.1.7), and OPTIONAL attribute information that is associated and encapsulated
// with the key material. This attribute information differs from the attributes associated with Managed
// Objects, and is obtained via the Get Attributes operation, only by the fact that it is encapsulated with
// (and possibly wrapped with) the key material itself.
// · The Key Value Byte String is either the wrapped TTLV-encoded (see Section 9.1) Key Value structure, or
// the wrapped un-encoded value of the Byte String Key Material field.
//
// TODO: Unmarshaler impl which unmarshals correct KeyMaterial type.
type KeyValue struct {
// KeyMaterial should be []byte, one of the Transparent*Key structs, or a custom struct if KeyFormatType is
// an extension.
KeyMaterial interface{}
Attribute []Attribute
}
// KeyWrappingData 2.1.5 Table 9
//
// The Key Block MAY also supply OPTIONAL information about a cryptographic key wrapping mechanism used
// to wrap the Key Value. This consists of a Key Wrapping Data structure (see Table 9). It is only used
// inside a Key Block.
//
// This structure contains fields for:
//
// · A Wrapping Method, which indicates the method used to wrap the Key Value.
// · Encryption Key Information, which contains the Unique Identifier (see 3.1) value of the encryption key
// and associated cryptographic parameters.
// · MAC/Signature Key Information, which contains the Unique Identifier value of the MAC/signature key
// and associated cryptographic parameters.
// · A MAC/Signature, which contains a MAC or signature of the Key Value.
// · An IV/Counter/Nonce, if REQUIRED by the wrapping method.
// · An Encoding Option, specifying the encoding of the Key Material within the Key Value structure of the
// Key Block that has been wrapped. If No Encoding is specified, then the Key Value structure SHALL NOT contain
// any attributes.
//
// If wrapping is used, then the whole Key Value structure is wrapped unless otherwise specified by the
// Wrapping Method. The algorithms used for wrapping are given by the Cryptographic Algorithm attributes of
// the encryption key and/or MAC/signature key; the block-cipher mode, padding method, and hashing algorithm used
// for wrapping are given by the Cryptographic Parameters in the Encryption Key Information and/or MAC/Signature
// Key Information, or, if not present, from the Cryptographic Parameters attribute of the respective key(s).
// Either the Encryption Key Information or the MAC/Signature Key Information (or both) in the Key Wrapping Data
// structure SHALL be specified.
//
// The following wrapping methods are currently defined:
//
// · Encrypt only (i.e., encryption using a symmetric key or public key, or authenticated encryption algorithms that use a single key).
// · MAC/sign only (i.e., either MACing the Key Value with a symmetric key, or signing the Key Value with a private key).
// · Encrypt then MAC/sign.
// · MAC/sign then encrypt.
// · TR-31.
// · Extensions.
//
// The following encoding options are currently defined:
//
// · No Encoding (i.e., the wrapped un-encoded value of the Byte String Key Material field in the Key Value structure).
// · TTLV Encoding (i.e., the wrapped TTLV-encoded Key Value structure).
type KeyWrappingData struct {
WrappingMethod kmip14.WrappingMethod
EncryptionKeyInformation *EncryptionKeyInformation
MACSignatureKeyInformation *MACSignatureKeyInformation
MACSignature []byte
IVCounterNonce []byte
EncodingOption kmip14.EncodingOption `ttlv:",omitempty" default:"TTLVEncoding"`
}
// EncryptionKeyInformation 2.1.5 Table 10
type EncryptionKeyInformation struct {
UniqueIdentifier string
CryptographicParameters *CryptographicParameters
}
// MACSignatureKeyInformation 2.1.5 Table 11
type MACSignatureKeyInformation struct {
UniqueIdentifier string
CryptographicParameters *CryptographicParameters
}
// TransparentSymmetricKey 2.1.7.1 Table 14
//
// If the Key Format Type in the Key Block is Transparent Symmetric Key, then Key Material is a
// structure as shown in Table 14.
type TransparentSymmetricKey struct {
Key []byte `validate:"required"`
}
// TransparentDSAPrivateKey 2.1.7.2 Table 15
//
// If the Key Format Type in the Key Block is Transparent DSA Private Key, then Key Material is a structure as
// shown in Table 15.
type TransparentDSAPrivateKey struct {
// TODO: should these be pointers? big package deals entirely with pointers, but these are not optional values.
P *big.Int `validate:"required"`
Q *big.Int `validate:"required"`
G *big.Int `validate:"required"`
X *big.Int `validate:"required"`
}
// TransparentDSAPublicKey 2.1.7.3 Table 16
//
// If the Key Format Type in the Key Block is Transparent DSA Public Key, then Key Material is a structure as
// shown in Table 16.
type TransparentDSAPublicKey struct {
P *big.Int `validate:"required"`
Q *big.Int `validate:"required"`
G *big.Int `validate:"required"`
Y *big.Int `validate:"required"`
}
// TransparentRSAPrivateKey 2.1.7.4 Table 17
//
// If the Key Format Type in the Key Block is Transparent RSA Private Key, then Key Material is a structure
// as shown in Table 17.
//
// One of the following SHALL be present (refer to [PKCS#1]):
//
// · Private Exponent,
// · P and Q (the first two prime factors of Modulus), or
// · Prime Exponent P and Prime Exponent Q.
type TransparentRSAPrivateKey struct {
Modulus *big.Int `validate:"required"`
PrivateExponent, PublicExponent *big.Int
P, Q *big.Int
PrimeExponentP, PrimeExponentQ *big.Int
CRTCoefficient *big.Int
}
// TransparentRSAPublicKey 2.1.7.5 Table 18
//
// If the Key Format Type in the Key Block is Transparent RSA Public Key, then Key Material is a structure
// as shown in Table 18.
type TransparentRSAPublicKey struct {
Modulus *big.Int `validate:"required"`
PublicExponent *big.Int `validate:"required"`
}
// TransparentDHPrivateKey 2.1.7.6 Table 19
//
// If the Key Format Type in the Key Block is Transparent DH Private Key, then Key Material is a structure as shown
// in Table 19.
type TransparentDHPrivateKey struct {
P *big.Int `validate:"required"`
Q *big.Int
G *big.Int `validate:"required"`
J *big.Int
X *big.Int `validate:"required"`
}
// TransparentDHPublicKey 2.1.7.7 Table 20
//
// If the Key Format Type in the Key Block is Transparent DH Public Key, then Key Material is a structure as
// shown in Table 20.
//
// P, G, and Y are required.
type TransparentDHPublicKey struct {
P *big.Int `validate:"required"`
Q *big.Int
G *big.Int `validate:"required"`
J *big.Int
Y *big.Int `validate:"required"`
}
// TransparentECDSAPrivateKey 2.1.7.8 Table 21
//
// The Transparent ECDSA Private Key structure is deprecated as of version 1.3 of this
// specification and MAY be removed from subsequent versions of the specification. The
// Transparent EC Private Key structure SHOULD be used as a replacement.
//
// If the Key Format Type in the Key Block is Transparent ECDSA Private Key, then Key Material is a
// structure as shown in Table 21.
type TransparentECDSAPrivateKey struct {
RecommendedCurve kmip14.RecommendedCurve
D *big.Int `validate:"required"`
}
// TransparentECDSAPublicKey 2.1.7.9 Table 22
//
// The Transparent ECDSA Public Key structure is deprecated as of version 1.3 of this specification and
// MAY be removed from subsequent versions of the specification. The Transparent EC Public Key structure
// SHOULD be used as a replacement.
//
// If the Key Format Type in the Key Block is Transparent ECDSA Public Key, then Key Material is a
// structure as shown in Table 22.
type TransparentECDSAPublicKey struct {
RecommendedCurve kmip14.RecommendedCurve
QString []byte `validate:"required"`
}
// TransparentECDHPrivateKey 2.1.7.10 Table 23
//
// The Transparent ECDH Private Key structure is deprecated as of version 1.3 of this specification and
// MAY be removed from subsequent versions of the specification. The Transparent EC Private Key structure
// SHOULD be used as a replacement.
//
// If the Key Format Type in the Key Block is Transparent ECDH Private Key, then Key Material is a structure
// as shown in Table 23.
type TransparentECDHPrivateKey TransparentECPrivateKey
// TransparentECDHPublicKey 2.1.7.11 Table 24
//
// The Transparent ECDH Public Key structure is deprecated as of version 1.3 of this specification and MAY
// be removed from subsequent versions of the specification. The Transparent EC Public Key structure SHOULD
// be used as a replacement.
//
// If the Key Format Type in the Key Block is Transparent ECDH Public Key, then Key Material is a structure as
// shown in Table 24.
type TransparentECDHPublicKey TransparentECPublicKey
// TransparentECMQVPrivateKey 2.1.7.12 Table 25
//
// The Transparent ECMQV Private Key structure is deprecated as of version 1.3 of this specification and MAY
// be removed from subsequent versions of the specification. The Transparent EC Private Key structure SHOULD
// be used as a replacement.
//
// If the Key Format Type in the Key Block is Transparent ECMQV Private Key, then Key Material is a structure
// as shown in Table 25.
type TransparentECMQVPrivateKey TransparentECPrivateKey
// TransparentECMQVPublicKey 2.1.7.13 Table 26
//
// The Transparent ECMQV Public Key structure is deprecated as of version 1.3 of this specification and MAY be
// removed from subsequent versions of the specification. The Transparent EC Public Key structure SHOULD be used as
// a replacement.
//
// If the Key Format Type in the Key Block is Transparent ECMQV Public Key, then Key Material is a structure as shown
// in Table 26.
type TransparentECMQVPublicKey TransparentECPublicKey
// TransparentECPrivateKey 2.1.7.14 Table 27
//
// If the Key Format Type in the Key Block is Transparent EC Private Key, then Key Material is a structure as shown
// in Table 27.
type TransparentECPrivateKey struct {
RecommendedCurve kmip14.RecommendedCurve
D *big.Int `validate:"required"`
}
// TransparentECPublicKey 2.1.7.15 Table 28
//
// If the Key Format Type in the Key Block is Transparent EC Public Key, then Key Material is a structure as
// shown in Table 28.
type TransparentECPublicKey struct {
RecommendedCurve kmip14.RecommendedCurve
QString []byte `validate:"required"`
}
// TemplateAttribute 2.1.8 Table 29
//
// The Template Managed Object is deprecated as of version 1.3 of this specification and MAY be removed from
// subsequent versions of the specification. Individual Attributes SHOULD be used in operations which currently
// support use of a Name within a Template-Attribute to reference a Template.
//
// These structures are used in various operations to provide the desired attribute values and/or template
// names in the request and to return the actual attribute values in the response.
//
// The Template-Attribute, Common Template-Attribute, Private Key Template-Attribute, and Public Key
// Template-Attribute structures are defined identically as follows:
// type TemplateAttribute struct {
// Attribute []Attribute
// }
type TemplateAttribute struct {
Name []Name
Attribute []Attribute
}
// Get returns a reference to the first Attribute in the list matching the name.
// Returns nil if not found.
func (t *TemplateAttribute) Get(s string) *Attribute {
if t == nil {
return nil
}
for i := range t.Attribute {
if t.Attribute[i].AttributeName == s {
return &t.Attribute[i]
}
}
return nil
}
// GetIdx returns a reference to the Attribute in the list matching the name and index.
// Returns nil if not found.
func (t *TemplateAttribute) GetIdx(s string, idx int) *Attribute {
if t == nil {
return nil
}
for i := range t.Attribute {
if t.Attribute[i].AttributeName == s && t.Attribute[i].AttributeIndex == idx {
return &t.Attribute[i]
}
}
return nil
}
// GetTag returns a reference to the first Attribute in the list matching the tag.
// Returns nil if not found.
func (t *TemplateAttribute) GetTag(tag ttlv.Tag) *Attribute {
return t.Get(tag.String())
}
// GetTagIdx returns a reference to the first Attribute in the list matching the tag and index.
// Returns nil if not found.
func (t *TemplateAttribute) GetTagIdx(tag ttlv.Tag, idx int) *Attribute {
return t.GetIdx(tag.String(), idx)
}
func (t *TemplateAttribute) GetAll(s string) []Attribute {
if t == nil {
return nil
}
var ret []Attribute
for i := range t.Attribute {
if t.Attribute[i].AttributeName == s {
ret = append(ret, t.Attribute[i])
}
}
return ret
}
func (t *TemplateAttribute) Append(tag ttlv.Tag, value interface{}) {
t.Attribute = append(t.Attribute, NewAttributeFromTag(tag, 0, value))
}
func (t *TemplateAttribute) GetAllTag(tag ttlv.Tag) []Attribute {
return t.GetAll(tag.String())
}

22
vendor/github.com/gemalto/kmip-go/docker-compose.yml generated vendored Normal file
View File

@ -0,0 +1,22 @@
version: '3'
services:
builder:
build:
context: .
environment:
CGO_ENABLED: 0
volumes:
- ./build:/project/build
dependencies:
image: waisbrot/wait
environment:
TARGETS: pykmip-server:5696
depends_on:
- pykmip-server
pykmip-server:
build:
context: pykmip-server
ports:
- 5696:5696

13
vendor/github.com/gemalto/kmip-go/docs.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Package kmip is a general purpose KMIP library for implementing KMIP services and clients.
//
// The ttlv sub package contains the core logic for parsing the KMIP TTLV encoding formats,
// and marshaling them to and from golang structs.
//
// This package defines structs for many of the structures defined in the KMIP Spec, such as
// the different types of managed objects, request and response bodies, etc. Not all Structures
// are represented here yet, but the ones that are can be used as examples.
//
// There is also a partial implementation of a server, and an example of a client. There is
// currently no Client type for KMIP, but it is simple to open a socket overwhich you send
// and receive raw KMIP requests and responses.
package kmip

42
vendor/github.com/gemalto/kmip-go/errors.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
package kmip
import (
"errors"
"fmt"
"github.com/ansel1/merry"
"github.com/gemalto/kmip-go/kmip14"
)
func Details(err error) string {
return merry.Details(err)
}
var ErrInvalidTag = errors.New("invalid tag")
type errKey int
const (
errorKeyResultReason errKey = iota
)
//nolint:gochecknoinits
func init() {
merry.RegisterDetail("Result Reason", errorKeyResultReason)
}
func WithResultReason(err error, rr kmip14.ResultReason) error {
return merry.WithValue(err, errorKeyResultReason, rr)
}
func GetResultReason(err error) kmip14.ResultReason {
v := merry.Value(err, errorKeyResultReason)
switch t := v.(type) {
case nil:
return kmip14.ResultReason(0)
case kmip14.ResultReason:
return t
default:
panic(fmt.Sprintf("err result reason attribute's value was wrong type, expected ResultReason, got %T", v))
}
}

View File

@ -0,0 +1,66 @@
package kmiputil
import (
"encoding/binary"
"encoding/hex"
"strings"
"github.com/ansel1/merry"
)
var ErrInvalidHexString = merry.New("invalid hex string")
func DecodeUint32(b []byte) uint32 {
// pad to 4 bytes with leading zeros
return binary.BigEndian.Uint32(pad(b, 4))
}
func DecodeUint64(b []byte) uint64 {
// pad to 8 bytes with leading zeros
return binary.BigEndian.Uint64(pad(b, 8))
}
func pad(b []byte, l int) []byte {
if len(b) < l {
b2 := make([]byte, l)
copy(b2[l-len(b):], b)
b = b2
}
return b
}
// ParseHexValue attempts to parse a string formatted as a hex value
// as described in the KMIP Profiles spec, in the "Hex representations" section.
//
// If the string doesn't start with the required prefix "0x", it is assumed the string
// is not a hex representation, and nil, nil is returned.
//
// An ErrInvalidHexString is returned if the hex parsing fails.
// If the max argument is >0, ErrInvalidHexString is returned if the number of bytes parsed
// is greater than max, ignoring leading zeros. All bytes parsed are returned (including
// leading zeros).
func ParseHexValue(s string, max int) ([]byte, error) {
if !strings.HasPrefix(s, "0x") {
return nil, nil
}
b, err := hex.DecodeString(s[2:])
if err != nil {
return nil, merry.WithCause(ErrInvalidHexString, err).Append(err.Error())
}
if max > 0 {
l := len(b)
// minus leading zeros
for i := 0; i < len(b) && b[i] == 0; i++ {
l--
}
if l > max {
return nil, merry.Appendf(ErrInvalidHexString, "must be %v bytes", max)
}
}
return b, nil
}

View File

@ -0,0 +1,62 @@
package kmiputil
import (
"regexp"
"strings"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
var (
nonWordAtWordBoundary = regexp.MustCompile(`(\W)([a-zA-Z][a-z])`)
startingDigits = regexp.MustCompile(`^([\d]+)(.*)`)
)
// NormalizeName converts a string into the CamelCase format required for the XML and JSON encoding
// of KMIP values. It should be used for tag names, type names, and enumeration value names.
// Implementation of 5.4.1.1 and 5.5.1.1 from the KMIP Profiles specification.
func NormalizeName(s string) string {
// 1. Replace round brackets (, ) with spaces
s = strings.Map(func(r rune) rune {
switch r {
case '(', ')':
return ' '
}
return r
}, s)
// 2. If a non-word char (not alpha, digit or underscore) is followed by a letter (either upper or lower case) then a lower case letter, replace the non-word char with space
s = nonWordAtWordBoundary.ReplaceAllString(s, " $2")
// 3. Replace remaining non-word chars (except whitespace) with underscore.
s = strings.Map(func(r rune) rune {
switch {
case r >= 'a' && r <= 'z':
case r >= 'A' && r <= 'Z':
case r >= '0' && r <= '9':
case r == '_':
case r == ' ':
default:
return '_'
}
return r
}, s)
words := strings.Split(s, " ")
for i, w := range words {
if i == 0 {
// 4. If the first word begins with a digit, move all digits at start of first word to end of first word
w = startingDigits.ReplaceAllString(w, `$2$1`)
}
// 5. Capitalize the first letter of each word
words[i] = cases.Title(language.AmericanEnglish, cases.NoLower).String(w)
}
// 6. Concatenate all words with spaces removed
return strings.Join(words, "")
}

23
vendor/github.com/gemalto/kmip-go/kmip14/kmip_1_4.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
//go:generate go run ../cmd/kmipgen/main.go -o kmip_1_4_generated.go -i kmip_1_4.json -p kmip14
// Package kmip14 contains tag and enumeration value definitions from the 1.4 specification.
// These definitions will be registered automatically into the DefaultRegistry.
//
// Each tag is stored in a package constant, named Tag<normalized KMIP name>.
// Bitmask and Enumeration values are each represented by a type, named
// after the normalized name of the values set from the spec, e.g.
package kmip14
import (
"github.com/gemalto/kmip-go/ttlv"
)
// nolint:gochecknoinits
func init() {
Register(&ttlv.DefaultRegistry)
}
// Register registers the 1.4 enumeration values with the registry.
func Register(registry *ttlv.Registry) {
RegisterGeneratedDefinitions(registry)
}

1389
vendor/github.com/gemalto/kmip-go/kmip14/kmip_1_4.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

72
vendor/github.com/gemalto/kmip-go/managed_objects.go generated vendored Normal file
View File

@ -0,0 +1,72 @@
package kmip
import (
"math/big"
"github.com/gemalto/kmip-go/kmip14"
)
// 2.2
// 2.2.1
type Certificate struct {
CertificateType kmip14.CertificateType
CertificateValue []byte
}
// 2.2.2
type SymmetricKey struct {
KeyBlock KeyBlock
}
// 2.2.3
type PublicKey struct {
KeyBlock KeyBlock
}
// 2.2.4
type PrivateKey struct {
KeyBlock KeyBlock
}
// 2.2.5
type SplitKey struct {
SplitKeyParts int
KeyPartIdentifier int
SplitKeyThreshold int
SplitKeyMethod kmip14.SplitKeyMethod
PrimeFieldSize *big.Int `ttlv:",omitempty"`
KeyBlock KeyBlock
}
// 2.2.6
type Template struct {
Attribute []Attribute
}
// 2.2.7
type SecretData struct {
SecretDataType kmip14.SecretDataType
KeyBlock KeyBlock
}
// 2.2.8
type OpaqueObject struct {
OpaqueDataType kmip14.OpaqueDataType
OpaqueDataValue []byte
}
// 2.2.9
type PGPKey struct {
PGPKeyVersion int
KeyBlock KeyBlock
}

74
vendor/github.com/gemalto/kmip-go/op_create.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package kmip
import (
"context"
"github.com/ansel1/merry"
"github.com/gemalto/kmip-go/kmip14"
)
// TODO: should request and response payloads implement validation?
// Sort of makes sense to run validation over the request at this level, at least for spec
// compliance, though perhaps handlers may want to be more relaxed with validation.
//
// Should the response object run through validation? What is a valid response may change as
// the spec changes. Maybe this should just be handled by spec compliance tests.
// 4.1
//
// This operation requests the server to generate a new symmetric key as a Managed Cryptographic Object.
// This operation is not used to create a Template object (see Register operation, Section 4.3).
//
// The request contains information about the type of object being created, and some of the attributes to be
// assigned to the object (e.g., Cryptographic Algorithm, Cryptographic Length, etc.). This information MAY be
// specified by the names of Template objects that already exist.
//
// The response contains the Unique Identifier of the created object. The server SHALL copy the Unique Identifier
// returned by this operation into the ID Placeholder variable.
// CreateRequestPayload 4.1 Table 163
//
// TemplateAttribute MUST include CryptographicAlgorithm (3.4) and CryptographicUsageMask (3.19).
type CreateRequestPayload struct {
ObjectType kmip14.ObjectType
TemplateAttribute TemplateAttribute
}
// CreateResponsePayload 4.1 Table 164
type CreateResponsePayload struct {
ObjectType kmip14.ObjectType
UniqueIdentifier string
TemplateAttribute *TemplateAttribute
}
type CreateHandler struct {
Create func(ctx context.Context, payload *CreateRequestPayload) (*CreateResponsePayload, error)
}
func (h *CreateHandler) HandleItem(ctx context.Context, req *Request) (*ResponseBatchItem, error) {
var payload CreateRequestPayload
err := req.DecodePayload(&payload)
if err != nil {
return nil, err
}
respPayload, err := h.Create(ctx, &payload)
if err != nil {
return nil, err
}
var ok bool
idAttr := respPayload.TemplateAttribute.GetTag(kmip14.TagUniqueIdentifier)
req.IDPlaceholder, ok = idAttr.AttributeValue.(string)
if !ok {
return nil, merry.Errorf("invalid response returned by CreateHandler: unique identifier tag in attributes should have been a string, was %t", idAttr.AttributeValue)
}
return &ResponseBatchItem{
ResponsePayload: respPayload,
}, nil
}

View File

@ -0,0 +1,38 @@
package kmip
// CreateKeyPairRequestPayload
// 4.2 Create Key Pair
// This operation requests the server to generate a new public/private key pair
// and register the two corresponding new Managed Cryptographic Objects.
//
// The request contains attributes to be assigned to the objects (e.g.,
// Cryptographic Algorithm, Cryptographic Length, etc.). Attributes and Template
// Names MAY be specified for both keys at the same time by specifying a Common
// Template-Attribute object in the request. Attributes not common to both keys
// (e.g., Name, Cryptographic Usage Mask) MAY be specified using the Private Key
// Template-Attribute and Public Key Template-Attribute objects in the request,
// which take precedence over the Common Template-Attribute object.
//
// The Template Managed Object is deprecated as of version 1.3 of this
// specification and MAY be removed from subsequent versions of the
// specification. Individual Attributes SHOULD be used in operations which
// currently support use of a Name within a Template-Attribute to reference a
// Template.
//
// For the Private Key, the server SHALL create a Link attribute of Link Type
// Public Key pointing to the Public Key. For the Public Key, the server SHALL
// create a Link attribute of Link Type Private Key pointing to the Private Key.
// The response contains the Unique Identifiers of both created objects. The ID
// Placeholder value SHALL be set to the Unique Identifier of the Private Key.
type CreateKeyPairRequestPayload struct {
CommonTemplateAttribute *TemplateAttribute
PrivateKeyTemplateAttribute *TemplateAttribute
PublicKeyTemplateAttribute *TemplateAttribute
}
type CreateKeyPairResponsePayload struct {
PrivateKeyUniqueIdentifier string
PublicKeyUniqueIdentifier string
PrivateKeyTemplateAttribute *TemplateAttribute
PublicKeyTemplateAttribute *TemplateAttribute
}

40
vendor/github.com/gemalto/kmip-go/op_destroy.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
package kmip
import (
"context"
)
// DestroyRequestPayload ////////////////////////////////////////
//
type DestroyRequestPayload struct {
UniqueIdentifier string
}
// DestroyResponsePayload
type DestroyResponsePayload struct {
UniqueIdentifier string
}
type DestroyHandler struct {
Destroy func(ctx context.Context, payload *DestroyRequestPayload) (*DestroyResponsePayload, error)
}
func (h *DestroyHandler) HandleItem(ctx context.Context, req *Request) (*ResponseBatchItem, error) {
var payload DestroyRequestPayload
err := req.DecodePayload(&payload)
if err != nil {
return nil, err
}
respPayload, err := h.Destroy(ctx, &payload)
if err != nil {
return nil, err
}
// req.Key = respPayload.Key
return &ResponseBatchItem{
ResponsePayload: respPayload,
}, nil
}

View File

@ -0,0 +1,47 @@
package kmip
import (
"context"
)
// 4.26
type DiscoverVersionsRequestPayload struct {
ProtocolVersion []ProtocolVersion
}
type DiscoverVersionsResponsePayload struct {
ProtocolVersion []ProtocolVersion
}
type DiscoverVersionsHandler struct {
SupportedVersions []ProtocolVersion
}
func (h *DiscoverVersionsHandler) HandleItem(ctx context.Context, req *Request) (item *ResponseBatchItem, err error) {
var payload DiscoverVersionsRequestPayload
err = req.DecodePayload(&payload)
if err != nil {
return nil, err
}
var respPayload DiscoverVersionsResponsePayload
if len(payload.ProtocolVersion) == 0 {
respPayload.ProtocolVersion = h.SupportedVersions
} else {
for _, v := range h.SupportedVersions {
for _, cv := range payload.ProtocolVersion {
if cv == v {
respPayload.ProtocolVersion = append(respPayload.ProtocolVersion, v)
break
}
}
}
}
return &ResponseBatchItem{
ResponsePayload: respPayload,
}, nil
}

51
vendor/github.com/gemalto/kmip-go/op_get.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
package kmip
import (
"context"
"github.com/gemalto/kmip-go/kmip14"
)
// GetRequestPayload ////////////////////////////////////////
//
type GetRequestPayload struct {
UniqueIdentifier string
}
// GetResponsePayload
type GetResponsePayload struct {
ObjectType kmip14.ObjectType
UniqueIdentifier string
Certificate *Certificate
SymmetricKey *SymmetricKey
PrivateKey *PrivateKey
PublicKey *PublicKey
SplitKey *SplitKey
Template *Template
SecretData *SecretData
OpaqueObject *OpaqueObject
}
type GetHandler struct {
Get func(ctx context.Context, payload *GetRequestPayload) (*GetResponsePayload, error)
}
func (h *GetHandler) HandleItem(ctx context.Context, req *Request) (*ResponseBatchItem, error) {
var payload GetRequestPayload
err := req.DecodePayload(&payload)
if err != nil {
return nil, err
}
respPayload, err := h.Get(ctx, &payload)
if err != nil {
return nil, err
}
// req.Key = respPayload.Key
return &ResponseBatchItem{
ResponsePayload: respPayload,
}, nil
}

86
vendor/github.com/gemalto/kmip-go/op_register.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
package kmip
import (
"context"
"github.com/ansel1/merry"
"github.com/gemalto/kmip-go/kmip14"
)
// 4.3
// Table 169
type RegisterRequestPayload struct {
ObjectType kmip14.ObjectType
TemplateAttribute TemplateAttribute
Certificate *Certificate
SymmetricKey *SymmetricKey
PrivateKey *PrivateKey
PublicKey *PublicKey
SplitKey *SplitKey
Template *Template
SecretData *SecretData
OpaqueObject *OpaqueObject
}
// Table 170
type RegisterResponsePayload struct {
UniqueIdentifier string
TemplateAttribute TemplateAttribute
}
type RegisterHandler struct {
SkipValidation bool
RegisterFunc func(context.Context, *RegisterRequestPayload) (*RegisterResponsePayload, error)
}
func (h *RegisterHandler) HandleItem(ctx context.Context, req *Request) (item *ResponseBatchItem, err error) {
var payload RegisterRequestPayload
err = req.DecodePayload(&payload)
if err != nil {
return nil, merry.Prepend(err, "decoding request")
}
if !h.SkipValidation {
var payloadPresent bool
switch payload.ObjectType {
default:
return nil, WithResultReason(merry.UserError("Object Type is not recognized"), kmip14.ResultReasonInvalidField)
case kmip14.ObjectTypeCertificate:
payloadPresent = payload.Certificate != nil
case kmip14.ObjectTypeSymmetricKey:
payloadPresent = payload.SymmetricKey != nil
case kmip14.ObjectTypePrivateKey:
payloadPresent = payload.PrivateKey != nil
case kmip14.ObjectTypePublicKey:
payloadPresent = payload.PublicKey != nil
case kmip14.ObjectTypeSplitKey:
payloadPresent = payload.SplitKey != nil
case kmip14.ObjectTypeTemplate:
payloadPresent = payload.Template != nil
case kmip14.ObjectTypeSecretData:
payloadPresent = payload.SecretData != nil
case kmip14.ObjectTypeOpaqueObject:
payloadPresent = payload.OpaqueObject != nil
}
if !payloadPresent {
return nil, WithResultReason(merry.UserErrorf("Object Type %s does not match type of cryptographic object provided", payload.ObjectType.String()), kmip14.ResultReasonInvalidField)
}
}
respPayload, err := h.RegisterFunc(ctx, &payload)
if err != nil {
return nil, err
}
req.IDPlaceholder = respPayload.UniqueIdentifier
return &ResponseBatchItem{
ResponsePayload: respPayload,
}, nil
}

902
vendor/github.com/gemalto/kmip-go/requests.go generated vendored Normal file
View File

@ -0,0 +1,902 @@
package kmip
// This is a WIP implementation of a KMIP server. The code is mostly based on the http server in
// the golang standard library. It is functional, but not all of the features of the http server
// have been ported over yet, and some of the stuff in here still refers to http stuff.
//
// The responsibility of handling a request is broken up into 3 layers of handlers: ProtocolHandler, MessageHandler,
// and ItemHandler. Each of these handlers delegates details to the next layer. Using the http
// package as an analogy, ProtocolHandler is similar to the wire-level HTTP protocol handling in
// http.Server and http.Transport. MessageHandler parses KMIP TTLV bytes into golang request and response structs.
// ItemHandler is a bit like http.ServeMux, routing particular KMIP operations to registered handlers.
import (
"bufio"
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"runtime"
"sync"
"sync/atomic"
"time"
"github.com/ansel1/merry"
"github.com/gemalto/flume"
"github.com/gemalto/kmip-go/kmip14"
"github.com/gemalto/kmip-go/ttlv"
"github.com/google/uuid"
)
var serverLog = flume.New("kmip_server")
// Server serves KMIP protocol connections from a net.Listener. Because KMIP is a connection-oriented
// protocol, unlike HTTP, each connection ends up being serviced by a dedicated goroutine (rather than
// each request). For each KMIP connection, requests are processed serially. The handling
// of the request is delegated to the ProtocolHandler.
//
// Limitations:
//
// This implementation is functional (it can respond to KMIP requests), but incomplete. Some of the
// connection management features of the http package haven't been ported over, and also, there is
// currently no connection-context in which to store things like an authentication or session management.
// Since HTTP is an intrinsically stateless model, it makes sense for the http package to delegate session
// management to third party packages, but for KMIP, it would makes sense for there to be some first
// class support for a connection context.
//
// This package also only handles the binary TTLV encoding for now. It may make sense for this
// server to detect or support the XML and JSON encodings as well. It may also makes sense to support
// KMIP requests over HTTP, perhaps by adapting ProtocolHandler to an http.Handler or something.
type Server struct {
Handler ProtocolHandler
mu sync.Mutex
listeners map[*net.Listener]struct{}
inShutdown int32 // accessed atomically (non-zero means we're in Shutdown)
}
// ErrServerClosed is returned by the Server's Serve, ServeTLS, ListenAndServe,
// and ListenAndServeTLS methods after a call to Shutdown or Close.
var ErrServerClosed = errors.New("http: Server closed")
// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines read requests and
// then call srv.MessageHandler to reply to them.
//
// Serve always returns a non-nil error and closes l.
// After Shutdown or Close, the returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
//if fn := testHookServerServe; fn != nil {
// fn(srv, l) // call hook with unwrapped listener
//}
l = &onceCloseListener{Listener: l}
defer l.Close()
if !srv.trackListener(&l, true) {
return ErrServerClosed
}
defer srv.trackListener(&l, false)
var tempDelay time.Duration // how long to sleep on accept failure
baseCtx := context.Background() // base is always background, per Issue 16220
ctx := baseCtx
// ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, e := l.Accept()
if e != nil {
if srv.shuttingDown() {
return ErrServerClosed
}
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
// srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := &conn{server: srv, rwc: rw}
// c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}
// Close immediately closes all active net.Listeners and any
// connections in state StateNew, StateActive, or StateIdle. For a
// graceful shutdown, use Shutdown.
//
// Close does not attempt to close (and does not even know about)
// any hijacked connections, such as WebSockets.
//
// Close returns any error returned from closing the Server's
// underlying Listener(s).
func (srv *Server) Close() error {
atomic.StoreInt32(&srv.inShutdown, 1)
srv.mu.Lock()
defer srv.mu.Unlock()
// srv.closeDoneChanLocked()
err := srv.closeListenersLocked()
//for c := range srv.activeConn {
// c.rwc.Close()
// delete(srv.activeConn, c)
//}
return err
}
// shutdownPollInterval is how often we poll for quiescence
// during Server.Shutdown. This is lower during tests, to
// speed up tests.
// Ideally we could find a solution that doesn't involve polling,
// but which also doesn't have a high runtime cost (and doesn't
// involve any contentious mutexes), but that is left as an
// exercise for the reader.
var shutdownPollInterval = 500 * time.Millisecond
// Shutdown gracefully shuts down the server without interrupting any
// active connections. Shutdown works by first closing all open
// listeners, then closing all idle connections, and then waiting
// indefinitely for connections to return to idle and then shut down.
// If the provided context expires before the shutdown is complete,
// Shutdown returns the context's error, otherwise it returns any
// error returned from closing the Server's underlying Listener(s).
//
// When Shutdown is called, Serve, ListenAndServe, and
// ListenAndServeTLS immediately return ErrServerClosed. Make sure the
// program doesn't exit and waits instead for Shutdown to return.
//
// Shutdown does not attempt to close nor wait for hijacked
// connections such as WebSockets. The caller of Shutdown should
// separately notify such long-lived connections of shutdown and wait
// for them to close, if desired. See RegisterOnShutdown for a way to
// register shutdown notification functions.
//
// Once Shutdown has been called on a server, it may not be reused;
// future calls to methods such as Serve will return ErrServerClosed.
func (srv *Server) Shutdown(ctx context.Context) error {
atomic.StoreInt32(&srv.inShutdown, 1)
srv.mu.Lock()
lnerr := srv.closeListenersLocked()
//srv.closeDoneChanLocked()
//for _, f := range srv.onShutdown {
// go f()
//}
srv.mu.Unlock()
ticker := time.NewTicker(shutdownPollInterval)
defer ticker.Stop()
return lnerr
//for {
// if srv.closeIdleConns() {
// return lnerr
// }
// select {
// case <-ctx.Done():
// return ctx.Err()
// case <-ticker.C:
// }
//}
}
func (srv *Server) closeListenersLocked() error {
var err error
for ln := range srv.listeners {
if cerr := (*ln).Close(); cerr != nil && err == nil {
err = cerr
}
delete(srv.listeners, ln)
}
return err
}
// trackListener adds or removes a net.Listener to the set of tracked
// listeners.
//
// We store a pointer to interface in the map set, in case the
// net.Listener is not comparable. This is safe because we only call
// trackListener via Serve and can track+defer untrack the same
// pointer to local variable there. We never need to compare a
// Listener from another caller.
//
// It reports whether the server is still up (not Shutdown or Closed).
func (srv *Server) trackListener(ln *net.Listener, add bool) bool {
srv.mu.Lock()
defer srv.mu.Unlock()
if srv.listeners == nil {
srv.listeners = make(map[*net.Listener]struct{})
}
if add {
if srv.shuttingDown() {
return false
}
srv.listeners[ln] = struct{}{}
} else {
delete(srv.listeners, ln)
}
return true
}
func (srv *Server) shuttingDown() bool {
return atomic.LoadInt32(&srv.inShutdown) != 0
}
type conn struct {
rwc net.Conn
remoteAddr string
localAddr string
tlsState *tls.ConnectionState
// cancelCtx cancels the connection-level context.
cancelCtx context.CancelFunc
// bufr reads from rwc.
bufr *bufio.Reader
dec *ttlv.Decoder
server *Server
}
func (c *conn) close() {
// TODO: http package has a buffered writer on the conn too, which is flushed here
_ = c.rwc.Close()
}
// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
ctx = flume.WithLogger(ctx, serverLog)
ctx, cancelCtx := context.WithCancel(ctx)
c.cancelCtx = cancelCtx
c.remoteAddr = c.rwc.RemoteAddr().String()
c.localAddr = c.rwc.LocalAddr().String()
// ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
defer func() {
if err := recover(); err != nil {
// TODO: logging support
// if err := recover(); err != nil && err != ErrAbortHandler {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
if e, ok := err.(error); ok {
fmt.Printf("kmip: panic serving %v: %v\n%s", c.remoteAddr, Details(e), buf)
} else {
fmt.Printf("kmip: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
}
// c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
}
cancelCtx()
// if !c.hijacked() {
c.close()
// c.setState(c.rwc, StateClosed)
//}
}()
if tlsConn, ok := c.rwc.(*tls.Conn); ok {
//if d := c.server.ReadTimeout; d != 0 {
// c.rwc.SetReadDeadline(time.Now().Add(d))
//}
//if d := c.server.WriteTimeout; d != 0 {
// c.rwc.SetWriteDeadline(time.Now().Add(d))
//}
if err := tlsConn.Handshake(); err != nil {
// TODO: logging support
fmt.Printf("kmip: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
// c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
return
}
c.tlsState = new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
//if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {
// if fn := c.server.TLSNextProto[proto]; fn != nil {
// h := initNPNRequest{tlsConn, serverHandler{c.server}}
// fn(c.server, tlsConn, h)
// }
// return
//}
}
// TODO: do we really need instance pooling here? We expect KMIP connections to be long lasting
c.dec = ttlv.NewDecoder(c.rwc)
c.bufr = bufio.NewReader(c.rwc)
// c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
for {
w, err := c.readRequest(ctx)
//if c.r.remain != c.server.initialReadLimitSize() {
// If we read any bytes off the wire, we're active.
//c.setState(c.rwc, StateActive)
//}
if err != nil {
if merry.Is(err, io.EOF) {
fmt.Println("client closed connection")
return
}
// TODO: do something with this error
panic(err)
//const errorHeaders= "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n"
//
//if err == errTooLarge {
// // Their HTTP client may or may not be
// // able to read this if we're
// // responding to them and hanging up
// // while they're still writing their
// // request. Undefined behavior.
// const publicErr= "431 Request Header Fields Too Large"
// fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
// c.closeWriteAndWait()
// return
//}
//if isCommonNetReadError(err) {
// return // don't reply
//}
//
//publicErr := "400 Bad Request"
//if v, ok := err.(badRequestError); ok {
// publicErr = publicErr + ": " + string(v)
//}
//
//fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
//return
}
// Expect 100 Continue support
//req := w.req
//if req.expectsContinue() {
// if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// // Wrap the Body reader with one that replies on the connection
// req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
// }
//} else if req.Header.get("Expect") != "" {
// w.sendExpectationFailed()
// return
//}
// c.curReq.Store(w)
//if requestBodyRemains(req.Body) {
// registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
//} else {
// w.conn.r.startBackgroundRead()
//}
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
h := c.server.Handler
if h == nil {
h = DefaultProtocolHandler
}
// var resp ResponseMessage
// err = c.server.MessageHandler.Handle(ctx, w, &resp)
// TODO: this cancelCtx() was created at the connection level, not the request level. Need to
// figure out how to handle connection vs request timeouts and cancels.
// cancelCtx()
// TODO: use recycled buffered writer
writer := bufio.NewWriter(c.rwc)
h.ServeKMIP(ctx, w, writer)
err = writer.Flush()
if err != nil {
// TODO: handle error
panic(err)
}
//serverHandler{c.server}.ServeHTTP(w, w.req)
//w.cancelCtx()
//if c.hijacked() {
// return
//}
//w.finishRequest()
//if !w.shouldReuseConnection() {
// if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
// c.closeWriteAndWait()
// }
// return
//}
//c.setState(c.rwc, StateIdle)
//c.curReq.Store((*response)(nil))
//if !w.conn.server.doKeepAlives() {
// // We're in shutdown mode. We might've replied
// // to the user without "Connection: close" and
// // they might think they can send another
// // request, but such is life with HTTP/1.1.
// return
//}
//
//if d := c.server.idleTimeout(); d != 0 {
// c.rwc.SetReadDeadline(time.Now().Add(d))
// if _, err := c.bufr.Peek(4); err != nil {
// return
// }
//}
//c.rwc.SetReadDeadline(time.Time{})
}
}
// Read next request from connection.
func (c *conn) readRequest(ctx context.Context) (w *Request, err error) {
//if c.hijacked() {
// return nil, ErrHijacked
//}
//var (
// wholeReqDeadline time.Time // or zero if none
// hdrDeadline time.Time // or zero if none
//)
//t0 := time.Now()
//if d := c.server.readHeaderTimeout(); d != 0 {
// hdrDeadline = t0.Add(d)
//}
//if d := c.server.ReadTimeout; d != 0 {
// wholeReqDeadline = t0.Add(d)
//}
//c.rwc.SetReadDeadline(hdrDeadline)
//if d := c.server.WriteTimeout; d != 0 {
// defer func() {
// c.rwc.SetWriteDeadline(time.Now().Add(d))
// }()
//}
//c.r.setReadLimit(c.server.initialReadLimitSize())
//if c.lastMethod == "POST" {
// RFC 7230 section 3 tolerance for old buggy clients.
//peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
//c.bufr.Discard(numLeadingCRorLF(peek))
//}
ttlvVal, err := c.dec.NextTTLV()
if err != nil {
return nil, err
}
//if err != nil {
//if c.r.hitReadLimit() {
// return nil, errTooLarge
//}
//}
// TODO: use pooling to recycle requests?
req := &Request{
TTLV: ttlvVal,
RemoteAddr: c.remoteAddr,
LocalAddr: c.localAddr,
TLS: c.tlsState,
}
// c.r.setInfiniteReadLimit()
// Adjust the read deadline if necessary.
//if !hdrDeadline.Equal(wholeReqDeadline) {
// c.rwc.SetReadDeadline(wholeReqDeadline)
//}
return req, nil
}
// Request represents a KMIP request.
type Request struct {
// TTLV will hold the entire body of the request.
TTLV ttlv.TTLV
Message *RequestMessage
CurrentItem *RequestBatchItem
DisallowExtraValues bool
// TLS holds the TLS state of the connection this request was received on.
TLS *tls.ConnectionState
RemoteAddr string
LocalAddr string
IDPlaceholder string
decoder *ttlv.Decoder
}
// coerceToTTLV attempts to coerce an interface value to TTLV.
// In most production scenarios, this is intended to be used in
// places where the value is already a TTLV, and just needs to be
// type cast. If v is not TTLV, it will be marshaled. This latter
// behavior is slow, so it should be used only in tests.
func coerceToTTLV(v interface{}) (ttlv.TTLV, error) {
switch t := v.(type) {
case nil:
return nil, nil
case ttlv.TTLV:
return t, nil
default:
return ttlv.Marshal(v)
}
}
// Unmarshal unmarshals ttlv into structures. Handlers should prefer this
// method over than their own Decoders or Unmarshal(). This method
// enforces rules about whether extra fields are allowed, and reuses
// buffers for efficiency.
func (r *Request) Unmarshal(ttlv ttlv.TTLV, into interface{}) error {
if len(ttlv) == 0 {
return nil
}
r.decoder.Reset(bytes.NewReader(ttlv))
return r.decoder.Decode(into)
}
func (r *Request) DecodePayload(v interface{}) error {
if r.CurrentItem == nil {
return nil
}
ttlvVal, err := coerceToTTLV(r.CurrentItem.RequestPayload)
if err != nil {
return err
}
return r.Unmarshal(ttlvVal, v)
}
// onceCloseListener wraps a net.Listener, protecting it from
// multiple Close calls.
type onceCloseListener struct {
net.Listener
once sync.Once
closeErr error
}
func (oc *onceCloseListener) Close() error {
oc.once.Do(oc.close)
return oc.closeErr
}
func (oc *onceCloseListener) close() { oc.closeErr = oc.Listener.Close() }
type ResponseWriter interface {
io.Writer
}
// ProtocolHandler is responsible for handling raw requests read off the wire. The
// *Request object will only have TTLV field populated. The response should
// be written directly to the ResponseWriter.
//
// The default implemention of ProtocolHandler is StandardProtocolHandler.
type ProtocolHandler interface {
ServeKMIP(ctx context.Context, req *Request, resp ResponseWriter)
}
// MessageHandler handles KMIP requests which have already be decoded. The *Request
// object's Message field will be populated from the decoded TTLV. The *Response
// object will always be non-nil, and its ResponseHeader will be populated. The
// MessageHandler usually shouldn't modify the ResponseHeader: the ProtocolHandler
// is responsible for the header. The MessageHandler just needs to populate
// the response batch items.
//
// The default implementation of MessageHandler is OperationMux.
type MessageHandler interface {
HandleMessage(ctx context.Context, req *Request, resp *Response)
}
// ItemHandler handles a single batch item in a KMIP request. The *Request
// object's CurrentItem field will be populated with item to be handled.
type ItemHandler interface {
HandleItem(ctx context.Context, req *Request) (item *ResponseBatchItem, err error)
}
type ProtocolHandlerFunc func(context.Context, *Request, ResponseWriter)
func (f ProtocolHandlerFunc) ServeKMIP(ctx context.Context, r *Request, w ResponseWriter) {
f(ctx, r, w)
}
type MessageHandlerFunc func(context.Context, *Request, *Response)
func (f MessageHandlerFunc) HandleMessage(ctx context.Context, req *Request, resp *Response) {
f(ctx, req, resp)
}
type ItemHandlerFunc func(context.Context, *Request) (*ResponseBatchItem, error)
func (f ItemHandlerFunc) HandleItem(ctx context.Context, req *Request) (item *ResponseBatchItem, err error) {
return f(ctx, req)
}
var DefaultProtocolHandler = &StandardProtocolHandler{
MessageHandler: DefaultOperationMux,
ProtocolVersion: ProtocolVersion{
ProtocolVersionMajor: 1,
ProtocolVersionMinor: 4,
},
}
var DefaultOperationMux = &OperationMux{}
// StandardProtocolHandler is the default ProtocolHandler implementation. It
// handles decoding the request and encoding the response, as well as protocol
// level tasks like version negotiation and correlation values.
//
// It delegates handling of the request to a MessageHandler.
type StandardProtocolHandler struct {
ProtocolVersion ProtocolVersion
MessageHandler MessageHandler
LogTraffic bool
}
func (h *StandardProtocolHandler) parseMessage(ctx context.Context, req *Request) error {
ttlvV := req.TTLV
if err := ttlvV.Valid(); err != nil {
return merry.Prepend(err, "invalid ttlv")
}
if ttlvV.Tag() != kmip14.TagRequestMessage {
return merry.Errorf("invalid tag: expected RequestMessage, was %s", ttlvV.Tag().String())
}
var message RequestMessage
err := ttlv.Unmarshal(ttlvV, &message)
if err != nil {
return merry.Prepend(err, "failed to parse message")
}
req.Message = &message
return nil
}
var responsePool = sync.Pool{}
type Response struct {
ResponseMessage
buf bytes.Buffer
enc *ttlv.Encoder
}
func newResponse() *Response {
v := responsePool.Get()
if v != nil {
r := v.(*Response)
r.reset()
return r
}
r := Response{}
r.enc = ttlv.NewEncoder(&r.buf)
return &r
}
func releaseResponse(r *Response) {
responsePool.Put(r)
}
func (r *Response) reset() {
r.BatchItem = nil
r.ResponseMessage = ResponseMessage{}
r.buf.Reset()
}
func (r *Response) Bytes() []byte {
r.buf.Reset()
err := r.enc.Encode(&r.ResponseMessage)
if err != nil {
panic(err)
}
return r.buf.Bytes()
}
func (r *Response) errorResponse(reason kmip14.ResultReason, msg string) {
r.BatchItem = []ResponseBatchItem{
{
ResultStatus: kmip14.ResultStatusOperationFailed,
ResultReason: reason,
ResultMessage: msg,
},
}
}
func (h *StandardProtocolHandler) handleRequest(ctx context.Context, req *Request, resp *Response) (logger flume.Logger) {
// create a server correlation value, which is like a unique transaction ID
scv := uuid.New().String()
// create a logger for the transaction, seeded with the scv
logger = flume.FromContext(ctx).With("scv", scv)
// attach the logger to the context, so it is available to the handling chain
ctx = flume.WithLogger(ctx, logger)
// TODO: it's unclear how the full protocol negogiation is supposed to work
// should server be pinned to a particular version? Or should we try and negogiate a common version?
resp.ResponseHeader.ProtocolVersion = h.ProtocolVersion
resp.ResponseHeader.TimeStamp = time.Now()
resp.ResponseHeader.BatchCount = len(resp.BatchItem)
resp.ResponseHeader.ServerCorrelationValue = scv
if err := h.parseMessage(ctx, req); err != nil {
resp.errorResponse(kmip14.ResultReasonInvalidMessage, err.Error())
return
}
ccv := req.Message.RequestHeader.ClientCorrelationValue
// add the client correlation value to the logging context. This value uniquely
// identifies the client, and is supposed to be included in server logs
logger = logger.With("ccv", ccv)
ctx = flume.WithLogger(ctx, logger)
resp.ResponseHeader.ClientCorrelationValue = req.Message.RequestHeader.ClientCorrelationValue
clientMajorVersion := req.Message.RequestHeader.ProtocolVersion.ProtocolVersionMajor
if clientMajorVersion != h.ProtocolVersion.ProtocolVersionMajor {
resp.errorResponse(kmip14.ResultReasonInvalidMessage,
fmt.Sprintf("mismatched protocol versions, client: %d, server: %d", clientMajorVersion, h.ProtocolVersion.ProtocolVersionMajor))
return
}
// set a flag hinting to handlers that extra fields should not be tolerated when
// unmarshaling payloads. According to spec, if server and client protocol version
// minor versions match, then extra fields should cause an error. Not sure how to enforce
// this in this higher level handler, since we (the protocol/message handlers) don't unmarshal the payload.
// That's done by a particular item handler.
req.DisallowExtraValues = req.Message.RequestHeader.ProtocolVersion.ProtocolVersionMinor == h.ProtocolVersion.ProtocolVersionMinor
req.decoder = ttlv.NewDecoder(nil)
req.decoder.DisallowExtraValues = req.DisallowExtraValues
h.MessageHandler.HandleMessage(ctx, req, resp)
resp.ResponseHeader.BatchCount = len(resp.BatchItem)
respTTLV := resp.Bytes()
if req.Message.RequestHeader.MaximumResponseSize > 0 && len(respTTLV) > req.Message.RequestHeader.MaximumResponseSize {
// new error resp
resp.errorResponse(kmip14.ResultReasonResponseTooLarge, "")
respTTLV = resp.Bytes()
}
return
}
func (h *StandardProtocolHandler) ServeKMIP(ctx context.Context, req *Request, writer ResponseWriter) {
// we precreate the response object and pass it down to handlers, because due
// the guidance in the spec on the Maximum Response Size, it will be necessary
// for handlers to recalculate the response size after each batch item, which
// requires re-encoding the entire response. Seems inefficient.
resp := newResponse()
logger := h.handleRequest(ctx, req, resp)
var err error
if h.LogTraffic {
ttlvV := resp.Bytes()
logger.Debug("traffic log", "request", req.TTLV.String(), "response", ttlv.TTLV(ttlvV).String())
_, err = writer.Write(ttlvV)
} else {
_, err = resp.buf.WriteTo(writer)
}
if err != nil {
panic(err)
}
releaseResponse(resp)
}
func (r *ResponseMessage) addFailure(reason kmip14.ResultReason, msg string) {
if msg == "" {
msg = reason.String()
}
r.BatchItem = append(r.BatchItem, ResponseBatchItem{
ResultStatus: kmip14.ResultStatusOperationFailed,
ResultReason: reason,
ResultMessage: msg,
})
}
// OperationMux is an implementation of MessageHandler which handles each batch item in the request
// by routing the operation to an ItemHandler. The ItemHandler performs the operation, and returns
// either a *ResponseBatchItem, or an error. If it returns an error, the error is passed to
// ErrorHandler, which converts it into a error *ResponseBatchItem. OperationMux handles correlating
// items in the request to items in the response.
type OperationMux struct {
mu sync.RWMutex
handlers map[kmip14.Operation]ItemHandler
// ErrorHandler defaults to the DefaultErrorHandler.
ErrorHandler ErrorHandler
}
// ErrorHandler converts a golang error into a *ResponseBatchItem (which should hold information
// about the error to convey back to the client).
type ErrorHandler interface {
HandleError(err error) *ResponseBatchItem
}
type ErrorHandlerFunc func(err error) *ResponseBatchItem
func (f ErrorHandlerFunc) HandleError(err error) *ResponseBatchItem {
return f(err)
}
// DefaultErrorHandler tries to map errors to ResultReasons.
var DefaultErrorHandler = ErrorHandlerFunc(func(err error) *ResponseBatchItem {
reason := GetResultReason(err)
if reason == kmip14.ResultReason(0) {
// error not handled
return nil
}
// prefer user message, but fall back on message
msg := merry.UserMessage(err)
if msg == "" {
msg = merry.Message(err)
}
return newFailedResponseBatchItem(reason, msg)
})
func newFailedResponseBatchItem(reason kmip14.ResultReason, msg string) *ResponseBatchItem {
return &ResponseBatchItem{
ResultStatus: kmip14.ResultStatusOperationFailed,
ResultReason: reason,
ResultMessage: msg,
}
}
func (m *OperationMux) bi(ctx context.Context, req *Request, reqItem *RequestBatchItem) *ResponseBatchItem {
req.CurrentItem = reqItem
h := m.handlerForOp(reqItem.Operation)
if h == nil {
return newFailedResponseBatchItem(kmip14.ResultReasonOperationNotSupported, "")
}
resp, err := h.HandleItem(ctx, req)
if err != nil {
eh := m.ErrorHandler
if eh == nil {
eh = DefaultErrorHandler
}
resp = eh.HandleError(err)
if resp == nil {
// errors which don't convert just panic
panic(err)
}
}
return resp
}
func (m *OperationMux) HandleMessage(ctx context.Context, req *Request, resp *Response) {
for i := range req.Message.BatchItem {
reqItem := &req.Message.BatchItem[i]
respItem := m.bi(ctx, req, reqItem)
respItem.Operation = reqItem.Operation
respItem.UniqueBatchItemID = reqItem.UniqueBatchItemID
resp.BatchItem = append(resp.BatchItem, *respItem)
}
}
func (m *OperationMux) Handle(op kmip14.Operation, handler ItemHandler) {
m.mu.Lock()
defer m.mu.Unlock()
if m.handlers == nil {
m.handlers = map[kmip14.Operation]ItemHandler{}
}
m.handlers[op] = handler
}
func (m *OperationMux) handlerForOp(op kmip14.Operation) ItemHandler {
m.mu.RLock()
defer m.mu.RUnlock()
return m.handlers[op]
}
func (m *OperationMux) missingHandler(ctx context.Context, req *Request, resp *ResponseMessage) error {
resp.addFailure(kmip14.ResultReasonOperationNotSupported, "")
return nil
}

499
vendor/github.com/gemalto/kmip-go/ttlv/decoder.go generated vendored Normal file
View File

@ -0,0 +1,499 @@
package ttlv
import (
"bufio"
"bytes"
"errors"
"io"
"reflect"
"github.com/ansel1/merry"
)
var ErrUnexpectedValue = errors.New("no field was found to unmarshal value into")
// Unmarshal parses TTLV encoded data and stores the result
// in the value pointed to by v.
//
// An error will be returned if v is nil or not a point, or
// if b is not valid TTLV.
//
// Unmarshal will allocate values to store the result in, similar to the
// json.Marshal. Generally, the destination value can be a pointer or
// or a direct value. Currently, Unmarshal does not support anonymous fields.
// They will be ignored. Private fields are ignored.
//
// Unmarshal maps TTLV values to golang values according to the following
// rules:
//
// 1. If the destination value is interface{}, it will be set to the result
// of TTLV.Value()
// 2. If the destination implements Unmarshaler, that will be called.
// 3. If the destination is a slice (except for []byte), append the
// unmarshalled value to the slice
// 4. Structure unmarshals into a struct. See rules
// below for matching struct fields to the values in the Structure.
// 5. Interval unmarshals into an int64
// 6. DateTime and DateTimeExtended ummarshal into time.Time
// 7. ByteString unmarshals to a []byte
// 8. TextString unmarshals into a string
// 9. Boolean unmarshals into a bool
// 10. Enumeration can unmarshal into an int, int8, int16, int32, or their
// uint counterparts. If the KMIP value overflows the destination, a
// *UnmarshalerError with cause ErrIntOverflow is returned.
// 11. Integer can unmarshal to the same types as Enumeration, with the
// same overflow check.
// 12. LongInteger unmarshals to int64 or uint64
// 13. BitInteger unmarshals to big.Int.
//
// If the destination value is not a supported type, an *UnmarshalerError with
// cause ErrUnsupportedTypeError is returned. If the source value's type is not recognized,
// *UnmarshalerError with cause ErrInvalidType is returned.
//
// Unmarshaling Structure
//
// Unmarshal will try to match the values in the Structure with the fields in the
// destination struct. Structure is an array of values, while a struct is more like
// a map, so not all Structure values can be accurately represented by a golang struct.
// In particular, a Structure can hold the same tag multiple times, e.g. 3 TagComment values
// in a row.
//
// For each field in the struct, Unmarshal infers a KMIP Tag by examining both the name
// and type of the field. It uses the following rules, in order:
//
// 1. If the type of a field is a struct, and the struct contains a field named "TTLVTag", and the field
// has a "ttlv" struct tag, the value of the struct tag will be parsed using ParseTag(). If
// parsing fails, an error is returned. The type and value of the TTLVTag field is ignored.
// In this example, the F field will map to TagDeactivationDate:
//
// type Bar struct {
// F Foo
// }
// type Foo struct {
// TTLVTag struct{} `ttlv:"DeactivationDate"`
// }
//
// If Bar uses a struct tag on F indicating a different tag, it is an error:
//
// type Bar struct {
// F Foo `ttlv:"DerivationData"` // this will cause an ErrTagConflict
// // because conflict Bar's field tag
// // conflicts with Foo's intrinsic tag
// F2 Foo `ttlv:"0x420034"` // the value can also be hex
// }
// 2. If the type of the field is a struct, and the struct contains a field named "TTLVTag",
// and that field is of type ttlv.Tag and is not empty, the value of the field will be the
// inferred Tag. For example:
//
// type Foo struct {
// TTLVTag ttlv.Tag
// }
// f := Foo{TTLVTag: ttlv.TagState}
//
// This allows you to dynamically set the KMIP tag that a value will marshal to.
// 3. The "ttlv" struct tag can be used to indicate the tag for a field. The value will
// be parsed with ParseTag()
//
// type Bar struct {
// F Foo `ttlv:"DerivationData"`
// }
//
// 4. The name of the field is parsed with ParseTag():
//
// type Bar struct {
// DerivationData int
// }
//
// 5. The name of the field's type is parsed with ParseTab():
//
// type DerivationData int
//
// type Bar struct {
// dd DerivationData
// }
//
// If no tag value can be inferred, the field is ignored. Multiple fields
// *cannot* map to the same KMIP tag. If they do, an ErrTagConflict will
// be returned.
//
// Each value in the Structure will be matched against the first field
// in the struct with the same inferred tag.
//
// If the value cannot be matched with a field, Unmarshal will look for
// the first field with the "any" struct flag set and unmarshal into that:
//
// type Foo struct {
// Comment string // the Comment will unmarshal into this
// EverythingElse []interface{} `,any` // all other values will unmarshal into this
// AnotherAny []interface{} `,any` // allowed, but ignored. first any field will always match
// NotLegal []interface{} `TagComment,any` // you cannot specify a tag and the any flag.
// // will return error
// }
//
// If after applying these rules no destination field is found, the KMIP value is ignored.
func Unmarshal(ttlv TTLV, v interface{}) error {
return NewDecoder(bytes.NewReader(ttlv)).Decode(v)
}
// Unmarshaler knows how to unmarshal a ttlv value into itself.
// The decoder argument may be used to decode the ttlv value into
// intermediary values if needed.
type Unmarshaler interface {
UnmarshalTTLV(d *Decoder, ttlv TTLV) error
}
// Decoder reads KMIP values from a stream, and decodes them into golang values.
// It currently only decodes TTLV encoded KMIP values.
// TODO: support decoding XML and JSON, so their decoding can be configured
//
// If DisallowExtraValues is true, the decoder will return an error when decoding
// Structures into structs and a matching field can't get found for every value.
type Decoder struct {
r io.Reader
bufr *bufio.Reader
DisallowExtraValues bool
currStruct reflect.Type
currField string
}
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
r: r,
bufr: bufio.NewReader(r),
}
}
// Reset resets the internal state of the decoder for reuse.
func (dec *Decoder) Reset(r io.Reader) {
*dec = Decoder{
r: r,
bufr: dec.bufr,
}
dec.bufr.Reset(r)
}
// Decode the first KMIP value from the reader into v.
// See Unmarshal for decoding rules.
func (dec *Decoder) Decode(v interface{}) error {
ttlv, err := dec.NextTTLV()
if err != nil {
return err
}
return dec.DecodeValue(v, ttlv)
}
// DecodeValue decodes a ttlv value into v. This doesn't read anything
// from the Decoder's reader.
// See Unmarshal for decoding rules.
func (dec *Decoder) DecodeValue(v interface{}, ttlv TTLV) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return merry.New("non-pointer passed to Decode")
}
return dec.unmarshal(val, ttlv)
}
func (dec *Decoder) unmarshal(val reflect.Value, ttlv TTLV) error {
if len(ttlv) == 0 {
return nil
}
// Load value from interface, but only if the result will be
// usefully addressable.
if val.Kind() == reflect.Interface && !val.IsNil() {
e := val.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() {
val = e
}
}
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
}
val = val.Elem()
}
if val.Type().Implements(unmarshalerType) {
return val.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) //nolint:forcetypeassert
}
if val.CanAddr() {
valAddr := val.Addr()
if valAddr.CanInterface() && valAddr.Type().Implements(unmarshalerType) {
return valAddr.Interface().(Unmarshaler).UnmarshalTTLV(dec, ttlv) //nolint:forcetypeassert
}
}
switch val.Kind() {
case reflect.Interface:
if ttlv.Type() == TypeStructure {
// if the value is a structure, set the whole TTLV
// as the value.
val.Set(reflect.ValueOf(ttlv))
} else {
// set blank interface equal to the TTLV.Value()
val.Set(reflect.ValueOf(ttlv.Value()))
}
return nil
case reflect.Slice:
typ := val.Type()
if typ.Elem() == byteType {
// []byte
break
}
// Slice of element values.
// Grow slice.
n := val.Len()
val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem())))
// Recur to read element into slice.
if err := dec.unmarshal(val.Index(n), ttlv); err != nil {
val.SetLen(n)
return err
}
return nil
default:
}
typeMismatchErr := func() error {
e := &UnmarshalerError{
Struct: dec.currStruct,
Field: dec.currField,
Tag: ttlv.Tag(),
Type: ttlv.Type(),
Val: val.Type(),
}
err := merry.WrapSkipping(e, 1).WithCause(ErrUnsupportedTypeError)
return err
}
switch ttlv.Type() {
case TypeStructure:
if val.Kind() != reflect.Struct {
return typeMismatchErr()
}
// stash currStruct
currStruct := dec.currStruct
err := dec.unmarshalStructure(ttlv, val)
// restore currStruct
dec.currStruct = currStruct
return err
case TypeInterval:
if val.Kind() != reflect.Int64 {
return typeMismatchErr()
}
val.SetInt(int64(ttlv.ValueInterval()))
case TypeDateTime, TypeDateTimeExtended:
if val.Type() != timeType {
return typeMismatchErr()
}
val.Set(reflect.ValueOf(ttlv.ValueDateTime()))
case TypeByteString:
if val.Kind() != reflect.Slice && val.Type().Elem() != byteType {
return typeMismatchErr()
}
val.SetBytes(ttlv.ValueByteString())
case TypeTextString:
if val.Kind() != reflect.String {
return typeMismatchErr()
}
val.SetString(ttlv.ValueTextString())
case TypeBoolean:
if val.Kind() != reflect.Bool {
return typeMismatchErr()
}
val.SetBool(ttlv.ValueBoolean())
// nolint:dupl
case TypeEnumeration:
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
i := int64(ttlv.ValueEnumeration())
if val.OverflowInt(i) {
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
}
val.SetInt(i)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
i := uint64(ttlv.ValueEnumeration())
if val.OverflowUint(i) {
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
}
val.SetUint(i)
default:
return typeMismatchErr()
}
// nolint:dupl
case TypeInteger:
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
i := int64(ttlv.ValueInteger())
if val.OverflowInt(i) {
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
}
val.SetInt(i)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
i := uint64(ttlv.ValueInteger())
if val.OverflowUint(i) {
return dec.newUnmarshalerError(ttlv, val.Type(), ErrIntOverflow)
}
val.SetUint(i)
default:
return typeMismatchErr()
}
case TypeLongInteger:
switch val.Kind() {
case reflect.Int64:
val.SetInt(ttlv.ValueLongInteger())
case reflect.Uint64:
val.SetUint(uint64(ttlv.ValueLongInteger()))
default:
return typeMismatchErr()
}
case TypeBigInteger:
if val.Type() != bigIntType {
return typeMismatchErr()
}
val.Set(reflect.ValueOf(*ttlv.ValueBigInteger()))
default:
return dec.newUnmarshalerError(ttlv, val.Type(), ErrInvalidType)
}
return nil
}
func (dec *Decoder) unmarshalStructure(ttlv TTLV, val reflect.Value) error {
ti, err := getTypeInfo(val.Type())
if err != nil {
return dec.newUnmarshalerError(ttlv, val.Type(), err)
}
if ti.tagField != nil && ti.tagField.ti.typ == tagType {
val.FieldByIndex(ti.tagField.index).Set(reflect.ValueOf(ttlv.Tag()))
}
fields := ti.valueFields
// push currStruct (caller will pop)
dec.currStruct = val.Type()
for n := ttlv.ValueStructure(); n != nil; n = n.Next() {
fldIdx := -1
for i := range fields {
if fields[i].flags.any() {
// if this is the first any field found, keep track
// of it as the current candidate match, but
// keep looking for a tag match
if fldIdx == -1 {
fldIdx = i
}
} else if fields[i].tag == n.Tag() {
// tag match found
// we can stop looking
fldIdx = i
break
}
}
if fldIdx > -1 {
// push currField
currField := dec.currField
dec.currField = fields[fldIdx].name
err := dec.unmarshal(val.FieldByIndex(fields[fldIdx].index), n)
// restore currField
dec.currField = currField
if err != nil {
return err
}
} else if dec.DisallowExtraValues {
return dec.newUnmarshalerError(ttlv, val.Type(), ErrUnexpectedValue)
}
}
return nil
}
// NextTTLV reads the next, full KMIP value off the reader.
func (dec *Decoder) NextTTLV() (TTLV, error) {
// first, read the header
header, err := dec.bufr.Peek(8)
if err != nil {
return nil, merry.Wrap(err)
}
if err := TTLV(header).ValidHeader(); err != nil {
// bad header, abort
return TTLV(header), merry.Prependf(err, "invalid header: %v", TTLV(header))
}
// allocate a buffer large enough for the entire message
fullLen := TTLV(header).FullLen()
buf := make([]byte, fullLen)
var totRead int
for {
n, err := dec.bufr.Read(buf[totRead:])
if err != nil {
return TTLV(buf), merry.Wrap(err)
}
totRead += n
if totRead >= fullLen {
// we've read off a single full message
return buf, nil
} // else keep reading
}
}
func (dec *Decoder) newUnmarshalerError(ttlv TTLV, valType reflect.Type, cause error) merry.Error {
e := &UnmarshalerError{
Struct: dec.currStruct,
Field: dec.currField,
Tag: ttlv.Tag(),
Type: ttlv.Type(),
Val: valType,
}
return merry.WrapSkipping(e, 1).WithCause(cause)
}
type UnmarshalerError struct {
// Val is the type of the destination value
Val reflect.Type
// Struct is the type of the containing struct if the value is a field
Struct reflect.Type
// Field is the name of the value field
Field string
Tag Tag
Type Type
}
func (e *UnmarshalerError) Error() string {
msg := "kmip: error unmarshaling " + e.Tag.String() + " with type " + e.Type.String() + " into value of type " + e.Val.Name()
if e.Struct != nil {
msg += " in struct field " + e.Struct.Name() + "." + e.Field
}
return msg
}

22
vendor/github.com/gemalto/kmip-go/ttlv/docs.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
// Package ttlv encodes and decodes the 3 wire formats defined in the KMIP specification:
//
// 1. TTLV (the default, binary wire format)
// 2. JSON
// 3. XML
//
// The core representation of KMIP values is the ttlv.TTLV type, which is
// a []byte encoded in the TTLV binary format. The ttlv.TTLV type knows how to marshal/
// unmarshal to and from the JSON and XML encoding formats.
//
// This package also knows how to marshal and unmarshal ttlv.TTLV values to golang structs,
// in a way similar to the json or xml packages.
//
// See Marshal() and Unmarshal() for the rules about how golang values map to KMIP TTLVs.
// Encoder and Decoder can be used to process streams of KMIP values.
//
// This package holds a registry of type, tag, and enum value names, which are used to transcode
// strings into these values. KMIP 1.4 names will be automatically loaded into the
// DefaultRegistry. See the kmip20 package to add definitions for 2.0 names.
//
// Print() and PrettyPrintHex() can be used to debug TTLV values.
package ttlv

962
vendor/github.com/gemalto/kmip-go/ttlv/encoder.go generated vendored Normal file
View File

@ -0,0 +1,962 @@
package ttlv
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"math"
"math/big"
"reflect"
"strings"
"time"
"github.com/ansel1/merry"
)
const structFieldTag = "ttlv"
var (
ErrIntOverflow = fmt.Errorf("value exceeds max int value %d", math.MaxInt32)
ErrUnsupportedEnumTypeError = errors.New("unsupported type for enums, must be string, or int types")
ErrUnsupportedTypeError = errors.New("marshaling/unmarshaling is not supported for this type")
ErrNoTag = errors.New("unable to determine tag for field")
ErrTagConflict = errors.New("tag conflict")
)
// Marshal encodes a golang value into a KMIP value.
//
// An error will be returned if v is an invalid pointer.
//
// Currently, Marshal does not support anonymous fields.
// Private fields are ignored.
//
// Marshal maps the golang value to a KMIP tag, type, and value
// encoding. To determine the KMIP tag, Marshal uses the same rules
// as Unmarshal.
//
// The appropriate type and encoding are inferred from the golang type
// and from the inferred KMIP tag, according to these rules:
//
// 1. If the value is a TTLV, it is copied byte for byte
// 2. If the value implements Marshaler, call that
// 3. If the struct field has an "omitempty" flag, and the value is
// zero, skip the field:
//
// type Foo struct {
// Comment string `ttlv:,omitempty`
// }
//
// 4. If the value is a slice (except []byte) or array, marshal all
// values concatenated
// 5. If a tag has not been inferred at this point, return *MarshalerError with
// cause ErrNoTag
// 6. If the Tag is registered as an enum, or has the "enum" struct tag flag, attempt
// to marshal as an Enumeration. int, int8, int16, int32, and their uint counterparts
// can be marshaled as an Enumeration. A string can be marshaled to an Enumeration
// if the string contains a number, a 4 byte (8 char) hex string with the prefix "0x",
// or the normalized name of an enum value registered to this tag. Examples:
//
// type Foo struct {
// CancellationResult string // will encode as an Enumeration because
// // the tag CancellationResult is registered
// // as an enum.
// C int `ttlv:"Comment,enum" // The tag Comment is not registered as an enum
// // but the enum flag will force this to encode
// // as an enumeration.
// }
//
// If the string can't be interpreted as an enum value, it will be encoded as a TextString. If
// the "enum" struct flag is set, the value *must* successfully encode to an Enumeration using
// above rules, or an error is returned.
// 7. If the Tag is registered as a bitmask, or has the "bitmask" struct tag flag, attempt
// to marshal to an Integer, following the same rules as for Enumerations. The ParseInt()
// function is used to parse string values.
// 9. time.Time marshals to DateTime. If the field has the "datetimeextended" struct flag,
// marshal as DateTimeExtended. Example:
//
// type Foo struct {
// ActivationDate time.Time `ttlv:",datetimeextended"`
// }
//
// 10. big.Int marshals to BigInteger
// 11. time.Duration marshals to Interval
// 12. string marshals to TextString
// 13. []byte marshals to ByteString
// 14. all int and uint variants except int64 and uint64 marshal to Integer. If the golang
// value overflows the KMIP value, *MarshalerError with cause ErrIntOverflow is returned
// 15. int64 and uint64 marshal to LongInteger
// 16. bool marshals to Boolean
// 17. structs marshal to Structure. Each field of the struct will be marshaled into the
// values of the Structure according to the above rules.
//
// Any other golang type will return *MarshalerError with cause ErrUnsupportedTypeError.
func Marshal(v interface{}) (TTLV, error) {
buf := bytes.NewBuffer(nil)
err := NewEncoder(buf).Encode(v)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Marshaler knows how to encode itself to TTLV.
// The implementation should use the primitive methods of the encoder,
// such as EncodeInteger(), etc.
//
// The tag inferred by the Encoder from the field or type information is
// passed as an argument, but the implementation can choose to ignore it.
type Marshaler interface {
MarshalTTLV(e *Encoder, tag Tag) error
}
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w}
}
// Encode a single value and flush to the writer. The tag will be inferred from
// the value. If no tag can be inferred, an error is returned.
// See Marshal for encoding rules.
func (e *Encoder) Encode(v interface{}) error {
return e.EncodeValue(TagNone, v)
}
// EncodeValue encodes a single value with the given tag and flushes it
// to the writer.
// See Marshal for encoding rules.
func (e *Encoder) EncodeValue(tag Tag, v interface{}) error {
err := e.encode(tag, reflect.ValueOf(v), nil)
if err != nil {
return err
}
return e.Flush()
}
// EncodeStructure encodes a Structure with the given tag to the writer.
// The function argument should encode the enclosed values inside the Structure.
// Call Flush() to write the data to the writer.
func (e *Encoder) EncodeStructure(tag Tag, f func(e *Encoder) error) error {
e.encodeDepth++
i := e.encBuf.begin(tag, TypeStructure)
err := f(e)
e.encBuf.end(i)
e.encodeDepth--
return err
}
// EncodeEnumeration, along with the other Encode<Type> methods, encodes a
// single KMIP value with the given tag to an internal buffer. These methods
// do not flush the data to the writer: call Flush() to flush the buffer.
func (e *Encoder) EncodeEnumeration(tag Tag, v uint32) {
e.encBuf.encodeEnum(tag, v)
}
func (e *Encoder) EncodeInteger(tag Tag, v int32) {
e.encBuf.encodeInt(tag, v)
}
func (e *Encoder) EncodeLongInteger(tag Tag, v int64) {
e.encBuf.encodeLongInt(tag, v)
}
func (e *Encoder) EncodeInterval(tag Tag, v time.Duration) {
e.encBuf.encodeInterval(tag, v)
}
func (e *Encoder) EncodeDateTime(tag Tag, v time.Time) {
e.encBuf.encodeDateTime(tag, v)
}
func (e *Encoder) EncodeDateTimeExtended(tag Tag, v time.Time) {
e.encBuf.encodeDateTimeExtended(tag, v)
}
func (e *Encoder) EncodeBigInteger(tag Tag, v *big.Int) {
e.encBuf.encodeBigInt(tag, v)
}
func (e *Encoder) EncodeBoolean(tag Tag, v bool) {
e.encBuf.encodeBool(tag, v)
}
func (e *Encoder) EncodeTextString(tag Tag, v string) {
e.encBuf.encodeTextString(tag, v)
}
func (e *Encoder) EncodeByteString(tag Tag, v []byte) {
e.encBuf.encodeByteString(tag, v)
}
// Flush flushes the internal encoding buffer to the writer.
func (e *Encoder) Flush() error {
if e.encodeDepth > 0 {
return nil
}
_, err := e.encBuf.WriteTo(e.w)
e.encBuf.Reset()
return err
}
type MarshalerError struct {
// Type is the golang type of the value being marshaled
Type reflect.Type
// Struct is the name of the enclosing struct if the marshaled value is a field.
Struct string
// Field is the name of the field being marshaled
Field string
Tag Tag
}
func (e *MarshalerError) Error() string {
msg := "kmip: error marshaling value"
if e.Type != nil {
msg += " of type " + e.Type.String()
}
if e.Struct != "" {
msg += " in struct field " + e.Struct + "." + e.Field
}
return msg
}
func (e *Encoder) marshalingError(tag Tag, t reflect.Type, cause error) merry.Error {
err := &MarshalerError{
Type: t,
Struct: e.currStruct,
Field: e.currField,
Tag: tag,
}
return merry.WrapSkipping(err, 1).WithCause(cause)
}
var (
byteType = reflect.TypeOf(byte(0))
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
bigIntPtrType = reflect.TypeOf((*big.Int)(nil))
bigIntType = bigIntPtrType.Elem()
durationType = reflect.TypeOf(time.Nanosecond)
ttlvType = reflect.TypeOf((*TTLV)(nil)).Elem()
tagType = reflect.TypeOf(Tag(0))
)
var invalidValue = reflect.Value{}
// indirect dives into interfaces values, and one level deep into pointers
// returns an invalid value if the resolved value is nil or invalid.
func indirect(v reflect.Value) reflect.Value {
if !v.IsValid() {
return v
}
if v.Kind() == reflect.Interface {
v = v.Elem()
}
if !v.IsValid() {
return v
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Func, reflect.Slice, reflect.Map, reflect.Chan, reflect.Ptr, reflect.Interface:
if v.IsNil() {
return invalidValue
}
default:
}
return v
}
var zeroBigInt = big.Int{}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
default:
}
switch v.Type() {
case timeType:
return v.Interface().(time.Time).IsZero() //nolint:forcetypeassert
case bigIntType:
i := v.Interface().(big.Int) //nolint:forcetypeassert
return zeroBigInt.Cmp(&i) == 0
}
return false
}
func (e *Encoder) encode(tag Tag, v reflect.Value, fi *fieldInfo) error {
// if pointer or interface
v = indirect(v)
if !v.IsValid() {
return nil
}
typ := v.Type()
if typ == ttlvType {
// fast path: if the value is TTLV, we write it directly to the output buffer
_, err := e.encBuf.Write(v.Bytes())
return err
}
typeInfo, err := getTypeInfo(typ)
if err != nil {
return err
}
if tag == TagNone {
tag = tagForMarshal(v, typeInfo, fi)
}
var flags fieldFlags
if fi != nil {
flags = fi.flags
}
// check for Marshaler
switch {
case typ.Implements(marshalerType):
if flags.omitEmpty() && isEmptyValue(v) {
return nil
}
return v.Interface().(Marshaler).MarshalTTLV(e, tag) //nolint:forcetypeassert
case v.CanAddr():
pv := v.Addr()
pvtyp := pv.Type()
if pvtyp.Implements(marshalerType) {
if flags.omitEmpty() && isEmptyValue(v) {
return nil
}
return pv.Interface().(Marshaler).MarshalTTLV(e, tag) //nolint:forcetypeassert
}
}
// If the type doesn't implement Marshaler, then validate the value is a supported kind
switch v.Kind() {
case reflect.Chan, reflect.Map, reflect.Func, reflect.Ptr, reflect.UnsafePointer, reflect.Uintptr, reflect.Float32,
reflect.Float64,
reflect.Complex64,
reflect.Complex128,
reflect.Interface:
return e.marshalingError(tag, v.Type(), ErrUnsupportedTypeError)
default:
}
// skip if value is empty and tags include omitempty
if flags.omitEmpty() && isEmptyValue(v) {
return nil
}
// recurse to handle slices of values
switch v.Kind() {
case reflect.Slice:
if typ.Elem() == byteType {
// special case, encode as a ByteString, handled below
break
}
fallthrough
case reflect.Array:
for i := 0; i < v.Len(); i++ {
// turn off the omit empty flag. applies at the field level,
// not to each member of the slice
// TODO: is this true?
var fi2 *fieldInfo
if fi != nil {
fi2 = &fieldInfo{}
// make a copy.
*fi2 = *fi
fi2.flags &^= fOmitEmpty
}
err := e.encode(tag, v.Index(i), fi2)
if err != nil {
return err
}
}
return nil
default:
}
if tag == TagNone {
return e.marshalingError(tag, v.Type(), ErrNoTag)
}
// handle enums and bitmasks
//
// If the field has the "enum" or "bitmask" flag, or the tag is registered as an enum or bitmask,
// attempt to interpret the go value as such.
//
// If the field is explicitly flag, return an error if the value can't be interpreted. Otherwise
// ignore errors and let processing fallthrough to the type-based encoding.
enumMap := DefaultRegistry.EnumForTag(tag)
if flags.enum() || flags.bitmask() || enumMap != nil {
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
i := v.Int()
if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) {
e.encBuf.encodeInt(tag, int32(i))
} else {
e.encBuf.encodeEnum(tag, uint32(i))
}
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
i := v.Uint()
if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) {
e.encBuf.encodeInt(tag, int32(i))
} else {
e.encBuf.encodeEnum(tag, uint32(i))
}
return nil
case reflect.String:
s := v.String()
if flags.bitmask() || (enumMap != nil && enumMap.Bitmask()) {
i, err := ParseInt(s, enumMap)
if err == nil {
e.encBuf.encodeInt(tag, i)
return nil
}
// only throw an error if the field is explicitly marked as a bitmask
// otherwise just ignore it, and let it encode as a string later on.
if flags.bitmask() {
// if we couldn't parse the string as an enum value
return e.marshalingError(tag, typ, err)
}
} else {
i, err := ParseEnum(s, enumMap)
if err == nil {
e.encBuf.encodeEnum(tag, i)
return nil
}
// only throw an error if the field is explicitly marked as an enum
// otherwise just ignore it, and let it encode as a string later on.
if flags.enum() {
// if we couldn't parse the string as an enum value
return e.marshalingError(tag, typ, err)
}
}
default:
if flags.enum() || flags.bitmask() {
return e.marshalingError(tag, typ, ErrUnsupportedEnumTypeError).Append(typ.String())
}
}
}
// handle special types
switch typ {
case timeType:
if flags.dateTimeExt() {
e.encBuf.encodeDateTimeExtended(tag, v.Interface().(time.Time)) //nolint:forcetypeassert
} else {
e.encBuf.encodeDateTime(tag, v.Interface().(time.Time)) //nolint:forcetypeassert
}
return nil
case bigIntType:
bi := v.Interface().(big.Int) //nolint:forcetypeassert
e.encBuf.encodeBigInt(tag, &bi)
return nil
case bigIntPtrType:
e.encBuf.encodeBigInt(tag, v.Interface().(*big.Int)) //nolint:forcetypeassert
return nil
case durationType:
e.encBuf.encodeInterval(tag, time.Duration(v.Int()))
return nil
}
// handle the rest of the kinds
switch typ.Kind() {
case reflect.Struct:
// push current struct onto stack
currStruct := e.currStruct
e.currStruct = typ.Name()
err = e.EncodeStructure(tag, func(e *Encoder) error {
for _, field := range typeInfo.valueFields {
fv := v.FieldByIndex(field.index)
// note: we're staying in reflection world here instead of
// converting back to an interface{} value and going through
// the non-reflection path again. Calling Interface()
// on the reflect value would make a potentially addressable value
// into an unaddressable value, reducing the chances we can coerce
// the value into a Marshalable.
//
// tl;dr
// Consider a type which implements Marshaler with
// a pointer receiver, and a struct with a non-pointer field of that type:
//
// type Wheel struct{}
// func (*Wheel) MarshalTTLV(...)
//
// type Car struct{
// Wheel Wheel
// }
//
// When traversing the Car struct, should the encoder invoke Wheel's
// Marshaler method, or not? Technically, the type `Wheel`
// doesn't implement the Marshaler interface. Only the type `*Wheel`
// implements it. However, the other encoders in the SDK, like JSON
// and XML, will try, if possible, to get a pointer to field values like this, in
// order to invoke the Marshaler interface anyway.
//
// Encoders can only get a pointer to field values if the field
// value is `addressable`. Addressability is explained in the docs for reflect.Value#CanAddr().
// Using reflection to turn a reflect.Value() back into an interface{}
// can make a potentially addressable value (like the field of an addressable struct)
// into an unaddressable value (reflect.Value#Interface{} always returns an unaddressable
// copy).
// push the currField
currField := e.currField
e.currField = field.name
err := e.encode(TagNone, fv, &field) //nolint:gosec,scopelint
// pop the currField
e.currField = currField
if err != nil {
return err
}
}
return nil
})
// pop current struct
e.currStruct = currStruct
return err
case reflect.String:
e.encBuf.encodeTextString(tag, v.String())
case reflect.Slice:
// special case, encode as a ByteString
// all slices which aren't []byte should have been handled above
// the call to v.Bytes() will panic if this assumption is wrong
e.encBuf.encodeByteString(tag, v.Bytes())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
i := v.Int()
if i > math.MaxInt32 {
return e.marshalingError(tag, typ, ErrIntOverflow)
}
e.encBuf.encodeInt(tag, int32(i))
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
u := v.Uint()
if u > math.MaxInt32 {
return e.marshalingError(tag, typ, ErrIntOverflow)
}
e.encBuf.encodeInt(tag, int32(u))
return nil
case reflect.Uint64:
u := v.Uint()
e.encBuf.encodeLongInt(tag, int64(u))
return nil
case reflect.Int64:
e.encBuf.encodeLongInt(tag, v.Int())
return nil
case reflect.Bool:
e.encBuf.encodeBool(tag, v.Bool())
default:
// all kinds should have been handled by now
panic(errors.New("should never get here"))
}
return nil
}
func tagForMarshal(v reflect.Value, ti typeInfo, fi *fieldInfo) Tag {
// the tag on the TTLVTag field
if ti.tagField != nil && ti.tagField.explicitTag != TagNone {
return ti.tagField.explicitTag
}
// the value of the TTLVTag field of type Tag
if v.IsValid() && ti.tagField != nil && ti.tagField.ti.typ == tagType {
tag := v.FieldByIndex(ti.tagField.index).Interface().(Tag) //nolint:forcetypeassert
if tag != TagNone {
return tag
}
}
// if value is in a struct field, infer the tag from the field
// else infer from the value's type name
if fi != nil {
return fi.tag
}
return ti.inferredTag
}
// encBuf encodes basic KMIP types into TTLV.
type encBuf struct {
bytes.Buffer
}
func (h *encBuf) begin(tag Tag, typ Type) int {
_ = h.WriteByte(byte(tag >> 16))
_ = h.WriteByte(byte(tag >> 8))
_ = h.WriteByte(byte(tag))
_ = h.WriteByte(byte(typ))
_, _ = h.Write(zeros[:4])
return h.Len()
}
func (h *encBuf) end(i int) {
n := h.Len() - i
if m := n % 8; m > 0 {
_, _ = h.Write(zeros[:8-m])
}
binary.BigEndian.PutUint32(h.Bytes()[i-4:], uint32(n))
}
func (h *encBuf) writeLongIntVal(tag Tag, typ Type, i int64) {
s := h.begin(tag, typ)
ll := h.Len()
_, _ = h.Write(zeros[:8])
binary.BigEndian.PutUint64(h.Bytes()[ll:], uint64(i))
h.end(s)
}
func (h *encBuf) writeIntVal(tag Tag, typ Type, val uint32) {
s := h.begin(tag, typ)
ll := h.Len()
_, _ = h.Write(zeros[:4])
binary.BigEndian.PutUint32(h.Bytes()[ll:], val)
h.end(s)
}
var (
ones = [8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
zeros = [8]byte{}
)
func (h *encBuf) encodeBigInt(tag Tag, i *big.Int) {
if i == nil {
return
}
ii := h.begin(tag, TypeBigInteger)
switch i.Sign() {
case 0:
_, _ = h.Write(zeros[:8])
case 1:
b := i.Bytes()
l := len(b)
// if n is positive, but the first bit is a 1, it will look like
// a negative in 2's complement, so prepend zeroes in front
if b[0]&0x80 > 0 {
_ = h.WriteByte(byte(0))
l++
}
// pad front with zeros to multiple of 8
if m := l % 8; m > 0 {
_, _ = h.Write(zeros[:8-m])
}
_, _ = h.Write(b)
case -1:
length := uint(i.BitLen()/8+1) * 8
j := new(big.Int).Lsh(one, length)
b := j.Add(i, j).Bytes()
// When the most significant bit is on a byte
// boundary, we can get some extra significant
// bits, so strip them off when that happens.
if len(b) >= 2 && b[0] == 0xff && b[1]&0x80 != 0 {
b = b[1:]
}
l := len(b)
// pad front with ones to multiple of 8
if m := l % 8; m > 0 {
_, _ = h.Write(ones[:8-m])
}
_, _ = h.Write(b)
}
h.end(ii)
}
func (h *encBuf) encodeInt(tag Tag, i int32) {
h.writeIntVal(tag, TypeInteger, uint32(i))
}
func (h *encBuf) encodeBool(tag Tag, b bool) {
if b {
h.writeLongIntVal(tag, TypeBoolean, 1)
} else {
h.writeLongIntVal(tag, TypeBoolean, 0)
}
}
func (h *encBuf) encodeLongInt(tag Tag, i int64) {
h.writeLongIntVal(tag, TypeLongInteger, i)
}
func (h *encBuf) encodeDateTime(tag Tag, t time.Time) {
h.writeLongIntVal(tag, TypeDateTime, t.Unix())
}
func (h *encBuf) encodeDateTimeExtended(tag Tag, t time.Time) {
// take unix seconds, times a million, to get microseconds, then
// add nanoseconds remainder/1000
//
// this gives us a larger ranger of possible values than just t.UnixNano() / 1000.
// see UnixNano() docs for its limits.
//
// this is limited to max(int64) *microseconds* from epoch, rather than
// max(int64) nanoseconds like UnixNano().
m := (t.Unix() * 1000000) + int64(t.Nanosecond()/1000)
h.writeLongIntVal(tag, TypeDateTimeExtended, m)
}
func (h *encBuf) encodeInterval(tag Tag, d time.Duration) {
h.writeIntVal(tag, TypeInterval, uint32(d/time.Second))
}
func (h *encBuf) encodeEnum(tag Tag, i uint32) {
h.writeIntVal(tag, TypeEnumeration, i)
}
func (h *encBuf) encodeTextString(tag Tag, s string) {
i := h.begin(tag, TypeTextString)
_, _ = h.WriteString(s)
h.end(i)
}
func (h *encBuf) encodeByteString(tag Tag, b []byte) {
if b == nil {
return
}
i := h.begin(tag, TypeByteString)
_, _ = h.Write(b)
h.end(i)
}
func getTypeInfo(typ reflect.Type) (ti typeInfo, err error) {
ti.inferredTag, _ = DefaultRegistry.ParseTag(typ.Name())
ti.typ = typ
err = ti.getFieldsInfo()
return ti, err
}
var errSkip = errors.New("skip")
func getFieldInfo(typ reflect.Type, sf reflect.StructField) (fieldInfo, error) {
var fi fieldInfo
// skip anonymous and unexported fields
if sf.Anonymous || /*unexported:*/ sf.PkgPath != "" {
return fi, errSkip
}
fi.name = sf.Name
fi.structType = typ
fi.index = sf.Index
var anyField bool
// handle field tags
parts := strings.Split(sf.Tag.Get(structFieldTag), ",")
for i, value := range parts {
if i == 0 {
switch value {
case "-":
// skip
return fi, errSkip
case "":
default:
var err error
fi.explicitTag, err = DefaultRegistry.ParseTag(value)
if err != nil {
return fi, err
}
}
} else {
switch strings.ToLower(value) {
case "enum":
fi.flags |= fEnum
case "omitempty":
fi.flags |= fOmitEmpty
case "datetimeextended":
fi.flags |= fDateTimeExtended
case "bitmask":
fi.flags |= fBitBask
case "any":
anyField = true
fi.flags |= fAny
}
}
}
if anyField && fi.explicitTag != TagNone {
return fi, merry.Here(ErrTagConflict).Appendf(`field %s.%s may not specify a TTLV tag and the "any" flag`, fi.structType.Name(), fi.name)
}
// extract type info for the field. The KMIP tag
// for this field is derived from either the field name,
// the field tags, or the field type.
var err error
fi.ti, err = getTypeInfo(sf.Type)
if err != nil {
return fi, err
}
if fi.ti.tagField != nil && fi.ti.tagField.explicitTag != TagNone {
fi.tag = fi.ti.tagField.explicitTag
if fi.explicitTag != TagNone && fi.explicitTag != fi.tag {
// if there was a tag on the struct field containing this value, it must
// agree with the value's intrinsic tag
return fi, merry.Here(ErrTagConflict).Appendf(`TTLV tag "%s" in tag of %s.%s conflicts with TTLV tag "%s" in %s.%s`, fi.explicitTag, fi.structType.Name(), fi.name, fi.ti.tagField.explicitTag, fi.ti.typ.Name(), fi.ti.tagField.name)
}
}
// pre-calculate the tag for this field. This intentional duplicates
// some of tagForMarshaling(). The value is primarily used in unmarshaling
// where the dynamic value of the field is not needed.
if fi.tag == TagNone {
fi.tag = fi.explicitTag
}
if fi.tag == TagNone {
fi.tag, _ = DefaultRegistry.ParseTag(fi.name)
}
return fi, nil
}
func (ti *typeInfo) getFieldsInfo() error {
if ti.typ.Kind() != reflect.Struct {
return nil
}
for i := 0; i < ti.typ.NumField(); i++ {
fi, err := getFieldInfo(ti.typ, ti.typ.Field(i))
switch {
case err == errSkip: //nolint:errorlint
// skip
case err != nil:
return err
case fi.name == "TTLVTag":
ti.tagField = &fi
default:
ti.valueFields = append(ti.valueFields, fi)
}
}
// verify that multiple fields don't have the same tag
names := map[Tag]string{}
for _, f := range ti.valueFields {
if f.flags.any() {
// ignore any fields
continue
}
tag := f.tag
if tag != TagNone {
if fname, ok := names[tag]; ok {
return merry.Here(ErrTagConflict).Appendf("field resolves to the same tag (%s) as other field (%s)", tag, fname)
}
names[tag] = f.name
}
}
return nil
}
type typeInfo struct {
typ reflect.Type
inferredTag Tag
tagField *fieldInfo
valueFields []fieldInfo
}
const (
fOmitEmpty fieldFlags = 1 << iota
fEnum
fDateTimeExtended
fAny
fBitBask
)
type fieldFlags int
func (f fieldFlags) omitEmpty() bool {
return f&fOmitEmpty != 0
}
func (f fieldFlags) any() bool {
return f&fAny != 0
}
func (f fieldFlags) dateTimeExt() bool {
return f&fDateTimeExtended != 0
}
func (f fieldFlags) enum() bool {
return f&fEnum != 0
}
func (f fieldFlags) bitmask() bool {
return f&fBitBask != 0
}
type fieldInfo struct {
structType reflect.Type
explicitTag, tag Tag
name string
index []int
flags fieldFlags
ti typeInfo
}

8
vendor/github.com/gemalto/kmip-go/ttlv/errors.go generated vendored Normal file
View File

@ -0,0 +1,8 @@
package ttlv
import "github.com/ansel1/merry"
// Details prints details from the error, including a stacktrace when available.
func Details(err error) string {
return merry.Details(err)
}

314
vendor/github.com/gemalto/kmip-go/ttlv/formatting.go generated vendored Normal file
View File

@ -0,0 +1,314 @@
package ttlv
import (
"fmt"
"strconv"
"strings"
"github.com/ansel1/merry"
"github.com/gemalto/kmip-go/internal/kmiputil"
)
// FormatType formats a byte as a KMIP Type string,
// as described in the KMIP Profiles spec. If the value is registered,
// the normalized name of the value will be returned.
//
// Otherwise, a 1 byte hex string is returned, but this is not
// technically a valid encoding for types in the JSON and XML encoding
// specs. Hex values Should only be used for debugging. Examples:
//
// - Integer
// - 0x42
func FormatType(b byte, enumMap EnumMap) string {
if enumMap != nil {
if s, ok := enumMap.Name(uint32(b)); ok {
return s
}
}
return fmt.Sprintf("%#02x", b)
}
// FormatTag formats an uint32 as a KMIP Tag string,
// as described in the KMIP Profiles spec. If the value is registered,
// the normalized name of the value will be returned. Otherwise, a
// 3 byte hex string is returned. Examples:
//
// - ActivationDate
// - 0x420001
func FormatTag(v uint32, enumMap EnumMap) string {
if enumMap != nil {
if s, ok := enumMap.Name(v); ok {
return s
}
}
return fmt.Sprintf("%#06x", v)
}
// FormatTagCanonical formats an uint32 as a canonical Tag name
// from the KMIP spec. If the value is registered,
// the canonical name of the value will be returned. Otherwise, a
// 3 byte hex string is returned. Examples:
//
// - Activation Date
// - 0x420001
//
// Canonical tag names are used in the AttributeName of Attribute structs.
func FormatTagCanonical(v uint32, enumMap EnumMap) string {
if enumMap != nil {
if s, ok := enumMap.CanonicalName(v); ok {
return s
}
}
return fmt.Sprintf("%#06x", v)
}
// FormatEnum formats an uint32 as a KMIP Enumeration string,
// as described in the KMIP Profiles spec. If the value is registered,
// the normalized name of the value will be returned. Otherwise, a
// four byte hex string is returned. Examples:
//
// - SymmetricKey
// - 0x00000002
func FormatEnum(v uint32, enumMap EnumMap) string {
if enumMap != nil {
if s, ok := enumMap.Name(v); ok {
return s
}
}
return fmt.Sprintf("%#08x", v)
}
// FormatInt formats an integer as a KMIP bitmask string, as
// described in the KMIP Profiles spec for JSON under
// the "Special case for Masks" section. Examples:
//
// - 0x0000100c
// - Encrypt|Decrypt|CertificateSign
// - CertificateSign|0x00000004|0x0000008
// - CertificateSign|0x0000000c
func FormatInt(i int32, enumMap EnumMap) string {
if enumMap == nil {
return fmt.Sprintf("%#08x", i)
}
values := enumMap.Values()
if len(values) == 0 {
return fmt.Sprintf("%#08x", i)
}
v := uint32(i)
// bitmask
// decompose mask into the names of set flags, concatenated by pipe
// if remaining value (minus registered flags) is not zero, append
// the remaining value as hex.
var sb strings.Builder
for _, v1 := range values {
if v1&v == v1 {
if name, ok := enumMap.Name(v1); ok {
if sb.Len() > 0 {
sb.WriteString("|")
}
sb.WriteString(name)
v ^= v1
}
}
if v == 0 {
break
}
}
if v != 0 {
if sb.Len() > 0 {
sb.WriteString("|")
}
_, _ = fmt.Fprintf(&sb, "%#08x", v)
}
return sb.String()
}
// ParseEnum parses a string into a uint32 according to the rules
// in the KMIP Profiles regarding encoding enumeration values.
// See FormatEnum for examples of the formats which can be parsed.
// It will also parse numeric strings. Examples:
//
// ParseEnum("UnableToCancel", registry.EnumForTag(TagCancellationResult))
// ParseEnum("0x00000002")
// ParseEnum("2")
//
// Returns ErrInvalidHexString if the string is invalid hex, or
// if the hex value is less than 1 byte or more than 4 bytes (ignoring
// leading zeroes).
//
// Returns ErrUnregisteredEnumName if string value is not a
// registered enum value name.
func ParseEnum(s string, enumMap EnumMap) (uint32, error) {
u, err := strconv.ParseUint(s, 10, 32)
if err == nil {
// it was a raw number
return uint32(u), nil
}
v, err := parseHexOrName(s, 4, enumMap)
if err != nil {
return 0, merry.Here(err)
}
return v, nil
}
// ParseInt parses a string into an int32 according the rules
// in the KMIP Profiles regarding encoding integers, including
// the special rules for bitmasks. See FormatInt for examples
// of the formats which can be parsed.
//
// Returns ErrInvalidHexString if the string is invalid hex, or
// if the hex value is less than 1 byte or more than 4 bytes (ignoring
// leading zeroes).
//
// Returns ErrUnregisteredEnumName if string value is not a
// registered enum value name.
func ParseInt(s string, enumMap EnumMap) (int32, error) {
i, err := strconv.ParseInt(s, 10, 32)
if err == nil {
// it was a raw number
return int32(i), nil
}
if !strings.ContainsAny(s, "| ") {
v, err := parseHexOrName(s, 4, enumMap)
if err != nil {
return 0, merry.Here(err)
}
return int32(v), nil
}
// split values, look up each, and recombine
s = strings.ReplaceAll(s, "|", " ")
parts := strings.Split(s, " ")
var v uint32
for _, part := range parts {
if len(part) == 0 {
continue
}
i, err := parseHexOrName(part, 4, enumMap)
if err != nil {
return 0, merry.Here(err)
}
v |= i
}
return int32(v), nil
}
func parseHexOrName(s string, max int, enumMap EnumMap) (uint32, error) {
b, err := kmiputil.ParseHexValue(s, max)
if err != nil {
return 0, err
}
if b != nil {
return kmiputil.DecodeUint32(b), nil
}
if enumMap != nil {
if v, ok := enumMap.Value(s); ok {
return v, nil
}
}
return 0, merry.Append(ErrUnregisteredEnumName, s)
}
// ParseTag parses a string into Tag according the rules
// in the KMIP Profiles regarding encoding tag values.
// See FormatTag for examples of the formats which can be parsed.
//
// Returns ErrInvalidHexString if the string is invalid hex, or
// if the hex value is less than 1 byte or more than 3 bytes (ignoring
// leading zeroes).
//
// Returns ErrUnregisteredEnumName if string value is not a
// registered enum value name.
func ParseTag(s string, enumMap EnumMap) (Tag, error) {
v, err := parseHexOrName(s, 3, enumMap)
if err != nil {
return 0, merry.Here(err)
}
return Tag(v), nil
}
// ParseType parses a string into Type according the rules
// in the KMIP Profiles regarding encoding type values.
// See FormatType for examples of the formats which can be parsed.
// This also supports parsing a hex string type (e.g. "0x01"), though
// this is not technically a valid encoding of a type in the spec.
//
// Returns ErrInvalidHexString if the string is invalid hex, or
// if the hex value is less than 1 byte or more than 3 bytes (ignoring
// leading zeroes).
//
// Returns ErrUnregisteredEnumName if string value is not a
// registered enum value name.
func ParseType(s string, enumMap EnumMap) (Type, error) {
b, err := kmiputil.ParseHexValue(s, 1)
if err != nil {
return 0, merry.Here(err)
}
if b != nil {
return Type(b[0]), nil
}
if enumMap != nil {
if v, ok := enumMap.Value(s); ok {
return Type(v), nil
}
}
return 0, merry.Here(ErrUnregisteredEnumName).Append(s)
}
// EnumMap defines a set of named enumeration values. Canonical names should
// be the name from the spec. Names should be in the normalized format
// described in the KMIP spec (see NormalizeName()).
//
//
// Value enumerations are used for encoding and decoding KMIP Enumeration values,
// KMIP Integer bitmask values, Types, and Tags.
type EnumMap interface {
// Name returns the normalized name for a value, e.g. AttributeName.
// If the name is not registered, it returns "", false.
Name(v uint32) (string, bool)
// CanonicalName returns the canonical name for the value from the spec,
// e.g. Attribute Name.
// If the name is not registered, it returns "", false
CanonicalName(v uint32) (string, bool)
// Value returns the value registered for the name argument. If there is
// no name registered for this value, it returns 0, false.
// The name argument may be the canonical name (e.g. "Cryptographic Algorithm") or
// the normalized name (e.g. "CryptographicAlgorithm").
Value(name string) (uint32, bool)
// Values returns the complete set of registered values. The order
// they are returned in will be the order they are encoded in when
// encoding bitmasks as strings.
Values() []uint32
// Bitmask returns true if this is an enumeration of bitmask flags.
Bitmask() bool
}

248
vendor/github.com/gemalto/kmip-go/ttlv/registry.go generated vendored Normal file
View File

@ -0,0 +1,248 @@
package ttlv
import (
"sort"
"github.com/ansel1/merry"
"github.com/gemalto/kmip-go/internal/kmiputil"
)
// DefaultRegistry holds the default mappings of types, tags, enums, and bitmasks
// to canonical names and normalized names from the KMIP spec. It is pre-populated with the 1.4 spec's
// values. It can be replaced, or additional values can be registered with it.
//
// It is not currently concurrent-safe, so replace or configure it early in your
// program.
var DefaultRegistry Registry
// nolint:gochecknoinits
func init() {
RegisterTypes(&DefaultRegistry)
}
var (
ErrInvalidHexString = kmiputil.ErrInvalidHexString
ErrUnregisteredEnumName = merry.New("unregistered enum name")
)
// NormalizeName tranforms KMIP names from the spec into the
// normalized form of the name. Typically, this means removing spaces,
// and replacing some special characters. The normalized form of the name
// is used in the JSON and XML encodings from the KMIP Profiles.
// The spec describes the normalization process in 5.4.1.1 and 5.5.1.1
func NormalizeName(s string) string {
return kmiputil.NormalizeName(s)
}
// Enum represents an enumeration of KMIP values (as uint32), and maps them
// to the canonical string names and the normalized string names of the
// value as declared in the KMIP specs.
// Enum is used to transpose values from strings to byte values, as required
// by the JSON and XML encodings defined in the KMIP Profiles spec.
// These mappings are also used to pretty print KMIP values, and to marshal
// and unmarshal enum and bitmask values to golang string values.
//
// Enum currently uses plain maps, so it is not thread safe to register new values
// concurrently. You should register all values at the start of your program before
// using this package concurrently.
//
// Enums are used in the KMIP spec for two purposes: for defining the possible values
// for values encoded as the KMIP Enumeration type, and for bitmask values. Bitmask
// values are encoded as Integers, but are really enum values bitwise-OR'd together.
//
// Enums are registered with a Registry. The code to register enums is typically
// generated by the kmipgen tool.
type Enum struct {
valuesToName map[uint32]string
valuesToCanonicalName map[uint32]string
nameToValue map[string]uint32
canonicalNamesToValue map[string]uint32
bitMask bool
}
func NewEnum() Enum {
return Enum{}
}
func NewBitmask() Enum {
return Enum{
bitMask: true,
}
}
// RegisterValue adds a mapping of a uint32 value to a name. The name will be
// processed by NormalizeName to produce the normalized enum value name as described
// in the KMIP spec.
func (e *Enum) RegisterValue(v uint32, name string) {
nn := NormalizeName(name)
if e.valuesToName == nil {
e.valuesToName = map[uint32]string{}
e.nameToValue = map[string]uint32{}
e.valuesToCanonicalName = map[uint32]string{}
e.canonicalNamesToValue = map[string]uint32{}
}
e.valuesToName[v] = nn
e.nameToValue[nn] = v
e.valuesToCanonicalName[v] = name
e.canonicalNamesToValue[name] = v
}
func (e *Enum) Name(v uint32) (string, bool) {
if e == nil {
return "", false
}
name, ok := e.valuesToName[v]
return name, ok
}
func (e *Enum) CanonicalName(v uint32) (string, bool) {
if e == nil {
return "", false
}
name, ok := e.valuesToCanonicalName[v]
return name, ok
}
func (e *Enum) Value(name string) (uint32, bool) {
if e == nil {
return 0, false
}
v, ok := e.nameToValue[name]
if !ok {
v, ok = e.canonicalNamesToValue[name]
}
return v, ok
}
func (e *Enum) Values() []uint32 {
values := make([]uint32, 0, len(e.valuesToName))
for v := range e.valuesToName {
values = append(values, v)
}
// Always list them in order of value so output is stable.
sort.Sort(uint32Slice(values))
return values
}
func (e *Enum) Bitmask() bool {
if e == nil {
return false
}
return e.bitMask
}
// Registry holds all the known tags, types, enums and bitmaps declared in
// a KMIP spec. It's used throughout the package to map values their canonical
// and normalized names.
type Registry struct {
enums map[Tag]EnumMap
tags Enum
types Enum
}
func (r *Registry) RegisterType(t Type, name string) {
r.types.RegisterValue(uint32(t), name)
}
func (r *Registry) RegisterTag(t Tag, name string) {
r.tags.RegisterValue(uint32(t), name)
}
func (r *Registry) RegisterEnum(t Tag, def EnumMap) {
if r.enums == nil {
r.enums = map[Tag]EnumMap{}
}
r.enums[t] = def
}
// EnumForTag returns the enum map registered for a tag. Returns
// nil if no map is registered for this tag.
func (r *Registry) EnumForTag(t Tag) EnumMap {
if r.enums == nil {
return nil
}
return r.enums[t]
}
func (r *Registry) IsBitmask(t Tag) bool {
if e := r.EnumForTag(t); e != nil {
return e.Bitmask()
}
return false
}
func (r *Registry) IsEnum(t Tag) bool {
if e := r.EnumForTag(t); e != nil {
return !e.Bitmask()
}
return false
}
func (r *Registry) Tags() EnumMap {
return &r.tags
}
func (r *Registry) Types() EnumMap {
return &r.types
}
func (r *Registry) FormatEnum(t Tag, v uint32) string {
return FormatEnum(v, r.EnumForTag(t))
}
func (r *Registry) FormatInt(t Tag, v int32) string {
return FormatInt(v, r.EnumForTag(t))
}
func (r *Registry) FormatTag(t Tag) string {
return FormatTag(uint32(t), &r.tags)
}
func (r *Registry) FormatTagCanonical(t Tag) string {
return FormatTagCanonical(uint32(t), &r.tags)
}
func (r *Registry) FormatType(t Type) string {
return FormatType(byte(t), &r.types)
}
func (r *Registry) ParseEnum(t Tag, s string) (uint32, error) {
return ParseEnum(s, r.EnumForTag(t))
}
func (r *Registry) ParseInt(t Tag, s string) (int32, error) {
return ParseInt(s, r.EnumForTag(t))
}
// ParseTag parses a string into Tag according the rules
// in the KMIP Profiles regarding encoding tag values.
// Returns TagNone if not found.
// Returns error if s is a malformed hex string, or a hex string of incorrect length
func (r *Registry) ParseTag(s string) (Tag, error) {
return ParseTag(s, &r.tags)
}
func (r *Registry) ParseType(s string) (Type, error) {
return ParseType(s, &r.types)
}
// uint32Slice attaches the methods of Interface to []int, sorting in increasing order.
type uint32Slice []uint32
func (p uint32Slice) Len() int { return len(p) }
func (p uint32Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

50
vendor/github.com/gemalto/kmip-go/ttlv/tag.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
package ttlv
const (
TagNone = Tag(0)
tagAttributeName Tag = 0x42000a
tagAttributeValue Tag = 0x42000b
)
// Tag
// 9.1.3.1
type Tag uint32
// String returns the normalized name of the tag.
func (t Tag) String() string {
return DefaultRegistry.FormatTag(t)
}
// CanonicalName returns the canonical name of the tag.
func (t Tag) CanonicalName() string {
return DefaultRegistry.FormatTagCanonical(t)
}
func (t Tag) MarshalText() (text []byte, err error) {
return []byte(t.String()), nil
}
func (t *Tag) UnmarshalText(text []byte) (err error) {
*t, err = DefaultRegistry.ParseTag(string(text))
return
}
const (
minStandardTag uint32 = 0x00420000
maxStandardTag uint32 = 0x00430000
minCustomTag uint32 = 0x00540000
maxCustomTag uint32 = 0x00550000
)
// Valid checks whether the tag's numeric value is valid according to
// the ranges in the spec.
func (t Tag) Valid() bool {
switch {
case uint32(t) >= minStandardTag && uint32(t) < maxStandardTag:
return true
case uint32(t) >= minCustomTag && uint32(t) < maxCustomTag:
return true
default:
return false
}
}

1252
vendor/github.com/gemalto/kmip-go/ttlv/ttlv.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

196
vendor/github.com/gemalto/kmip-go/ttlv/types.go generated vendored Normal file
View File

@ -0,0 +1,196 @@
package ttlv
import (
"io"
"time"
)
func RegisterTypes(r *Registry) {
m := map[string]Type{
"BigInteger": TypeBigInteger,
"Boolean": TypeBoolean,
"ByteString": TypeByteString,
"DateTime": TypeDateTime,
"Enumeration": TypeEnumeration,
"Integer": TypeInteger,
"Interval": TypeInterval,
"LongInteger": TypeLongInteger,
"Structure": TypeStructure,
"TextString": TypeTextString,
"DateTimeExtended": TypeDateTimeExtended,
}
for name, v := range m {
r.RegisterType(v, name)
}
}
// Type describes the type of a KMIP TTLV.
// 2 and 9.1.1.2
type Type byte
const (
TypeStructure Type = 0x01
TypeInteger Type = 0x02
TypeLongInteger Type = 0x03
TypeBigInteger Type = 0x04
TypeEnumeration Type = 0x05
TypeBoolean Type = 0x06
TypeTextString Type = 0x07
TypeByteString Type = 0x08
TypeDateTime Type = 0x09
TypeInterval Type = 0x0A
TypeDateTimeExtended Type = 0x0B
)
// String returns the normalized name of the type. If the type
// name isn't registered, it returns the hex value of the type,
// e.g. "0x01" (TypeStructure). The value of String() is suitable
// for use in the JSON or XML encoding of TTLV.
func (t Type) String() string {
return DefaultRegistry.FormatType(t)
}
func (t Type) MarshalText() (text []byte, err error) {
return []byte(t.String()), nil
}
func (t *Type) UnmarshalText(text []byte) (err error) {
*t, err = DefaultRegistry.ParseType(string(text))
return
}
// DateTimeExtended is a time wrapper which always marshals to a DateTimeExtended.
type DateTimeExtended struct {
time.Time
}
func (t *DateTimeExtended) UnmarshalTTLV(d *Decoder, ttlv TTLV) error {
if len(ttlv) == 0 {
return nil
}
if t == nil {
*t = DateTimeExtended{}
}
err := d.DecodeValue(&t.Time, ttlv)
if err != nil {
return err
}
return nil
}
func (t DateTimeExtended) MarshalTTLV(e *Encoder, tag Tag) error {
e.EncodeDateTimeExtended(tag, t.Time)
return nil
}
// Value is a go-typed mapping for a TTLV value. It holds a tag, and the value in
// the form of a native go type.
//
// Value supports marshaling and unmarshaling, allowing a mapping between encoded TTLV
// bytes and native go types. It's useful in tests, or where you want to construct
// an arbitrary TTLV structure in code without declaring a bespoke type, e.g.:
//
// v := ttlv.Value{Tag: TagBatchCount, Value: Values{
// Value{Tag: TagComment, Value: "red"},
// Value{Tag: TagComment, Value: "blue"},
// Value{Tag: TagComment, Value: "green"},
// }
// t, err := ttlv.Marshal(v)
//
// KMIP Structure types are mapped to the Values go type. When marshaling, if the Value
// field is set to a Values{}, the resulting TTLV will be TypeStructure. When unmarshaling
// a TTLV with TypeStructure, the Value field will be set to a Values{}.
type Value struct {
Tag Tag
Value interface{}
}
// UnmarshalTTLV implements Unmarshaler
func (t *Value) UnmarshalTTLV(d *Decoder, ttlv TTLV) error {
t.Tag = ttlv.Tag()
switch ttlv.Type() {
case TypeStructure:
var v Values
ttlv = ttlv.ValueStructure()
for ttlv.Valid() == nil {
err := d.DecodeValue(&v, ttlv)
if err != nil {
return err
}
ttlv = ttlv.Next()
}
t.Value = v
default:
t.Value = ttlv.Value()
}
return nil
}
// MarshalTTLV implements Marshaler
func (t Value) MarshalTTLV(e *Encoder, tag Tag) error {
// if tag is set, override the suggested tag
if t.Tag != TagNone {
tag = t.Tag
}
if tvs, ok := t.Value.(Values); ok {
return e.EncodeStructure(tag, func(e *Encoder) error {
for _, v := range tvs {
if err := e.Encode(v); err != nil {
return err
}
}
return nil
})
}
return e.EncodeValue(tag, t.Value)
}
// Values is a slice of Value objects. It represents the body of a TTLV with a type of Structure.
type Values []Value
// NewValue creates a new tagged value.
func NewValue(tag Tag, val interface{}) Value {
return Value{
Tag: tag,
Value: val,
}
}
// NewStruct creates a new tagged value which is of type struct.
func NewStruct(tag Tag, vals ...Value) Value {
return Value{
Tag: tag,
Value: Values(vals),
}
}
type Encoder struct {
encodeDepth int
w io.Writer
encBuf encBuf
// these fields store where the encoder is when marshaling a nested struct. its
// used to construct error messages.
currStruct string
currField string
}
// EnumValue is a uint32 wrapper which always encodes as an enumeration.
type EnumValue uint32
func (v EnumValue) MarshalTTLV(e *Encoder, tag Tag) error {
e.EncodeEnumeration(tag, uint32(v))
return nil
}

25
vendor/github.com/gemalto/kmip-go/types.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
package kmip
type Authentication struct {
Credential []Credential
}
type Nonce struct {
NonceID []byte
NonceValue []byte
}
type ProtocolVersion struct {
ProtocolVersionMajor int
ProtocolVersionMinor int
}
type MessageExtension struct {
VendorIdentification string
CriticalityIndicator bool
VendorExtension interface{}
}
type Attributes struct {
Attributes []Attribute
}

64
vendor/github.com/gemalto/kmip-go/types_messages.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
package kmip
import (
"time"
"github.com/gemalto/kmip-go/kmip14"
)
// 7.1
type RequestMessage struct {
RequestHeader RequestHeader
BatchItem []RequestBatchItem
}
type ResponseMessage struct {
ResponseHeader ResponseHeader
BatchItem []ResponseBatchItem
}
// 7.2
type RequestHeader struct {
ProtocolVersion ProtocolVersion
MaximumResponseSize int `ttlv:",omitempty"`
ClientCorrelationValue string `ttlv:",omitempty"`
ServerCorrelationValue string `ttlv:",omitempty"`
AsynchronousIndicator bool `ttlv:",omitempty"`
AttestationCapableIndicator bool `ttlv:",omitempty"`
AttestationType []kmip14.AttestationType
Authentication *Authentication
BatchErrorContinuationOption kmip14.BatchErrorContinuationOption `ttlv:",omitempty"`
BatchOrderOption bool `ttlv:",omitempty"`
TimeStamp *time.Time
BatchCount int
}
type RequestBatchItem struct {
Operation kmip14.Operation
UniqueBatchItemID []byte `ttlv:",omitempty"`
RequestPayload interface{}
MessageExtension *MessageExtension `ttlv:",omitempty"`
}
type ResponseHeader struct {
ProtocolVersion ProtocolVersion
TimeStamp time.Time
Nonce *Nonce
AttestationType []kmip14.AttestationType
ClientCorrelationValue string `ttlv:",omitempty"`
ServerCorrelationValue string `ttlv:",omitempty"`
BatchCount int
}
type ResponseBatchItem struct {
Operation kmip14.Operation `ttlv:",omitempty"`
UniqueBatchItemID []byte `ttlv:",omitempty"`
ResultStatus kmip14.ResultStatus
ResultReason kmip14.ResultReason `ttlv:",omitempty"`
ResultMessage string `ttlv:",omitempty"`
AsynchronousCorrelationValue []byte `ttlv:",omitempty"`
ResponsePayload interface{} `ttlv:",omitempty"`
MessageExtension *MessageExtension
}