diff --git a/README.md b/README.md index e822ec4..41117e6 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,25 @@ go-kmip go-kmip implements subset of [KMIP 1.4](http://docs.oasis-open.org/kmip/spec/v1.4/os/kmip-spec-v1.4-os.html) protocol. -Basic encoding/decoding is fully implemented, as well as the basic client/server implementations. Other operations and fields -could be implemented by adding required Go structures with KMIP tags. +Basic TTLV encoding/decoding is fully implemented, as well as the basic client/server operations. +Other operations and fields could be implemented by adding required Go structures with KMIP tags. -Note ----- +KMIP protocol is used to access KMS solutions: generating keys, certificates, +accessing stored objects, etc. -This is WIP at the moment. +KMIP is using TTLV-like encoding, which is implemented in this packaged +as encoding/decoding of Go struct types. Go struct fields are annotated with +`kmip` tags which specify KMIP tag names. Field is encoded/decoded according +to its tag, type. + +Two high-level objects are implemented: Server and Client. Server listens for +TLS connections, does initial handshake and processes batch requests from the +clients. Processing of specific operations is delegated to operation handlers. +Client objects establishes connection with the KMIP server and allows sending +any number of requests over the connection. + +This package doesn't implement any actual key processing or management - it's outside +the scope of this package. License ------- diff --git a/client.go b/client.go index cf99ebe..18bb0f7 100644 --- a/client.go +++ b/client.go @@ -98,6 +98,9 @@ func (c *Client) DiscoverVersions(versions []ProtocolVersion) (serverVersions [] // Request payload should be passed as req, and response payload will be // returned back as resp. Operation will be sent as a batch with single // item. +// +// Send is a generic method, it's better to implement specific methods for +// each operation (use DiscoverVersions as example). func (c *Client) Send(operation Enum, req interface{}) (resp interface{}, err error) { if c.conn == nil { err = errors.New("not connected") diff --git a/decode.go b/decode.go index cf13d60..a121794 100644 --- a/decode.go +++ b/decode.go @@ -15,6 +15,9 @@ import ( ) // Decoder implements KMIP protocol decoding +// +// Decoding works exactly the same way as encoding +// (see Encoder documentation), but the other way around. type Decoder struct { r io.Reader s io.ByteScanner @@ -235,11 +238,23 @@ func (d *Decoder) decodeValue(f field, t reflect.Type, ff reflect.Value) (n int, vv = reflect.ValueOf(val) switch vv.Type() { + case typeOfInt32: + f.typ = INTEGER + return d.decodeValue(f, t, ff) + case typeOfInt64: + f.typ = LONG_INTEGER + return d.decodeValue(f, t, ff) case typeOfEnum: f.typ = ENUMERATION return d.decodeValue(f, t, ff) - case typeOfInt32: - f.typ = INTEGER + case typeOfBool: + f.typ = BOOLEAN + return d.decodeValue(f, t, ff) + case typeOfBytes: + f.typ = BYTE_STRING + return d.decodeValue(f, t, ff) + case typeOfString: + f.typ = TEXT_STRING return d.decodeValue(f, t, ff) } diff --git a/doc.go b/doc.go index c777000..e06cb99 100644 --- a/doc.go +++ b/doc.go @@ -1,6 +1,24 @@ -// Package kmip implements KMIP low-level protocol +// Package kmip implements KMIP protocol package kmip /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// KMIP protocol is used to access KMS solutions: generating keys, certificates, +// accessing stored objects, etc. +// +// KMIP is using TTLV-like encoding, which is implemented in this packaged +// as encoding/decoding of Go struct types. Go struct fields are annotated with +// `kmip` tags which specify KMIP tag names. Field is encoded/decoded according +// to its tag, type. +// +// Two high-level objects are implemented: Server and Client. Server listens for +// TLS connections, does initial handshake and processes batch requests from the +// clients. Processing of specific operations is delegated to operation handlers. +// Client objects establishes connection with the KMIP server and allows sending +// any number of requests over the connection. +// +// Not all the KMIP operations have corresponding Go structs, missing ones should +// be added to operations.go, and dynamic type dispatch to +// RequestBatchItem/ResponseBatchItem.BuildFieldValue methods. diff --git a/encode.go b/encode.go index 1e307c5..ff22322 100644 --- a/encode.go +++ b/encode.go @@ -14,7 +14,26 @@ import ( "github.com/pkg/errors" ) -// Encoder implements basic type encoding to TTLV KMIP encoding +// Encoder implements encoding to TTLV KMIP protocol format +// +// All core types are supported: +// +// * Integer (int32) +// * Long Integer (int64) +// * Enumeration (Enum) +// * Boolean (bool) +// * Bytes ([]byte) +// * String (string) +// * Timestamp (time.Time) +// * Interval (time.Duration) +// +// Encoder processes Go structure, analyzing field tags and parsing out +// `kmip` Go struct tags, e.g.: +// Value string `kmip:"TAG_NAME,required"` +// KMIP TAG_NAME is looked up to find tag value, Go type is translated to +// respective KMIP core type (see above), length is automatically calculated. +// +// Fields with zero value which are not required are skipped while encoding. type Encoder struct { w io.Writer } diff --git a/keys.go b/keys.go index e6cd1af..9cea0fe 100644 --- a/keys.go +++ b/keys.go @@ -15,6 +15,18 @@ type KeyWrappingSpecification struct { EncodingOption Enum `kmip:"ENCODING_OPTION"` } +// KeyWrappingData is a Key Wrapping Data Object Structure +type KeyWrappingData struct { + Tag `kmip:"KEY_WRAPPING_DATA"` + + WrappingMethod Enum `kmip:"WRAPPING_METHOD,required"` + EncryptionKeyInformation EncryptionKeyInformation `kmip:"ENCRYPTION_KEY_INFORMATION"` + MACSignatureKeyInformation MACSignatureKeyInformation `kmip:"MAC_SIGNATURE_KEY_INFORMATION"` + MACSignature []byte `kmip:"MAC_SIGNATURE"` + IVCounterNonce []byte `kmip:"IV_COUNTER_NONCE"` + EncodingOption Enum `kmip:"ENCODING_OPTION"` +} + // EncryptionKeyInformation is a Key Wrapping Specification Object type EncryptionKeyInformation struct { Tag `kmip:"ENCRYPTION_KEY_INFORMATION"` @@ -33,6 +45,8 @@ type MACSignatureKeyInformation struct { // CryptoParams is a Cryptographic Parameters Attribute Structure type CryptoParams struct { + Tag `kmip:"CRYPTOGRAPHIC_PARAMETERS"` + BlockCipherMode Enum `kmip:"BLOCK_CIPHER_MODE"` PaddingMethod Enum `kmip:"PADDING_METHOD"` HashingAlgorithm Enum `kmip:"HASHING_ALGORITHM"` @@ -52,3 +66,22 @@ type CryptoParams struct { PSource []byte `kmip:"P_SOURCE"` TrailerFIeld int32 `kmip:"TRAILER_FIELD"` } + +// SymmetricKey is a Managed Cryptographic Object that is a symmetric key +type SymmetricKey struct { + Tag `kmip:"SYMMETRIC_KEY"` + + KeyBlock KeyBlock `kmip:"KEY_BLOCK,required"` +} + +// KeyBlock is a Key Block Object Structure +type KeyBlock struct { + Tag `kmip:"KEY_BLOCK"` + + FormatType Enum `kmip:"KEY_FORMAT_TYPE,required"` + CompressionType Enum `kmip:"KEY_COMPRESSION_TYPE"` + Value interface{} `kmip:"KEY_VALUE,required"` + CryptographicAlgorithm Enum `kmip:"CRYPTOGRAPHIC_ALGORITHM"` + CryptographicLength int32 `kmip:"CRYPTOGRAPHIC_LENGTH"` + WrappingData KeyWrappingData `kmip:"KEY_WRAPPING_SPECIFICATION"` +} diff --git a/operations.go b/operations.go index ba9fc35..6b77558 100644 --- a/operations.go +++ b/operations.go @@ -10,6 +10,13 @@ type CreateRequest struct { TemplateAttribute `kmip:"TEMPLATE_ATTRIBUTE,required"` } +// CreateResponse is a Create Response Payload +type CreateResponse struct { + ObjectType Enum `kmip:"OBJECT_TYPE,required"` + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER,required"` + TemplateAttribute `kmip:"TEMPLATE_ATTRIBUTE"` +} + // GetRequest is a Get Request Payload type GetRequest struct { UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER"` @@ -19,6 +26,47 @@ type GetRequest struct { KeyWrappingSpec KeyWrappingSpecification `kmip:"KEY_WRAPPING_SPECIFICATION"` } +// GetResponse is a Get Response Payload +type GetResponse struct { + ObjectType Enum `kmip:"OBJECT_TYPE,required"` + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER,required"` + // Response might contain one of SymmetricKey, Certificate, ... + SymmetricKey SymmetricKey `kmip:"SYMMETRIC_KEY"` +} + +// GetAttributesRequest is a Get Attributes Request Payload +type GetAttributesRequest struct { + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER"` + AttributeNames []string `kmip:"ATTRIBUTE_NAME"` +} + +// GetAttributesResponse is a Get Attributes Response Payload +type GetAttributesResponse struct { + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER,required"` + Attributes []Attribute `kmip:"ATTRIBUTE"` +} + +// GetAttributeListRequest is a Get Attribute List Request Payload +type GetAttributeListRequest struct { + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER"` +} + +// GetAttributeListResponse is a Get Attribute List Response Payload +type GetAttributeListResponse struct { + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER,required"` + AttributeNames []string `kmip:"ATTRIBUTE_NAME"` +} + +// DestroyRequest is a Destroy Request Payload +type DestroyRequest struct { + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER"` +} + +// DestroyResponse is a Destroy Response Payload +type DestroyResponse struct { + UniqueIdentifier string `kmip:"UNIQUE_IDENTIFIER,required"` +} + // DiscoverVersionsRequest is a Discover Versions Request Payload type DiscoverVersionsRequest struct { ProtocolVersions []ProtocolVersion `kmip:"PROTOCOL_VERSION"` diff --git a/request.go b/request.go index a5e498f..1a70da2 100644 --- a/request.go +++ b/request.go @@ -53,6 +53,12 @@ func (bi *RequestBatchItem) BuildFieldValue(name string) (v interface{}, err err v = &CreateRequest{} case OPERATION_GET: v = &GetRequest{} + case OPERATION_GET_ATTRIBUTES: + v = &GetAttributesRequest{} + case OPERATION_GET_ATTRIBUTE_LIST: + v = &GetAttributeListRequest{} + case OPERATION_DESTROY: + v = &DestroyRequest{} case OPERATION_DISCOVER_VERSIONS: v = &DiscoverVersionsRequest{} default: diff --git a/response.go b/response.go index aa2ce7c..d9e397b 100644 --- a/response.go +++ b/response.go @@ -1,15 +1,15 @@ package kmip +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + import ( "time" "github.com/pkg/errors" ) -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - // Response is a Response Message Structure type Response struct { Tag `kmip:"RESPONSE_MESSAGE"` @@ -46,6 +46,16 @@ type ResponseBatchItem struct { // BuildFieldValue builds value for ResponsePayload based on Operation func (bi *ResponseBatchItem) BuildFieldValue(name string) (v interface{}, err error) { switch bi.Operation { + case OPERATION_CREATE: + v = &CreateResponse{} + case OPERATION_GET: + v = &GetResponse{} + case OPERATION_GET_ATTRIBUTES: + v = &GetAttributesResponse{} + case OPERATION_GET_ATTRIBUTE_LIST: + v = &GetAttributeListResponse{} + case OPERATION_DESTROY: + v = &DestroyResponse{} case OPERATION_DISCOVER_VERSIONS: v = &DiscoverVersionsResponse{} default: