From 35ac7f72a77ae8a111b394a66ef7cad2a2e84218 Mon Sep 17 00:00:00 2001 From: Nicolae Nicora Date: Tue, 2 Dec 2025 09:59:05 +0100 Subject: [PATCH] feat: add support for KMIP 2.0 --- kmip/attributes.go | 27 ++ kmip/bitmasks.go | 79 +++-- kmip/consts.go | 1 + kmip/enums.go | 514 ++++++++++++++++++++++++++++- kmip/kmip.go | 70 +++- kmip/kmipclient/client.go | 2 +- kmip/kmipclient/middlewares.go | 2 +- kmip/kmipserver/router.go | 2 +- kmip/objects.go | 28 +- kmip/operations.go | 26 +- kmip/payloads/adjust_attribute.go | 35 ++ kmip/payloads/delegated_login.go | 37 +++ kmip/payloads/interop.go | 32 ++ kmip/payloads/log.go | 32 ++ kmip/payloads/login.go | 32 ++ kmip/payloads/logout.go | 32 ++ kmip/payloads/pkcs11.go | 32 ++ kmip/payloads/re_provision.go | 32 ++ kmip/payloads/set_attribute.go | 32 ++ kmip/payloads/set_endpoint_role.go | 32 ++ kmip/tags.go | 132 ++++++++ kmip/ttlv/decoder.go | 6 + kmip/ttlv/encoder.go | 1 + kmip/ttlv/encoding_json.go | 69 ++-- kmip/ttlv/encoding_text.go | 7 + kmip/ttlv/encoding_ttlv.go | 16 + kmip/ttlv/encoding_xml.go | 15 + kmip/ttlv/types.go | 6 + 28 files changed, 1268 insertions(+), 63 deletions(-) create mode 100644 kmip/payloads/adjust_attribute.go create mode 100644 kmip/payloads/delegated_login.go create mode 100644 kmip/payloads/interop.go create mode 100644 kmip/payloads/log.go create mode 100644 kmip/payloads/login.go create mode 100644 kmip/payloads/logout.go create mode 100644 kmip/payloads/pkcs11.go create mode 100644 kmip/payloads/re_provision.go create mode 100644 kmip/payloads/set_attribute.go create mode 100644 kmip/payloads/set_endpoint_role.go diff --git a/kmip/attributes.go b/kmip/attributes.go index 8276f5f..60b4555 100644 --- a/kmip/attributes.go +++ b/kmip/attributes.go @@ -80,6 +80,18 @@ const ( AttributeNameAlwaysSensitive AttributeName = "Always Sensitive" AttributeNameExtractable AttributeName = "Extractable" AttributeNameNeverExtractable AttributeName = "Never Extractable" + AttributeNameKeyFormatType AttributeName = "Key Format Type" + AttributeNameOpaqueDataType AttributeName = "Opaque Data Type" + + // KMIP 2.0 + AttributeNameCertificateAttributes AttributeName = "Certificate Attributes" + AttributeNameNISTKeyType AttributeName = "NIST Key Type" + AttributeNameProtectionLevel AttributeName = "Protection Level" + AttributeNameProtectionPeriod AttributeName = "Protection Period" + AttributeNameProtectionStorageMask AttributeName = "Protection Storage Mask" + AttributeNameProtectionQuantumSafe AttributeName = "Quantum Safe" + AttributeNameProtectionShortUniqueIdentifier AttributeName = "Short Unique Identifier" + AttributeNameProtectionVendorAttribute AttributeName = "Vendor Attribute" ) var AllAttributeNames = []AttributeName{ @@ -93,6 +105,10 @@ var AllAttributeNames = []AttributeName{ AttributeNameX509CertificateIssuer, AttributeNameDigitalSignatureAlgorithm, AttributeNameAlternativeName, AttributeNameKeyValuePresent, AttributeNameKeyValueLocation, AttributeNameOriginalCreationDate, AttributeNameRandomNumberGenerator, AttributeNamePKCS_12FriendlyName, AttributeNameDescription, AttributeNameComment, AttributeNameSensitive, AttributeNameAlwaysSensitive, AttributeNameExtractable, AttributeNameNeverExtractable, + + AttributeNameCertificateAttributes, AttributeNameKeyFormatType, AttributeNameNISTKeyType, AttributeNameOpaqueDataType, AttributeNameProtectionLevel, + AttributeNameProtectionPeriod, AttributeNameProtectionStorageMask, AttributeNameProtectionQuantumSafe, AttributeNameProtectionShortUniqueIdentifier, + AttributeNameProtectionVendorAttribute, } var attrTypes = map[AttributeName]reflect.Type{ @@ -150,6 +166,17 @@ var attrTypes = map[AttributeName]reflect.Type{ AttributeNameAlwaysSensitive: reflect.TypeFor[bool](), AttributeNameExtractable: reflect.TypeFor[bool](), AttributeNameNeverExtractable: reflect.TypeFor[bool](), + + AttributeNameCertificateAttributes: reflect.TypeFor[CertificateAttributes](), + AttributeNameKeyFormatType: reflect.TypeFor[KeyFormatType](), + AttributeNameNISTKeyType: reflect.TypeFor[NISTKeyType](), + AttributeNameOpaqueDataType: reflect.TypeFor[OpaqueDataType](), + AttributeNameProtectionLevel: reflect.TypeFor[ProtectionLevel](), + AttributeNameProtectionPeriod: reflect.TypeFor[time.Duration](), + AttributeNameProtectionStorageMask: reflect.TypeFor[ProtectionStorageMask](), + AttributeNameProtectionQuantumSafe: reflect.TypeFor[bool](), + AttributeNameProtectionShortUniqueIdentifier: reflect.TypeFor[[]byte](), + AttributeNameProtectionVendorAttribute: reflect.TypeFor[VendorAttribute](), } func newAttribute(name AttributeName) reflect.Value { diff --git a/kmip/bitmasks.go b/kmip/bitmasks.go index 14c1995..06276d5 100644 --- a/kmip/bitmasks.go +++ b/kmip/bitmasks.go @@ -10,6 +10,7 @@ import ( // init registers the bitmask string representations for CryptographicUsageMask and StorageStatusMask // with the KMIP TTLV package. This enables human-readable string formatting and parsing for these bitmask types. func init() { + ttlv.RegisterBitmask[CryptographicUsageMask]( TagCryptographicUsageMask, "Sign", @@ -32,12 +33,35 @@ func init() { "TranslateDecrypt", "TranslateWrap", "TranslateUnwrap", + "Authenticate", + "Unrestricted", + "FPEEncrypt", + "FPEDecrypt", ) + ttlv.RegisterBitmask[StorageStatusMask]( TagStorageStatusMask, "OnLineStorage", "ArchivalStorage", ) + + ttlv.RegisterBitmask[ProtectionStorageMask]( + TagProtectionStorageMask, + "Software", + "Hardware", + "OnProcessor", + "OnSystem", + "OffSystem", + "Hypervisor", + "OperatingSystem", + "Container", + "OnPremises", + "OffPremises", + "SelfManaged", + "Outsourced", + "Validated", + "SameJurisdiction", + ) } // CryptographicUsageMask represents a set of bitmask flags indicating the permitted cryptographic operations @@ -47,46 +71,31 @@ func init() { type CryptographicUsageMask int32 const ( - // CryptographicUsageSign allows the object to be used for signing operations. CryptographicUsageSign CryptographicUsageMask = 1 << iota - // CryptographicUsageVerify allows the object to be used for signature verification. CryptographicUsageVerify - // CryptographicUsageEncrypt allows the object to be used for encryption. CryptographicUsageEncrypt - // CryptographicUsageDecrypt allows the object to be used for decryption. CryptographicUsageDecrypt - // CryptographicUsageWrapKey allows the object to be used for key wrapping. CryptographicUsageWrapKey - // CryptographicUsageUnwrapKey allows the object to be used for key unwrapping. CryptographicUsageUnwrapKey - // CryptographicUsageExport allows the object to be exported. CryptographicUsageExport - // CryptographicUsageMACGenerate allows the object to be used for MAC generation. CryptographicUsageMACGenerate - // CryptographicUsageMACVerify allows the object to be used for verifying MAC. CryptographicUsageMACVerify - // CryptographicUsageDeriveKey allows the object to be used for key derivation. CryptographicUsageDeriveKey - // CryptographicUsageContentCommitment allows the object to be used for content commitment (non-repudiation). CryptographicUsageContentCommitment - // CryptographicUsageKeyAgreement allows the object to be used for key agreement. CryptographicUsageKeyAgreement - // CryptographicUsageCertificateSign allows the object to be used for certificate signing. CryptographicUsageCertificateSign - // CryptographicUsageCRLSign allows the object to be used for CRL signing. CryptographicUsageCRLSign - // CryptographicUsageGenerateCryptogram allows the object to be used for cryptogram generation. CryptographicUsageGenerateCryptogram - // CryptographicUsageValidateCryptogram allows the object to be used for cryptogram validation. CryptographicUsageValidateCryptogram - // CryptographicUsageTranslateEncrypt allows the object to be used for translation encryption. CryptographicUsageTranslateEncrypt - // CryptographicUsageTranslateDecrypt allows the object to be used for translation decryption. CryptographicUsageTranslateDecrypt - // CryptographicUsageTranslateWrap allows the object to be used for translation wrapping. CryptographicUsageTranslateWrap - // CryptographicUsageTranslateUnwrap allows the object to be used for translation unwrapping. CryptographicUsageTranslateUnwrap + // KMIP 2.0 + CryptographicUsageAuthenticate + CryptographicUsageUnrestricted + CryptographicUsageFPEEncrypt + CryptographicUsageFPEDecrypt ) // MarshalText returns a human-readable string representation of the CryptographicUsageMask. @@ -110,6 +119,9 @@ const ( StorageStatusOnlineStorage StorageStatusMask = 1 << iota // StorageStatusArchivalStorage indicates the object is in archival storage. StorageStatusArchivalStorage + + // KMIP 2.0 + StorageStatusDestroyedStorage ) // MarshalText returns a human-readable string representation of the StorageStatusMask. @@ -123,6 +135,33 @@ func (mask *StorageStatusMask) UnmarshalText(text []byte) error { return maskUnmarshalText(mask, TagStorageStatusMask, string(text)) } +type ProtectionStorageMask int32 + +const ( + ProtectionStorageSoftware ProtectionStorageMask = 1 << iota + ProtectionStorageHardware + ProtectionStorageOnProcessor + ProtectionStorageOnSystem + ProtectionStorageOffSystem + ProtectionStorageHypervisor + ProtectionStorageOperatingSystem + ProtectionStorageContainer + ProtectionStorageOnPremises + ProtectionStorageOffPremises + ProtectionStorageSelfManaged + ProtectionStorageOutsourced + ProtectionStorageValidated + ProtectionStorageSameJurisdiction +) + +func (mask ProtectionStorageMask) MarshalText() ([]byte, error) { + return []byte(ttlv.BitmaskStr(mask, " | ")), nil +} + +func (mask *ProtectionStorageMask) UnmarshalText(text []byte) error { + return maskUnmarshalText(mask, TagProtectionStorageMask, string(text)) +} + func maskUnmarshalText[T ~int32](mask *T, tag int, text string) error { var parts []string if strings.ContainsRune(text, '|') { diff --git a/kmip/consts.go b/kmip/consts.go index 01c1fc1..bc0bf6f 100644 --- a/kmip/consts.go +++ b/kmip/consts.go @@ -9,6 +9,7 @@ var ( V2_0 = ProtocolVersion{ProtocolVersionMajor: 2, ProtocolVersionMinor: 0} V2_1 = ProtocolVersion{ProtocolVersionMajor: 2, ProtocolVersionMinor: 1} V2_2 = ProtocolVersion{ProtocolVersionMajor: 2, ProtocolVersionMinor: 2} + V3_0 = ProtocolVersion{ProtocolVersionMajor: 3, ProtocolVersionMinor: 0} ) var ( diff --git a/kmip/enums.go b/kmip/enums.go index 3996aab..055cbca 100644 --- a/kmip/enums.go +++ b/kmip/enums.go @@ -46,6 +46,52 @@ func init() { ResultReasonSensitive: "Sensitive", ResultReasonNotExtractable: "NotExtractable", ResultReasonObjectAlreadyExists: "ObjectAlreadyExists", + //KMIP 2.0. + ResultReasonInvalidTicket: "InvalidTicket", + ResultReasonUsageLimitExceeded: "UsageLimitExceeded", + ResultReasonNumericRange: "NumericRange", + ResultReasonInvalidDataType: "InvalidDataType", + ResultReasonReadOnlyAttribute: "ReadOnlyAttribute", + ResultReasonMultiValuedAttribute: "MultiValuedAttribute", + ResultReasonUnsupportedAttribute: "UnsupportedAttribute", + ResultReasonAttributeInstanceNotFound: "AttributeInstanceNotFound", + ResultReasonAttributeNotFound: "AttributeNotFound", + ResultReasonAttributeReadOnly: "AttributeReadOnly", + ResultReasonAttributeSingleValued: "AttributeSingleValued", + ResultReasonBadCryptographicParameters: "BadCryptographicParameters", + ResultReasonBadPassword: "BadPassword", + ResultReasonCodecError: "CodecError", + ResultReasonIllegalObjectType: "IllegalObjectType", + ResultReasonIncompatibleCryptographicUsageMask: "IncompatibleCryptographicUsageMask", + ResultReasonInternalServerError: "InternalServerError", + ResultReasonInvalidAsynchronousCorrelationValue: "InvalidAsynchronousCorrelationValue", + ResultReasonInvalidAttribute: "InvalidAttribute", + ResultReasonInvalidAttributeValue: "InvalidAttributeValue", + ResultReasonInvalidCorrelationValue: "InvalidCorrelationValue", + ResultReasonInvalidCSR: "InvalidCSR", + ResultReasonInvalidObjectType: "InvalidObjectType", + ResultReasonKeyWrapTypeNotSupported: "KeyWrapTypeNotSupported", + ResultReasonMissingInitializationVector: "MissingInitializationVector", + ResultReasonNonUniqueNameAttribute: "NonUniqueNameAttribute", + ResultReasonObjectDestroyed: "ObjectDestroyed", + ResultReasonObjectNotFound: "ObjectNotFound", + ResultReasonNotAuthorised: "NotAuthorised", + ResultReasonServerLimitExceeded: "ServerLimitExceeded", + ResultReasonUnknownEnumeration: "UnknownEnumeration", + ResultReasonUnknownMessageExtension: "UnknownMessageExtension", + ResultReasonUnknownTagResultReason: "UnknownTagResultReason", + ResultReasonUnsupportedCryptographicParameters: "UnsupportedCryptographicParameters", + ResultReasonUnsupportedProtocolVersion: "UnsupportedProtocolVersion", + ResultReasonWrappingObjectArchived: "WrappingObjectArchived", + ResultReasonWrappingObjectDestroyed: "WrappingObjectDestroyed", + ResultReasonWrappingObjectNotFoundResultReason: "WrappingObjectNotFoundResultReason", + ResultReasonWrongKeyLifecycleStateResultReason: "WrongKeyLifecycleStateResultReason", + ResultReasonProtectionStorageUnavailable: "ProtectionStorageUnavailable", + ResultReasonPKCS11CodecError: "PKCS#11CodecError", + ResultReasonPKCS11InvalidFunction: "PKCS#11InvalidFunction", + ResultReasonPKCS11InvalidInterface: "PKCS#11InvalidInterface", + ResultReasonPrivateProtectionStorageUnavailable: "PrivateProtectionStorageUnavailable", + ResultReasonPublicProtectionStorageUnavailable: "PublicProtectionStorageUnavailable", }) ttlv.RegisterEnum(TagCredentialType, map[CredentialType]string{ CredentialTypeUsernameAndPassword: "UsernameAndPassword", @@ -53,6 +99,10 @@ func init() { CredentialTypeDevice: "Device", // KMIP 1.2. CredentialTypeAttestation: "Attestation", + // KMIP 2.0 + CredentialTypeOneTimePassword: "OneTimePassword", + CredentialTypeHashedPassword: "HashedPassword", + CredentialTypeTicket: "Ticket", }) ttlv.RegisterEnum(TagRevocationReasonCode, map[RevocationReasonCode]string{ RevocationReasonCodeUnspecified: "Unspecified", @@ -84,8 +134,12 @@ func init() { // KMIP 1.2. ObjectTypePGPKey: "PGPKey", + + // KMIP 2.0 + ObjectTypeCertificateRequest: "CertificateRequest", }) ttlv.RegisterEnum(TagOpaqueDataType, map[OpaqueDataType]string{}) + ttlv.RegisterEnum(TagState, map[State]string{ StatePreActive: "PreActive", StateActive: "Active", @@ -141,6 +195,21 @@ func init() { CryptographicAlgorithmHMAC_SHA3_512: "HMAC_SHA3_512", CryptographicAlgorithmSHAKE_128: "SHAKE_128", CryptographicAlgorithmSHAKE_256: "SHAKE_256", + + // KMIP 2.0. + CryptographicAlgorithmSM3: "SM3", + CryptographicAlgorithmSM4: "SM4", + CryptographicAlgorithmGOSTR34102012: "GOST_R_34_10_2012", + CryptographicAlgorithmGOSTR34112012: "GOST_R_34_11_2012", + CryptographicAlgorithmGOSTR34132015: "GOST_R_34_13_2015", + CryptographicAlgorithmGOST2814789: "GOST_28147_89", + CryptographicAlgorithmXMSS: "XMSS", + CryptographicAlgorithmSPHINCS256: "SPHINCS_256", + CryptographicAlgorithmMcEliece: "McEliece", + CryptographicAlgorithmMcEliece6960119: "McEliece_6960119", + CryptographicAlgorithmMcEliece8192128: "McEliece_8192128", + CryptographicAlgorithmEd25519: "Ed25519", + CryptographicAlgorithmEd448: "Ed448", }) ttlv.RegisterEnum(TagBlockCipherMode, map[BlockCipherMode]string{ BlockCipherModeCBC: "CBC", @@ -295,6 +364,8 @@ func init() { RecommendedCurveBRAINPOOLP384T1: "BRAINPOOLP384T1", RecommendedCurveBRAINPOOLP512R1: "BRAINPOOLP512R1", RecommendedCurveBRAINPOOLP512T1: "BRAINPOOLP512T1", + RecommendedCurveCURVE25519: "CURVE25519", + RecommendedCurveCURVE448: "CURVE448", }) ttlv.RegisterEnum(TagSecretDataType, map[SecretDataType]string{ SecretDataTypePassword: "Password", @@ -383,6 +454,10 @@ func init() { QueryFunctionProfiles: "QueryProfiles", QueryFunctionCapabilities: "QueryCapabilities", QueryFunctionClientRegistrationMethods: "QueryClientRegistrationMethods", + + //KMIP 2.0 + QueryFunctionDefaultsInformation: "QueryDefaultsInformation", + QueryFunctionStorageProtectionMasks: "QueryStorageProtectionMasks", }) ttlv.RegisterEnum(TagUsageLimitsUnit, map[UsageLimitsUnit]string{ UsageLimitsUnitByte: "Byte", @@ -650,6 +725,43 @@ func init() { ProfileNameJSONServerKMIPV1_4: "JSONServerKMIPV1_4", ProfileNameXMLClientKMIPV1_4: "XMLClientKMIPV1_4", ProfileNameXMLServerKMIPV1_4: "XMLServerKMIPV1_4", + ProfileNameCompleteServerBasic: "CompleteServerBasic", + ProfileNameCompleteServerTLSV1_2: "CompleteServerTLSV1_2", + ProfileNameTapeLibraryClient: "TapeLibraryClient", + ProfileNameTapeLibraryServer: "TapeLibraryServer", + ProfileNameSymmetricKeyLifecycleClient: "SymmetricKeyLifecycleClient", + ProfileNameSymmetricKeyLifecycleServer: "SymmetricKeyLifecycleServer", + ProfileNameAsymmetricKeyLifecycleClient: "AsymmetricKeyLifecycleClient", + ProfileNameAsymmetricKeyLifecycleServer: "AsymmetricKeyLifecycleServer", + ProfileNameBasicCryptographicClient: "BasicCryptographicClient", + ProfileNameBasicCryptographicServer: "BasicCryptographicServer", + ProfileNameAdvancedCryptographicClient: "AdvancedCryptographicClient", + ProfileNameAdvancedCryptographicServer: "AdvancedCryptographicServer", + ProfileNameRNGCryptographicClient: "RNGCryptographicClient", + ProfileNameRNGCryptographicServer: "RNGCryptographicServer", + ProfileNameBasicSymmetricKeyFoundryClient: "BasicSymmetricKeyFoundryClient", + ProfileNameIntermediateSymmetricKeyFoundryClient: "IntermediateSymmetricKeyFoundryClient", + ProfileNameAdvancedSymmetricKeyFoundryClient: "AdvancedSymmetricKeyFoundryClient", + ProfileNameSymmetricKeyFoundryServer: "SymmetricKeyFoundryServer", + ProfileNameOpaqueManagedObjectStoreClient: "OpaqueManagedObjectStoreClient", + ProfileNameOpaqueManagedObjectStoreServer: "OpaqueManagedObjectStoreServer", + ProfileNameStorageArrayWithSelfEncryptingDriveClient: "StorageArrayWithSelfEncryptingDriveClient", + ProfileNameStorageArrayWithSelfEncryptingDriveServer: "StorageArrayWithSelfEncryptingDriveServer", + ProfileNameHTTPSClient: "HTTPSClient", + ProfileNameHTTPSServer: "HTTPSServer", + ProfileNameJSONClient: "JSONClient", + ProfileNameJSONServer: "JSONServer", + ProfileNameXMLClient: "XMLClient", + ProfileNameXMLServer: "XMLServer", + ProfileNameAESXTSClient: "AESXTSClient", + ProfileNameAESXTSServer: "AESXTSServer", + ProfileNameQuantumSafeClient: "QuantumSafeClient", + ProfileNameQuantumSafeServer: "QuantumSafeServer", + ProfileNamePKCS11Client: "PKCS11Client", + ProfileNamePKCS11Server: "PKCS11Server", + ProfileNameBaselineClient: "BaselineClient", + ProfileNameBaselineServer: "BaselineServer", + ProfileNameCompleteServer: "CompleteServer", }) ttlv.RegisterEnum(TagValidationAuthorityType, map[ValidationAuthorityType]string{ ValidationAuthorityTypeUnspecified: "Unspecified", @@ -700,6 +812,104 @@ func init() { ttlv.RegisterEnum(TagKeyWrapType, map[KeyWrapType]string{ NotWrapped: "NotWrapped", AsRegistered: "AsRegistered"}) + + ttlv.RegisterEnum(TagAdjustmentType, map[AdjustmentType]string{ + Increment: "Increment", + Decrement: "Decrement", + Negate: "Negate", + }) + + ttlv.RegisterEnum(TagAdjustmentType, map[AsynchronousIndicator]string{ + Mandatory: "Mandatory", + Optional: "Optional", + Prohibited: "Prohibited", + }) + + ttlv.RegisterEnum(TagData, map[Data]string{ + DataDecrypt: "Decrypt", + DataEncrypt: "Encrypt", + DataHash: "Hash", + DataMACMACData: "MACMACData", + DataRNGRetrieve: "RNG_etrieve", + DataSignSignatureData: "SignSignatureData", + DataSignatureVerify: "SignatureVerify", + }) + + ttlv.RegisterEnum(TagDerivationMethod, map[DerivationMethod]string{ + PBKDF2: "PBKDF2", + HASH: "HASH", + HMAC: "HMAC", + ENCRYPT: "ENCRYPT", + NIST800108C: "NIST800-108-C", + NIST800108F: "NIST800-108-F", + NIST800108DPI: "NIST800-108-DPI", + AsymmetricKey: "AsymmetricKey", + AWSSignatureVersion4: "AWSSignatureVersion4", + HKDF: "HKDF", + }) + + ttlv.RegisterEnum(TagEndpointRole, map[EndpointRole]string{ + Client: "Client", + Server: "Server", + }) + + ttlv.RegisterEnum(TagInteropFunction, map[InteropFunction]string{ + Begin: "Begin", + End: "End", + Reset: "Reset", + }) + + ttlv.RegisterEnum(TagNISTKeyType, map[NISTKeyType]string{ + PrivateSignatureKey: "PrivateSignatureKey", + PublicSignatureVerificationKey: "PublicSignatureVerificationKey", + SymmetricAuthenticationKey: "SymmetricAuthenticationKey", + PrivateAuthenticationKey: "PrivateAuthenticationKey", + PublicAuthenticationKey: "PublicAuthenticationKey", + SymmetricDataEncryptionKey: "SymmetricDataEncryptionKey", + SymmetricKeyWrappingKey: "SymmetricKeyWrappingKey", + SymmetricRandomNumberGenerationKey: "SymmetricRandomNumberGenerationKey", + SymmetricMasterKey: "SymmetricMasterKey", + PrivateKeyTransportKey: "PrivateKeyTransportKey", + PublicKeyTransportKey: "PublicKeyTransportKey", + SymmetricKeyAgreementKey: "SymmetricKeyAgreementKey", + PrivateStaticKeyAgreementKey: "PrivateStaticKeyAgreementKey", + PublicStaticKeyAgreementKey: "PublicStaticKeyAgreementKey", + PrivateEphemeralKeyAgreementKey: "PrivateEphemeralKeyAgreementKey", + PublicEphemeralKeyAgreementKey: "PublicEphemeralKeyAgreementKey", + SymmetricAuthorizationKey: "SymmetricAuthorizationKey", + PrivateAuthorizationKey: "PrivateAuthorizationKey", + PublicAuthorizationKey: "PublicAuthorizationKey", + }) + + ttlv.RegisterEnum(TagProtectionLevel, map[ProtectionLevel]string{ + ProtectionLevelHigh: "High", + ProtectionLevelLow: "Low", + }) + + ttlv.RegisterEnum(TagTicketType, map[TicketType]string{ + TicketLogin: "Login", + }) + + ttlv.RegisterEnum(TagUniqueIdentifier, map[UniqueIdentifier]string{ + UniqueIdentifierIDPlaceholder: "IDPlaceholder", + UniqueIdentifierCertify: "Certify", + UniqueIdentifierCreate: "Create", + UniqueIdentifierCreateKeyPair: "CreateKeyPair", + UniqueIdentifierCreateKeyPairPrivateKey: "CreateKeyPairPrivateKey", + UniqueIdentifierCreateKeyPairPublicKey: "CreateKeyPairPublicKey", + UniqueIdentifierCreateSplitKey: "CreateSplitKey", + UniqueIdentifierDeriveKey: "DeriveKey", + UniqueIdentifierImport: "Import", + UniqueIdentifierJoinSplitKey: "JoinSplitKey", + UniqueIdentifierLocate: "Locate", + UniqueIdentifierRegister: "Register", + UniqueIdentifierReKey: "ReKey", + UniqueIdentifierReCertify: "ReCertify", + UniqueIdentifierReKeyKeyPair: "ReKeyKeyPair", + UniqueIdentifierReKeyKeyPairPrivateKey: "ReKeyKeyPairPrivateKey", + UniqueIdentifierReKeyKeyPairPublicKey: "ReKeyKeyPairPublicKey", + }) + } // ResultStatus represents the status of a KMIP operation result as defined by the KMIP specification. @@ -750,6 +960,53 @@ const ( ResultReasonNotExtractable ResultReason = 0x00000017 ResultReasonObjectAlreadyExists ResultReason = 0x00000018 + // KMIP 2.0. + ResultReasonInvalidTicket ResultReason = 0x00000019 + ResultReasonUsageLimitExceeded ResultReason = 0x0000001A + ResultReasonNumericRange ResultReason = 0x0000001B + ResultReasonInvalidDataType ResultReason = 0x0000001C + ResultReasonReadOnlyAttribute ResultReason = 0x0000001D + ResultReasonMultiValuedAttribute ResultReason = 0x0000001E + ResultReasonUnsupportedAttribute ResultReason = 0x0000001F + ResultReasonAttributeInstanceNotFound ResultReason = 0x00000020 + ResultReasonAttributeNotFound ResultReason = 0x00000021 + ResultReasonAttributeReadOnly ResultReason = 0x00000022 + ResultReasonAttributeSingleValued ResultReason = 0x00000023 + ResultReasonBadCryptographicParameters ResultReason = 0x00000024 + ResultReasonBadPassword ResultReason = 0x00000025 + ResultReasonCodecError ResultReason = 0x00000026 + ResultReasonIllegalObjectType ResultReason = 0x00000028 + ResultReasonIncompatibleCryptographicUsageMask ResultReason = 0x00000029 + ResultReasonInternalServerError ResultReason = 0x0000002A + ResultReasonInvalidAsynchronousCorrelationValue ResultReason = 0x0000002B + ResultReasonInvalidAttribute ResultReason = 0x0000002C + ResultReasonInvalidAttributeValue ResultReason = 0x0000002D + ResultReasonInvalidCorrelationValue ResultReason = 0x0000002E + ResultReasonInvalidCSR ResultReason = 0x0000002F + ResultReasonInvalidObjectType ResultReason = 0x00000030 + ResultReasonKeyWrapTypeNotSupported ResultReason = 0x00000032 + ResultReasonMissingInitializationVector ResultReason = 0x00000034 + ResultReasonNonUniqueNameAttribute ResultReason = 0x00000035 + ResultReasonObjectDestroyed ResultReason = 0x00000036 + ResultReasonObjectNotFound ResultReason = 0x00000037 + ResultReasonNotAuthorised ResultReason = 0x00000039 + ResultReasonServerLimitExceeded ResultReason = 0x0000003A + ResultReasonUnknownEnumeration ResultReason = 0x0000003B + ResultReasonUnknownMessageExtension ResultReason = 0x0000003C + ResultReasonUnknownTagResultReason = 0x0000003D + ResultReasonUnsupportedCryptographicParameters ResultReason = 0x0000003E + ResultReasonUnsupportedProtocolVersion ResultReason = 0x0000003F + ResultReasonWrappingObjectArchived ResultReason = 0x00000040 + ResultReasonWrappingObjectDestroyed ResultReason = 0x00000041 + ResultReasonWrappingObjectNotFoundResultReason = 0x00000042 + ResultReasonWrongKeyLifecycleStateResultReason = 0x00000043 + ResultReasonProtectionStorageUnavailable ResultReason = 0x00000044 + ResultReasonPKCS11CodecError ResultReason = 0x00000045 + ResultReasonPKCS11InvalidFunction ResultReason = 0x00000046 + ResultReasonPKCS11InvalidInterface ResultReason = 0x00000047 + ResultReasonPrivateProtectionStorageUnavailable ResultReason = 0x00000048 + ResultReasonPublicProtectionStorageUnavailable ResultReason = 0x00000049 + ResultReasonGeneralFailure ResultReason = 0x00000100 ) @@ -761,6 +1018,11 @@ const ( CredentialTypeDevice CredentialType = 0x00000002 // KMIP 1.2. CredentialTypeAttestation CredentialType = 0x00000003 + + //KMIP 2.0 + CredentialTypeOneTimePassword CredentialType = 0x00000004 + CredentialTypeHashedPassword CredentialType = 0x00000005 + CredentialTypeTicket CredentialType = 0x00000006 ) type RevocationReasonCode uint32 @@ -804,6 +1066,9 @@ const ( ObjectTypeOpaqueObject ObjectType = 0x00000008 // KMIP 1.2. ObjectTypePGPKey ObjectType = 0x00000009 + + // KMIP 2.0. + ObjectTypeCertificateRequest ObjectType = 0x0000000A ) type OpaqueDataType uint32 @@ -870,6 +1135,21 @@ const ( CryptographicAlgorithmHMAC_SHA3_512 CryptographicAlgorithm = 0x00000026 CryptographicAlgorithmSHAKE_128 CryptographicAlgorithm = 0x00000027 CryptographicAlgorithmSHAKE_256 CryptographicAlgorithm = 0x00000028 + + // KMIP 2.0. + CryptographicAlgorithmSM3 = 0x0000002C + CryptographicAlgorithmSM4 = 0x0000002D + CryptographicAlgorithmGOSTR34102012 = 0x0000002E + CryptographicAlgorithmGOSTR34112012 = 0x0000002F + CryptographicAlgorithmGOSTR34132015 = 0x00000030 + CryptographicAlgorithmGOST2814789 = 0x00000031 + CryptographicAlgorithmXMSS = 0x00000032 + CryptographicAlgorithmSPHINCS256 = 0x00000033 + CryptographicAlgorithmMcEliece = 0x00000034 + CryptographicAlgorithmMcEliece6960119 = 0x00000035 + CryptographicAlgorithmMcEliece8192128 = 0x00000036 + CryptographicAlgorithmEd25519 = 0x00000037 + CryptographicAlgorithmEd448 = 0x00000038 ) type BlockCipherMode uint32 @@ -1041,6 +1321,10 @@ const ( RecommendedCurveBRAINPOOLP384T1 RecommendedCurve = 0x00000042 RecommendedCurveBRAINPOOLP512R1 RecommendedCurve = 0x00000043 RecommendedCurveBRAINPOOLP512T1 RecommendedCurve = 0x00000044 + + // KMIP 2.0 + RecommendedCurveCURVE25519 RecommendedCurve = 0x00000045 + RecommendedCurveCURVE448 RecommendedCurve = 0x00000046 ) // Bitlen returns the bit length for the key using the curve. @@ -1206,7 +1490,7 @@ const ( LinkTypePKCS_12CertificateLink LinkType = 0x0000010C LinkTypePKCS_12PasswordLink LinkType = 0x0000010D - //FIXME: This is defined in KMIP 2.0+ only. + // KMPI 2.0. LinkTypeWrappingKeyLink LinkType = 0x0000010E ) @@ -1229,6 +1513,10 @@ const ( QueryFunctionProfiles QueryFunction = 0x0000000A QueryFunctionCapabilities QueryFunction = 0x0000000B QueryFunctionClientRegistrationMethods QueryFunction = 0x0000000C + + // KMIP 2.0 + QueryFunctionDefaultsInformation QueryFunction = 0x0000000D + QueryFunctionStorageProtectionMasks QueryFunction = 0x0000000E ) type UsageLimitsUnit uint32 @@ -1550,6 +1838,47 @@ const ( ProfileNameJSONServerKMIPV1_4 ProfileName = 0x0000009A ProfileNameXMLClientKMIPV1_4 ProfileName = 0x0000009B ProfileNameXMLServerKMIPV1_4 ProfileName = 0x0000009C + + // KMIP 2.0. + // (Reserved) 00000001-00000103 + ProfileNameCompleteServerBasic ProfileName = 0x00000104 + ProfileNameCompleteServerTLSV1_2 ProfileName = 0x00000105 + ProfileNameTapeLibraryClient ProfileName = 0x00000106 + ProfileNameTapeLibraryServer ProfileName = 0x00000107 + ProfileNameSymmetricKeyLifecycleClient ProfileName = 0x00000108 + ProfileNameSymmetricKeyLifecycleServer ProfileName = 0x00000109 + ProfileNameAsymmetricKeyLifecycleClient ProfileName = 0x0000010A + ProfileNameAsymmetricKeyLifecycleServer ProfileName = 0x0000010B + ProfileNameBasicCryptographicClient ProfileName = 0x0000010C + ProfileNameBasicCryptographicServer ProfileName = 0x0000010D + ProfileNameAdvancedCryptographicClient ProfileName = 0x0000010E + ProfileNameAdvancedCryptographicServer ProfileName = 0x0000010F + ProfileNameRNGCryptographicClient ProfileName = 0x00000110 + ProfileNameRNGCryptographicServer ProfileName = 0x00000111 + ProfileNameBasicSymmetricKeyFoundryClient ProfileName = 0x00000112 + ProfileNameIntermediateSymmetricKeyFoundryClient ProfileName = 0x00000113 + ProfileNameAdvancedSymmetricKeyFoundryClient ProfileName = 0x00000114 + ProfileNameSymmetricKeyFoundryServer ProfileName = 0x00000115 + ProfileNameOpaqueManagedObjectStoreClient ProfileName = 0x00000116 + ProfileNameOpaqueManagedObjectStoreServer ProfileName = 0x00000117 + //(Reserved) 00000118 - 0000011B + ProfileNameStorageArrayWithSelfEncryptingDriveClient ProfileName = 0x0000011C + ProfileNameStorageArrayWithSelfEncryptingDriveServer ProfileName = 0x0000011D + ProfileNameHTTPSClient ProfileName = 0x0000011E + ProfileNameHTTPSServer ProfileName = 0x0000011F + ProfileNameJSONClient ProfileName = 0x00000120 + ProfileNameJSONServer ProfileName = 0x00000121 + ProfileNameXMLClient ProfileName = 0x00000122 + ProfileNameXMLServer ProfileName = 0x00000123 + ProfileNameAESXTSClient ProfileName = 0x00000124 + ProfileNameAESXTSServer ProfileName = 0x00000125 + ProfileNameQuantumSafeClient ProfileName = 0x00000126 + ProfileNameQuantumSafeServer ProfileName = 0x00000127 + ProfileNamePKCS11Client ProfileName = 0x00000128 + ProfileNamePKCS11Server ProfileName = 0x00000129 + ProfileNameBaselineClient ProfileName = 0x0000012A + ProfileNameBaselineServer ProfileName = 0x0000012B + ProfileNameCompleteServer ProfileName = 0x0000012C ) type ValidationAuthorityType uint32 @@ -1631,6 +1960,124 @@ const ( AsRegistered KeyWrapType = 0x00000002 ) +// KMIP 2.0 +type AdjustmentType uint32 + +const ( + Increment AdjustmentType = 0x00000001 + Decrement AdjustmentType = 0x00000002 + Negate AdjustmentType = 0x00000003 +) + +type AsynchronousIndicator uint32 + +const ( + Mandatory AsynchronousIndicator = 0x00000001 + Optional AsynchronousIndicator = 0x00000002 + Prohibited AsynchronousIndicator = 0x00000003 +) + +type Data uint32 + +const ( + DataDecrypt Data = 0x00000001 + DataEncrypt Data = 0x00000002 + DataHash Data = 0x00000003 + DataMACMACData Data = 0x00000004 + DataRNGRetrieve Data = 0x00000005 + DataSignSignatureData Data = 0x00000006 + DataSignatureVerify Data = 0x00000007 +) + +type DerivationMethod uint32 + +const ( + PBKDF2 DerivationMethod = 0x00000001 + HASH DerivationMethod = 0x00000002 + HMAC DerivationMethod = 0x00000003 + ENCRYPT DerivationMethod = 0x00000004 + NIST800108C DerivationMethod = 0x00000005 + NIST800108F DerivationMethod = 0x00000006 + NIST800108DPI DerivationMethod = 0x00000007 + AsymmetricKey DerivationMethod = 0x00000008 + AWSSignatureVersion4 DerivationMethod = 0x00000009 + HKDF DerivationMethod = 0x0000000A +) + +type EndpointRole uint32 + +const ( + Client EndpointRole = 0x00000001 + Server EndpointRole = 0x00000002 +) + +type InteropFunction uint32 + +const ( + Begin InteropFunction = 0x00000001 + End InteropFunction = 0x00000002 + Reset InteropFunction = 0x00000003 +) + +type NISTKeyType uint32 + +const ( + PrivateSignatureKey NISTKeyType = 0x00000001 + PublicSignatureVerificationKey NISTKeyType = 0x00000002 + SymmetricAuthenticationKey NISTKeyType = 0x00000003 + PrivateAuthenticationKey NISTKeyType = 0x00000004 + PublicAuthenticationKey NISTKeyType = 0x00000005 + SymmetricDataEncryptionKey NISTKeyType = 0x00000006 + SymmetricKeyWrappingKey NISTKeyType = 0x00000007 + SymmetricRandomNumberGenerationKey NISTKeyType = 0x00000008 + SymmetricMasterKey NISTKeyType = 0x00000009 + PrivateKeyTransportKey NISTKeyType = 0x0000000A + PublicKeyTransportKey NISTKeyType = 0x0000000B + SymmetricKeyAgreementKey NISTKeyType = 0x0000000C + PrivateStaticKeyAgreementKey NISTKeyType = 0x0000000D + PublicStaticKeyAgreementKey NISTKeyType = 0x0000000E + PrivateEphemeralKeyAgreementKey NISTKeyType = 0x0000000F + PublicEphemeralKeyAgreementKey NISTKeyType = 0x00000010 + SymmetricAuthorizationKey NISTKeyType = 0x00000011 + PrivateAuthorizationKey NISTKeyType = 0x00000012 + PublicAuthorizationKey NISTKeyType = 0x00000013 +) + +type ProtectionLevel uint32 + +const ( + ProtectionLevelHigh ProtectionLevel = 0x00000001 + ProtectionLevelLow ProtectionLevel = 0x00000002 +) + +type TicketType uint32 + +const ( + TicketLogin TicketType = 0x00000001 +) + +type UniqueIdentifier uint32 + +const ( + UniqueIdentifierIDPlaceholder UniqueIdentifier = 0x00000001 + UniqueIdentifierCertify UniqueIdentifier = 0x00000002 + UniqueIdentifierCreate UniqueIdentifier = 0x00000003 + UniqueIdentifierCreateKeyPair UniqueIdentifier = 0x00000004 + UniqueIdentifierCreateKeyPairPrivateKey UniqueIdentifier = 0x00000005 + UniqueIdentifierCreateKeyPairPublicKey UniqueIdentifier = 0x00000006 + UniqueIdentifierCreateSplitKey UniqueIdentifier = 0x00000007 + UniqueIdentifierDeriveKey UniqueIdentifier = 0x00000008 + UniqueIdentifierImport UniqueIdentifier = 0x00000009 + UniqueIdentifierJoinSplitKey UniqueIdentifier = 0x0000000A + UniqueIdentifierLocate UniqueIdentifier = 0x0000000B + UniqueIdentifierRegister UniqueIdentifier = 0x0000000C + UniqueIdentifierReKey UniqueIdentifier = 0x0000000D + UniqueIdentifierReCertify UniqueIdentifier = 0x0000000E + UniqueIdentifierReKeyKeyPair UniqueIdentifier = 0x0000000F + UniqueIdentifierReKeyKeyPairPrivateKey UniqueIdentifier = 0x00000010 + UniqueIdentifierReKeyKeyPairPublicKey UniqueIdentifier = 0x00000011 +) + // Text Marshaling for better display in json outputs. // Test UnmarshalText for return enums from json intputs. @@ -1914,7 +2361,70 @@ func (enum KeyWrapType) MarshalText() ([]byte, error) { return marshalText(enum) } func (enum *KeyWrapType) UnmarshalText(text []byte) error { - return unmarshalText(enum, int(TagKeyWrapType), string(text)) + return unmarshalText(enum, TagKeyWrapType, string(text)) +} +func (enum AdjustmentType) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *AdjustmentType) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagAdjustmentType, string(text)) +} +func (enum AsynchronousIndicator) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *AsynchronousIndicator) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagAsynchronousIndicator, string(text)) +} +func (enum Data) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *Data) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagData, string(text)) +} +func (enum DerivationMethod) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *DerivationMethod) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagDerivationMethod, string(text)) +} +func (enum EndpointRole) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *EndpointRole) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagEndpointRole, string(text)) +} +func (enum InteropFunction) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *InteropFunction) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagInteropFunction, string(text)) +} +func (enum NISTKeyType) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *NISTKeyType) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagNISTKeyType, string(text)) +} + +func (enum ProtectionLevel) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *ProtectionLevel) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagProtectionLevel, string(text)) +} + +func (enum TicketType) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *TicketType) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagTicketType, string(text)) +} + +func (enum UniqueIdentifier) MarshalText() ([]byte, error) { + return marshalText(enum) +} +func (enum *UniqueIdentifier) UnmarshalText(text []byte) error { + return unmarshalText(enum, TagUniqueIdentifier, string(text)) } func marshalText[T ~uint32](enum T) ([]byte, error) { diff --git a/kmip/kmip.go b/kmip/kmip.go index e5e37c2..ced4950 100644 --- a/kmip/kmip.go +++ b/kmip/kmip.go @@ -24,15 +24,20 @@ func (pv ProtocolVersion) String() string { } type CredentialValue struct { - UserPassword *CredentialValueUserPassword - Device *CredentialValueDevice - Attestation *CredentialValueAttestation + UserPassword *CredentialValueUserPassword + Device *CredentialValueDevice + Attestation *CredentialValueAttestation + OneTimePassword *CredentialValueOneTimePassword + HashedPassword *CredentialValueHashedPassword + Ticket *CredentialValueTicket } func (cred *CredentialValue) TagEncodeTTLV(e *ttlv.Encoder, tag int) { e.TagAny(tag, cred.UserPassword) e.TagAny(tag, cred.Device) e.TagAny(tag, cred.Attestation) + e.TagAny(tag, cred.OneTimePassword) + e.TagAny(tag, cred.Ticket) } func (cred *CredentialValue) decode(d *ttlv.Decoder, tag int, cType CredentialType) error { @@ -43,6 +48,12 @@ func (cred *CredentialValue) decode(d *ttlv.Decoder, tag int, cType CredentialTy return d.TagAny(tag, &cred.Device) case CredentialTypeAttestation: return d.TagAny(tag, &cred.Attestation) + case CredentialTypeOneTimePassword: + return d.TagAny(tag, &cred.OneTimePassword) + case CredentialTypeHashedPassword: + return d.TagAny(tag, &cred.HashedPassword) + case CredentialTypeTicket: + return d.TagAny(tag, &cred.Ticket) } return fmt.Errorf("Unsupported credential type %X", cType) } @@ -68,6 +79,15 @@ type CredentialValueAttestation struct { AttestationAssertion []byte `ttlv:",omitempty"` } +type CredentialValueOneTimePassword struct { +} + +type CredentialValueHashedPassword struct { +} + +type CredentialValueTicket struct { +} + type Credential struct { CredentialType CredentialType CredentialValue CredentialValue @@ -267,3 +287,47 @@ type CapabilityInformation struct { ShreddingAlgorithm ShreddingAlgorithm `ttlv:",omitempty"` RNGMode RNGMode `ttlv:",omitempty"` } + +type CertificateAttributes struct { + CertificateSubjectCN string `ttlv:",omitempty"` + CertificateSubjectO string `ttlv:",omitempty"` + CertificateSubjectOU string `ttlv:",omitempty"` + CertificateSubjectEmail string `ttlv:",omitempty"` + CertificateSubjectC string `ttlv:",omitempty"` + CertificateSubjectST string `ttlv:",omitempty"` + CertificateSubjectL string `ttlv:",omitempty"` + CertificateSubjectUID string `ttlv:",omitempty"` + CertificateSubjectSerialNumber string `ttlv:",omitempty"` + CertificateSubjectTitle string `ttlv:",omitempty"` + CertificateSubjectDC string `ttlv:",omitempty"` + CertificateSubjectDNQualifier string `ttlv:",omitempty"` + CertificateIssuerCN string `ttlv:",omitempty"` + CertificateIssuerO string `ttlv:",omitempty"` + CertificateIssuerOU string `ttlv:",omitempty"` + CertificateIssuerEmail string `ttlv:",omitempty"` + CertificateIssuerC string `ttlv:",omitempty"` + CertificateIssuerST string `ttlv:",omitempty"` + CertificateIssuerL string `ttlv:",omitempty"` + CertificateIssuerUID string `ttlv:",omitempty"` + CertificateIssuerSerialNumber string `ttlv:",omitempty"` + CertificateIssuerTitle string `ttlv:",omitempty"` + CertificateIssuerDC string `ttlv:",omitempty"` + CertificateIssuerDNQualifier string `ttlv:",omitempty"` +} + +type VendorAttribute struct { + VendorIdentification string `ttlv:",omitempty"` + AttributeName string `ttlv:",omitempty"` + AttributeValue any `ttlv:",omitempty"` +} + +type Right struct { + UsageLimits *UsageLimits `ttlv:",omitempty"` + Operations []Operation `ttlv:",omitempty"` + Objects []Object `ttlv:",omitempty"` +} + +type Ticket struct { + TicketType TicketType `ttlv:",omitempty"` + TicketValue []byte `ttlv:",omitempty"` +} diff --git a/kmip/kmipclient/client.go b/kmip/kmipclient/client.go index 11432bf..5e9e8b1 100644 --- a/kmip/kmipclient/client.go +++ b/kmip/kmipclient/client.go @@ -56,7 +56,7 @@ import ( "github.com/openkcm/crypto/kmip/ttlv" ) -var supportedVersions = []kmip.ProtocolVersion{kmip.V1_4, kmip.V1_3, kmip.V1_2, kmip.V1_1, kmip.V1_0} +var supportedVersions = []kmip.ProtocolVersion{kmip.V2_0, kmip.V1_4, kmip.V1_3, kmip.V1_2, kmip.V1_1, kmip.V1_0} type opts struct { middlewares []Middleware diff --git a/kmip/kmipclient/middlewares.go b/kmip/kmipclient/middlewares.go index 7d66219..0ce7e1a 100644 --- a/kmip/kmipclient/middlewares.go +++ b/kmip/kmipclient/middlewares.go @@ -67,7 +67,7 @@ func CorrelationValueMiddleware(fn func() string) Middleware { panic("correlation value generator function cannot be null") } return func(next Next, ctx context.Context, msg *kmip.RequestMessage) (*kmip.ResponseMessage, error) { - if msg.Header.ClientCorrelationValue == "" && ttlv.CompareVersions(msg.Header.ProtocolVersion, kmip.V1_4) >= 0 { + if msg.Header.ClientCorrelationValue == "" && ttlv.CompareVersions(msg.Header.ProtocolVersion, kmip.V2_0) >= 0 { msg.Header.ClientCorrelationValue = fn() } return next(ctx, msg) diff --git a/kmip/kmipserver/router.go b/kmip/kmipserver/router.go index 7feca1c..9f7c60f 100644 --- a/kmip/kmipserver/router.go +++ b/kmip/kmipserver/router.go @@ -14,7 +14,7 @@ import ( "github.com/openkcm/crypto/kmip/ttlv" ) -var defaultSupportedVersion = []kmip.ProtocolVersion{kmip.V1_4, kmip.V1_3, kmip.V1_2, kmip.V1_1, kmip.V1_0} +var defaultSupportedVersion = []kmip.ProtocolVersion{kmip.V2_0, kmip.V1_4, kmip.V1_3, kmip.V1_2, kmip.V1_1, kmip.V1_0} // OperationHandler defines an interface for handling KMIP operations. // Implementations of this interface should provide logic to process a specific diff --git a/kmip/objects.go b/kmip/objects.go index ae801a5..8c18c16 100644 --- a/kmip/objects.go +++ b/kmip/objects.go @@ -16,15 +16,16 @@ import ( ) var objectTypes = map[ObjectType]reflect.Type{ - ObjectTypeSecretData: reflect.TypeFor[SecretData](), - ObjectTypeCertificate: reflect.TypeFor[Certificate](), - ObjectTypeSymmetricKey: reflect.TypeFor[SymmetricKey](), - ObjectTypePublicKey: reflect.TypeFor[PublicKey](), - ObjectTypePrivateKey: reflect.TypeFor[PrivateKey](), - ObjectTypeSplitKey: reflect.TypeFor[SplitKey](), - ObjectTypeOpaqueObject: reflect.TypeFor[OpaqueObject](), - ObjectTypeTemplate: reflect.TypeFor[Template](), - ObjectTypePGPKey: reflect.TypeFor[PGPKey](), + ObjectTypeSecretData: reflect.TypeFor[SecretData](), + ObjectTypeCertificate: reflect.TypeFor[Certificate](), + ObjectTypeSymmetricKey: reflect.TypeFor[SymmetricKey](), + ObjectTypePublicKey: reflect.TypeFor[PublicKey](), + ObjectTypePrivateKey: reflect.TypeFor[PrivateKey](), + ObjectTypeSplitKey: reflect.TypeFor[SplitKey](), + ObjectTypeOpaqueObject: reflect.TypeFor[OpaqueObject](), + ObjectTypeTemplate: reflect.TypeFor[Template](), + ObjectTypePGPKey: reflect.TypeFor[PGPKey](), + ObjectTypeCertificateRequest: reflect.TypeFor[CertificateRequest](), } // TODO: Make it private. @@ -719,3 +720,12 @@ type PGPKey struct { func (sd *PGPKey) ObjectType() ObjectType { return ObjectTypePGPKey } + +type CertificateRequest struct { + CertificateRequestType CertificateRequestType + CertificateRequestValue []byte +} + +func (sd *CertificateRequest) ObjectType() ObjectType { + return ObjectTypeCertificateRequest +} diff --git a/kmip/operations.go b/kmip/operations.go index ac590a6..17045a0 100644 --- a/kmip/operations.go +++ b/kmip/operations.go @@ -57,6 +57,18 @@ func init() { // KMIP 1.4 OperationImport: "Import", OperationExport: "Export", + + // KMIP 2.0 + OperationLog: "Log", + OperationLogin: "Login", + OperationLogout: "Logout", + OperationDelegatedLogin: "DelegatedLogin", + OperationAdjustAttribute: "AdjustAttribute", + OperationSetAttribute: "SetAttribute", + OperationSetEndpointRole: "SetEndpointRole", + OperationPKCS11: "PKCS#11", + OperationInterop: "Interop", + OperationReProvision: "ReProvision", }) } @@ -112,13 +124,25 @@ const ( // KMIP 1.4. OperationImport Operation = 0x0000002A OperationExport Operation = 0x0000002B + + // KMIP 2.0 + OperationLog Operation = 0x0000002C + OperationLogin Operation = 0x0000002D + OperationLogout Operation = 0x0000002E + OperationDelegatedLogin Operation = 0x0000002F + OperationAdjustAttribute Operation = 0x00000030 + OperationSetAttribute Operation = 0x00000031 + OperationSetEndpointRole Operation = 0x00000032 + OperationPKCS11 Operation = 0x00000033 + OperationInterop Operation = 0x00000034 + OperationReProvision Operation = 0x00000035 ) func (enum Operation) MarshalText() ([]byte, error) { return marshalText(enum) } func (enum *Operation) UnmarshalText(text []byte) error { - return unmarshalText(enum, int(TagOperation), string(text)) + return unmarshalText(enum, TagOperation, string(text)) } type operationPayloadTypes struct { diff --git a/kmip/payloads/adjust_attribute.go b/kmip/payloads/adjust_attribute.go new file mode 100644 index 0000000..b8c0caf --- /dev/null +++ b/kmip/payloads/adjust_attribute.go @@ -0,0 +1,35 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[AdjustAttributeRequestPayload, AdjustAttributeResponsePayload](kmip.OperationAdjustAttribute) +} + +var _ kmip.OperationPayload = (*AdjustAttributeRequestPayload)(nil) + +type AdjustAttributeRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` + AttributeReference kmip.Attribute `ttlv:",omitempty"` + AdjustmentType kmip.AdjustmentType `ttlv:",omitempty"` + AdjustmentValue string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *AdjustAttributeRequestPayload) Operation() kmip.Operation { + return kmip.OperationAdjustAttribute +} + +type AdjustAttributeResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*AdjustAttributeResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *AdjustAttributeResponsePayload) Operation() kmip.Operation { + return kmip.OperationAdjustAttribute +} diff --git a/kmip/payloads/delegated_login.go b/kmip/payloads/delegated_login.go new file mode 100644 index 0000000..d2241f7 --- /dev/null +++ b/kmip/payloads/delegated_login.go @@ -0,0 +1,37 @@ +package payloads + +import ( + "time" + + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[DelegatedLoginRequestPayload, DelegatedLoginResponsePayload](kmip.OperationDelegatedLogin) +} + +var _ kmip.OperationPayload = (*DelegatedLoginRequestPayload)(nil) + +type DelegatedLoginRequestPayload struct { + LeaseTime *time.Duration `ttlv:",omitempty"` + RequestCount *uint32 `ttlv:",omitempty"` + UsageLimits *kmip.UsageLimits `ttlv:",omitempty"` + Rights []kmip.Right `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *DelegatedLoginRequestPayload) Operation() kmip.Operation { + return kmip.OperationDelegatedLogin +} + +type DelegatedLoginResponsePayload struct { + // The Unique Identifier of the object. + TicketTicket kmip.Ticket `ttlv:",omitempty"` +} + +var _ kmip.OperationPayload = (*DelegatedLoginResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *DelegatedLoginResponsePayload) Operation() kmip.Operation { + return kmip.OperationDelegatedLogin +} diff --git a/kmip/payloads/interop.go b/kmip/payloads/interop.go new file mode 100644 index 0000000..a5c2419 --- /dev/null +++ b/kmip/payloads/interop.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[InteropRequestPayload, InteropResponsePayload](kmip.OperationInterop) +} + +var _ kmip.OperationPayload = (*InteropRequestPayload)(nil) + +type InteropRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *InteropRequestPayload) Operation() kmip.Operation { + return kmip.OperationInterop +} + +type InteropResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*InteropResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *InteropResponsePayload) Operation() kmip.Operation { + return kmip.OperationInterop +} diff --git a/kmip/payloads/log.go b/kmip/payloads/log.go new file mode 100644 index 0000000..37c799e --- /dev/null +++ b/kmip/payloads/log.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[LogRequestPayload, LogResponsePayload](kmip.OperationLog) +} + +var _ kmip.OperationPayload = (*LogRequestPayload)(nil) + +type LogRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *LogRequestPayload) Operation() kmip.Operation { + return kmip.OperationLog +} + +type LogResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*LogResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *LogResponsePayload) Operation() kmip.Operation { + return kmip.OperationLog +} diff --git a/kmip/payloads/login.go b/kmip/payloads/login.go new file mode 100644 index 0000000..74709ce --- /dev/null +++ b/kmip/payloads/login.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[LoginRequestPayload, LoginResponsePayload](kmip.OperationLogin) +} + +var _ kmip.OperationPayload = (*LoginRequestPayload)(nil) + +type LoginRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *LoginRequestPayload) Operation() kmip.Operation { + return kmip.OperationLogin +} + +type LoginResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*LoginResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *LoginResponsePayload) Operation() kmip.Operation { + return kmip.OperationLogin +} diff --git a/kmip/payloads/logout.go b/kmip/payloads/logout.go new file mode 100644 index 0000000..30639e8 --- /dev/null +++ b/kmip/payloads/logout.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[LogoutRequestPayload, LogoutResponsePayload](kmip.OperationLogout) +} + +var _ kmip.OperationPayload = (*LogoutRequestPayload)(nil) + +type LogoutRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *LogoutRequestPayload) Operation() kmip.Operation { + return kmip.OperationLogout +} + +type LogoutResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*LogoutResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *LogoutResponsePayload) Operation() kmip.Operation { + return kmip.OperationLogout +} diff --git a/kmip/payloads/pkcs11.go b/kmip/payloads/pkcs11.go new file mode 100644 index 0000000..1d26033 --- /dev/null +++ b/kmip/payloads/pkcs11.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[PKCS11RequestPayload, PKCS11ResponsePayload](kmip.OperationPKCS11) +} + +var _ kmip.OperationPayload = (*PKCS11RequestPayload)(nil) + +type PKCS11RequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *PKCS11RequestPayload) Operation() kmip.Operation { + return kmip.OperationPKCS11 +} + +type PKCS11ResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*PKCS11ResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *PKCS11ResponsePayload) Operation() kmip.Operation { + return kmip.OperationPKCS11 +} diff --git a/kmip/payloads/re_provision.go b/kmip/payloads/re_provision.go new file mode 100644 index 0000000..c0831d7 --- /dev/null +++ b/kmip/payloads/re_provision.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[ReProvisionRequestPayload, ReProvisionResponsePayload](kmip.OperationReProvision) +} + +var _ kmip.OperationPayload = (*ReProvisionRequestPayload)(nil) + +type ReProvisionRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *ReProvisionRequestPayload) Operation() kmip.Operation { + return kmip.OperationReProvision +} + +type ReProvisionResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*ReProvisionResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *ReProvisionResponsePayload) Operation() kmip.Operation { + return kmip.OperationReProvision +} diff --git a/kmip/payloads/set_attribute.go b/kmip/payloads/set_attribute.go new file mode 100644 index 0000000..0d34d8c --- /dev/null +++ b/kmip/payloads/set_attribute.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[SetAttributeRequestPayload, SetAttributeResponsePayload](kmip.OperationSetAttribute) +} + +var _ kmip.OperationPayload = (*SetAttributeRequestPayload)(nil) + +type SetAttributeRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *SetAttributeRequestPayload) Operation() kmip.Operation { + return kmip.OperationSetAttribute +} + +type SetAttributeResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*SetAttributeResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *SetAttributeResponsePayload) Operation() kmip.Operation { + return kmip.OperationSetAttribute +} diff --git a/kmip/payloads/set_endpoint_role.go b/kmip/payloads/set_endpoint_role.go new file mode 100644 index 0000000..ecbab5f --- /dev/null +++ b/kmip/payloads/set_endpoint_role.go @@ -0,0 +1,32 @@ +package payloads + +import ( + "github.com/openkcm/crypto/kmip" +) + +func init() { + kmip.RegisterOperationPayload[SetEndpointRoleRequestPayload, SetEndpointRoleResponsePayload](kmip.OperationSetEndpointRole) +} + +var _ kmip.OperationPayload = (*SetEndpointRoleRequestPayload)(nil) + +type SetEndpointRoleRequestPayload struct { + UniqueIdentifier string `ttlv:",omitempty"` +} + +// Operation implements kmip.OperationPayload. +func (a *SetEndpointRoleRequestPayload) Operation() kmip.Operation { + return kmip.OperationSetEndpointRole +} + +type SetEndpointRoleResponsePayload struct { + // The Unique Identifier of the object. + UniqueIdentifier string +} + +var _ kmip.OperationPayload = (*SetEndpointRoleResponsePayload)(nil) + +// Operation implements kmip.OperationPayload. +func (a *SetEndpointRoleResponsePayload) Operation() kmip.Operation { + return kmip.OperationSetEndpointRole +} diff --git a/kmip/tags.go b/kmip/tags.go index 5efbf45..a6e6be6 100644 --- a/kmip/tags.go +++ b/kmip/tags.go @@ -316,6 +316,73 @@ const ( TagExtractable = 0x420122 TagNeverExtractable = 0x420123 TagReplaceExisting = 0x420124 + + // KMIP 2.0 + TagAttributes = 0x420125 + TagCommonAttributes = 0x420126 + TagPrivateKeyAttributes = 0x420127 + TagPublicKeyAttributes = 0x420128 + TagExtensionEnumeration = 0x420129 + TagExtensionAttribute = 0x42012A + TagExtensionParentStructureTag = 0x42012B + TagExtensionDescription = 0x42012C + TagServerName = 0x42012D + TagServerSerialNumber = 0x42012E + TagServerVersion = 0x42012F + TagServerLoad = 0x420130 + TagProductName = 0x420131 + TagBuildLevel = 0x420132 + TagBuildDate = 0x420133 + TagClusterInfo = 0x420134 + TagAlternateFailoverEndpoints = 0x420135 + TagShortUniqueIdentifier = 0x420136 + TagReserved = 0x420137 + TagTag = 0x420138 + TagCertificateRequestUniqueIdentifier = 0x420139 + TagNISTKeyType = 0x42013A + TagAttributeReference = 0x42013B + TagCurrentAttribute = 0x42013C + TagNewAttribute = 0x42013D + //(Reserved) = 0x42013E + //(Reserved) = 0x42013F + TagCertificateRequestValue = 0x420140 + TagLogMessage = 0x420141 + TagProfileVersion = 0x420142 + TagProfileVersionMajor = 0x420143 + TagProfileVersionMinor = 0x420144 + TagProtectionLevel = 0x420145 + TagProtectionPeriod = 0x420146 + TagQuantumSafe = 0x420147 + TagQuantumSafeCapability = 0x420148 + TagTicket = 0x420149 + TagTicketType = 0x42014A + TagTicketValue = 0x42014B + TagRequestCount = 0x42014C + TagRights = 0x42014D + TagObjects = 0x42014E + TagOperations = 0x42014F + TagRight = 0x420150 + TagEndpointRole = 0x420151 + TagDefaultsInformation = 0x420152 + TagObjectDefaults = 0x420153 + TagEphemeral = 0x420154 + TagServerHashedPassword = 0x420155 + TagOneTimePassword = 0x420156 + TagHashedPassword = 0x420157 + TagAdjustmentType = 0x420158 + TagPKCS11Interface = 0x420159 + TagPKCS11Function = 0x42015A + TagPKCS11InputParameters = 0x42015B + TagPKCS11OutputParameters = 0x42015C + TagPKCS11ReturnCode = 0x42015D + TagProtectionStorageMask = 0x42015E + TagProtectionStorageMasks = 0x42015F + TagInteropFunction = 0x420160 + TagInteropIdentifier = 0x420161 + TagAdjustmentValue = 0x420162 + TagCommonProtectionStorageMasks = 0x420163 + TagPrivateProtectionStorageMasks = 0x420164 + TagPublicProtectionStorageMasks = 0x420165 ) var tagNames = map[int]string{ @@ -620,6 +687,71 @@ var tagNames = map[int]string{ TagExtractable: "Extractable", TagNeverExtractable: "NeverExtractable", TagReplaceExisting: "ReplaceExisting", + + // KMIP 2.0 + TagAttributes: "Attributes", + TagCommonAttributes: "CommonAttributes", + TagPrivateKeyAttributes: "PrivateKeyAttributes", + TagPublicKeyAttributes: "PublicKeyAttributes", + TagExtensionEnumeration: "ExtensionEnumeration", + TagExtensionAttribute: "ExtensionAttribute", + TagExtensionParentStructureTag: "ExtensionParentStructureTag", + TagExtensionDescription: "ExtensionDescription", + TagServerName: "ServerName", + TagServerSerialNumber: "ServerSerialNumber", + TagServerVersion: "ServerVersion", + TagServerLoad: "ServerLoad", + TagProductName: "ProductName", + TagBuildLevel: "BuildLevel", + TagBuildDate: "BuildDate", + TagClusterInfo: "ClusterInfo", + TagAlternateFailoverEndpoints: "AlternateFailoverEndpoints", + TagShortUniqueIdentifier: "ShortUniqueIdentifier", + TagReserved: "Reserved", + TagTag: "Tag", + TagCertificateRequestUniqueIdentifier: "CertificateRequestUniqueIdentifier", + TagNISTKeyType: "NISTKeyType", + TagAttributeReference: "AttributeReference", + TagCurrentAttribute: "CurrentAttribute", + TagNewAttribute: "NewAttribute", + TagCertificateRequestValue: "CertificateRequestValue", + TagLogMessage: "LogMessage", + TagProfileVersion: "ProfileVersion", + TagProfileVersionMajor: "ProfileVersionMajor", + TagProfileVersionMinor: "ProfileVersionMinor", + TagProtectionLevel: "ProtectionLevel", + TagProtectionPeriod: "ProtectionPeriod", + TagQuantumSafe: "QuantumSafe", + TagQuantumSafeCapability: "QuantumSafeCapability", + TagTicket: "Ticket", + TagTicketType: "TicketType", + TagTicketValue: "TicketValue", + TagRequestCount: "RequestCount", + TagRights: "Rights", + TagObjects: "Objects", + TagOperations: "Operations", + TagRight: "Right", + TagEndpointRole: "EndpointRole", + TagDefaultsInformation: "DefaultsInformation", + TagObjectDefaults: "ObjectDefaults", + TagEphemeral: "Ephemeral", + TagServerHashedPassword: "ServerHashedPassword", + TagOneTimePassword: "OneTimePassword", + TagHashedPassword: "HashedPassword", + TagAdjustmentType: "AdjustmentType", + TagPKCS11Interface: "PKCS#11Interface", + TagPKCS11Function: "PKCS#11Function", + TagPKCS11InputParameters: "PKCS#11InputParameters", + TagPKCS11OutputParameters: "PKCS#11OutputParameters", + TagPKCS11ReturnCode: "PKCS#11ReturnCode", + TagProtectionStorageMask: "ProtectionStorageMask", + TagProtectionStorageMasks: "ProtectionStorageMasks", + TagInteropFunction: "InteropFunction", + TagInteropIdentifier: "InteropIdentifier", + TagAdjustmentValue: "AdjustmentValue", + TagCommonProtectionStorageMasks: "CommonProtectionStorageMasks", + TagPrivateProtectionStorageMasks: "PrivateProtectionStorageMasks", + TagPublicProtectionStorageMasks: "PublicProtectionStorageMasks", } func init() { diff --git a/kmip/ttlv/decoder.go b/kmip/ttlv/decoder.go index 714bccc..5fe55f3 100644 --- a/kmip/ttlv/decoder.go +++ b/kmip/ttlv/decoder.go @@ -24,6 +24,7 @@ type reader interface { ByteString(tag int) ([]byte, error) DateTime(tag int) (time.Time, error) Interval(tag int) (time.Duration, error) + DateTimeExtended(tag int) (time.Time, error) Bitmask(realtag, tag int) (int32, error) } @@ -153,6 +154,11 @@ func (dec *Decoder) Interval(tag int) (time.Duration, error) { return dec.r.Interval(tag) } +// DateTimeExtended reads a date-time and advance to the next value. +func (dec *Decoder) DateTimeExtended(tag int) (time.Time, error) { + return dec.r.DateTime(tag) +} + // Bitmaks reads a bitmask value from the internal buffer. // While `tag` is the tag to write with the value, which may differ from the bitmask's default tag, // `realtag` can optionally be set to non-zero to identify the real default tag associated to the bitmask type. diff --git a/kmip/ttlv/encoder.go b/kmip/ttlv/encoder.go index 06f3182..526294a 100644 --- a/kmip/ttlv/encoder.go +++ b/kmip/ttlv/encoder.go @@ -21,6 +21,7 @@ type writer interface { ByteString(tag int, str []byte) DateTime(tag int, date time.Time) Interval(tag int, interval time.Duration) + DateTimeExtended(tag int, date time.Time) Bitmask(realtag, tag int, value int32) } diff --git a/kmip/ttlv/encoding_json.go b/kmip/ttlv/encoding_json.go index e55e9ef..97e26a6 100644 --- a/kmip/ttlv/encoding_json.go +++ b/kmip/ttlv/encoding_json.go @@ -184,6 +184,15 @@ func (j *jsonWriter) Interval(tag int, interval time.Duration) { }) } +// DateTimeExtended implements writer. +func (j *jsonWriter) DateTimeExtended(tag int, date time.Time) { + j.encodeAppend(TypeDateTimeExtended, tag, func(b []byte) []byte { + b = append(b, '"') + b = date.AppendFormat(b, time.RFC3339) + return append(b, '"') + }) +} + // Struct implements writer. func (j *jsonWriter) Struct(tag int, f func(writer)) { j.startElem(TypeStructure, tag) @@ -487,31 +496,7 @@ func (j *jsonReader) ByteString(tag int) ([]byte, error) { // DateTime implements reader. func (j *jsonReader) DateTime(tag int) (time.Time, error) { - if err := j.assertType(TypeDateTime, tag); err != nil { - return time.Time{}, err - } - switch val := j.getValue().(type) { - case string: - if strings.HasPrefix(val, "0x") { - parsed, err := strconv.ParseUint(val[2:], 10, 64) - if err != nil { - return time.Time{}, err - } - //nolint:gosec // this cast is safe as we are parsing an 64 bits hex value - epoch := int64(parsed) - if epoch < 0 { - return time.Time{}, Errorf("date-time cannot be negative") - } - return time.Unix(epoch, 0).UTC(), j.Next() - } - t, err := time.Parse(time.RFC3339, val) - if err != nil { - return t, err - } - return t.Local(), j.Next() - default: - return time.Time{}, Errorf("invalid date-time value: %q", val) - } + return j.genericDateTime(TypeDateTime, tag) } // Interval implements reader. @@ -541,6 +526,11 @@ func (j *jsonReader) Interval(tag int) (time.Duration, error) { } } +// DateTimeExtended implements reader. +func (j *jsonReader) DateTimeExtended(tag int) (time.Time, error) { + return j.genericDateTime(TypeDateTimeExtended, tag) +} + // Struct implements reader. func (j *jsonReader) Struct(tag int, f func(reader) error) error { if err := j.assertType(TypeStructure, tag); err != nil { @@ -603,3 +593,32 @@ func (j *jsonReader) Bitmask(realtag, tag int) (int32, error) { return 0, Errorf("Invalid bitmask value %q", val) } } + +// genericDateTime implements DateTime reader. +func (j *jsonReader) genericDateTime(ty Type, tag int) (time.Time, error) { + if err := j.assertType(ty, tag); err != nil { + return time.Time{}, err + } + switch val := j.getValue().(type) { + case string: + if strings.HasPrefix(val, "0x") { + parsed, err := strconv.ParseUint(val[2:], 10, 64) + if err != nil { + return time.Time{}, err + } + //nolint:gosec // this cast is safe as we are parsing an 64 bits hex value + epoch := int64(parsed) + if epoch < 0 { + return time.Time{}, Errorf("date-time cannot be negative") + } + return time.Unix(epoch, 0).UTC(), j.Next() + } + t, err := time.Parse(time.RFC3339, val) + if err != nil { + return t, err + } + return t.Local(), j.Next() + default: + return time.Time{}, Errorf("invalid date-time value: %q", val) + } +} diff --git a/kmip/ttlv/encoding_text.go b/kmip/ttlv/encoding_text.go index c285b92..72ef489 100644 --- a/kmip/ttlv/encoding_text.go +++ b/kmip/ttlv/encoding_text.go @@ -148,6 +148,13 @@ func (j *textWriter) Interval(tag int, interval time.Duration) { }) } +// DateTime implements writer. +func (j *textWriter) DateTimeExtended(tag int, date time.Time) { + j.encodeAppend(TypeDateTimeExtended, tag, func(b []byte) []byte { + return date.AppendFormat(b, time.RFC3339) + }) +} + // Struct implements writer. func (j *textWriter) Struct(tag int, f func(writer)) { j.startElem(TypeStructure, tag) diff --git a/kmip/ttlv/encoding_ttlv.go b/kmip/ttlv/encoding_ttlv.go index 8c71882..b117554 100644 --- a/kmip/ttlv/encoding_ttlv.go +++ b/kmip/ttlv/encoding_ttlv.go @@ -149,6 +149,13 @@ func (enc *ttlvWriter) Interval(tag int, interval time.Duration) { }) } +func (enc *ttlvWriter) DateTimeExtended(tag int, date time.Time) { + enc.encodeAppend(tag, TypeDateTimeExtended, 8, func(b []byte) []byte { + //nolint:gosec // this cast is safe as we are appending a number to a byte slice. + return binary.BigEndian.AppendUint64(b, uint64(date.Unix())) + }) +} + func (enc *ttlvWriter) Bitmask(bitmasktag, tag int, value int32) { enc.Integer(tag, value) } @@ -321,6 +328,15 @@ func (dec *ttlvReader) Interval(tag int) (time.Duration, error) { return v, dec.Next() } +func (dec *ttlvReader) DateTimeExtended(tag int) (time.Time, error) { + if err := dec.assertType(TypeDateTimeExtended, tag); err != nil { + return time.Time{}, err + } + //nolint:gosec // this cast is safe as we are parsing raw bytes. + v := time.Unix(int64(binary.BigEndian.Uint64(dec.value())), 0) + return v, dec.Next() +} + func (dec *ttlvReader) Bitmask(realtag, tag int) (int32, error) { return dec.Integer(tag) } diff --git a/kmip/ttlv/encoding_xml.go b/kmip/ttlv/encoding_xml.go index a7e420b..f607cc9 100644 --- a/kmip/ttlv/encoding_xml.go +++ b/kmip/ttlv/encoding_xml.go @@ -141,6 +141,10 @@ func (enc *xmlWriter) Interval(tag int, interval time.Duration) { enc.encode(TypeInterval, tag, strconv.Itoa(int(interval.Seconds()))) } +func (enc *xmlWriter) DateTimeExtended(tag int, date time.Time) { + enc.encode(TypeDateTimeExtended, tag, date.Format(time.RFC3339)) +} + func (enc *xmlWriter) Bitmask(bitmasktag, tag int, value int32) { if bitmasktag <= 0 { bitmasktag = tag @@ -402,6 +406,17 @@ func (dec *xmlReader) Interval(tag int) (time.Duration, error) { return time.Duration(parsed) * time.Second, dec.Next() } +func (dec *xmlReader) DateTimeExtended(tag int) (time.Time, error) { + if err := dec.assertType(TypeDateTimeExtended, tag); err != nil { + return time.Time{}, err + } + dt, err := time.Parse(time.RFC3339, dec.value()) + if err != nil { + return time.Time{}, err + } + return dt.Local(), dec.Next() +} + func (dec *xmlReader) Bitmask(realtag, tag int) (int32, error) { if err := dec.assertType(TypeInteger, tag); err != nil { return 0, err diff --git a/kmip/ttlv/types.go b/kmip/ttlv/types.go index 27f479c..766ed80 100644 --- a/kmip/ttlv/types.go +++ b/kmip/ttlv/types.go @@ -19,6 +19,9 @@ const ( TypeByteString TypeDateTime TypeInterval + + // KMIP 2.0 + TypeDateTimeExtended ) func (ty Type) String() string { @@ -51,6 +54,9 @@ var ( TypeByteString: "ByteString", TypeDateTime: "DateTime", TypeInterval: "Interval", + + // KMIP 2.0 + TypeDateTimeExtended: "DateTimeExtended", } nameTypes = revMap(typesName) )