# Copyright 2016-2018 Yubico AB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Named constants used in YubiHSM commands."""
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
from enum import IntEnum, IntFlag, unique
[docs]@unique
class ERROR(IntEnum):
"""Error codes returned by the YubiHSM"""
OK = 0x00
INVALID_COMMAND = 0x01
INVALID_DATA = 0x02
INVALID_SESSION = 0x03
AUTHENTICATION_FAILED = 0x04
SESSIONS_FULL = 0x05
SESSION_FAILED = 0x06
STORAGE_FAILED = 0x07
WRONG_LENGTH = 0x08
INSUFFICIENT_PERMISSIONS = 0x09
LOG_FULL = 0x0A
OBJECT_NOT_FOUND = 0x0B
INVALID_ID = 0x0C
SSH_CA_CONSTRAINT_VIOLATION = 0x0E
INVALID_OTP = 0x0F
DEMO_MODE = 0x10
OBJECT_EXISTS = 0x11
ALGORITHM_DISABLED = 0x12
COMMAND_UNEXECUTED = 0xFF
[docs]@unique
class COMMAND(IntEnum):
"""Commands available to send to the YubiHSM"""
ECHO = 0x01
CREATE_SESSION = 0x03
AUTHENTICATE_SESSION = 0x04
SESSION_MESSAGE = 0x05
DEVICE_INFO = 0x06
RESET_DEVICE = 0x08
GET_DEVICE_PUBLIC_KEY = 0x0A
CLOSE_SESSION = 0x40
GET_STORAGE_INFO = 0x041
PUT_OPAQUE = 0x42
GET_OPAQUE = 0x43
PUT_AUTHENTICATION_KEY = 0x44
PUT_ASYMMETRIC_KEY = 0x45
GENERATE_ASYMMETRIC_KEY = 0x46
SIGN_PKCS1 = 0x47
LIST_OBJECTS = 0x48
DECRYPT_PKCS1 = 0x49
EXPORT_WRAPPED = 0x4A
IMPORT_WRAPPED = 0x4B
PUT_WRAP_KEY = 0x4C
GET_LOG_ENTRIES = 0x4D
GET_OBJECT_INFO = 0x4E
SET_OPTION = 0x4F
GET_OPTION = 0x50
GET_PSEUDO_RANDOM = 0x51
PUT_HMAC_KEY = 0x52
SIGN_HMAC = 0x53
GET_PUBLIC_KEY = 0x54
SIGN_PSS = 0x55
SIGN_ECDSA = 0x56
DERIVE_ECDH = 0x57
DELETE_OBJECT = 0x58
DECRYPT_OAEP = 0x59
GENERATE_HMAC_KEY = 0x5A
GENERATE_WRAP_KEY = 0x5B
VERIFY_HMAC = 0x5C
SIGN_SSH_CERTIFICATE = 0x5D
PUT_TEMPLATE = 0x5E
GET_TEMPLATE = 0x5F
DECRYPT_OTP = 0x60
CREATE_OTP_AEAD = 0x61
RANDOMIZE_OTP_AEAD = 0x62
REWRAP_OTP_AEAD = 0x63
SIGN_ATTESTATION_CERTIFICATE = 0x64
PUT_OTP_AEAD_KEY = 0x65
GENERATE_OTP_AEAD_KEY = 0x66
SET_LOG_INDEX = 0x67
WRAP_DATA = 0x68
UNWRAP_DATA = 0x69
SIGN_EDDSA = 0x6A
BLINK_DEVICE = 0x6B
CHANGE_AUTHENTICATION_KEY = 0x6C
PUT_SYMMETRIC_KEY = 0x6D
GENERATE_SYMMETRIC_KEY = 0x6E
DECRYPT_ECB = 0x6F
ENCRYPT_ECB = 0x70
DECRYPT_CBC = 0x71
ENCRYPT_CBC = 0x72
PUT_PUBLIC_WRAP_KEY = 0x73
WRAP_KEY_RSA = 0x74
UNWRAP_KEY_RSA = 0x75
EXPORT_WRAPPED_RSA = 0x76
IMPORT_WRAPPED_RSA = 0x77
ERROR = 0x7F
[docs]@unique
class ALGORITHM(IntEnum):
"""Various algorithm constants"""
RSA_PKCS1_SHA1 = 1
RSA_PKCS1_SHA256 = 2
RSA_PKCS1_SHA384 = 3
RSA_PKCS1_SHA512 = 4
RSA_PSS_SHA1 = 5
RSA_PSS_SHA256 = 6
RSA_PSS_SHA384 = 7
RSA_PSS_SHA512 = 8
RSA_2048 = 9
RSA_3072 = 10
RSA_4096 = 11
RSA_OAEP_SHA1 = 25
RSA_OAEP_SHA256 = 26
RSA_OAEP_SHA384 = 27
RSA_OAEP_SHA512 = 28
RSA_MGF1_SHA1 = 32
RSA_MGF1_SHA256 = 33
RSA_MGF1_SHA384 = 34
RSA_MGF1_SHA512 = 35
EC_P256 = 12
EC_P384 = 13
EC_P521 = 14
EC_K256 = 15
EC_BP256 = 16
EC_BP384 = 17
EC_BP512 = 18
EC_ECDSA_SHA1 = 23
EC_ECDH = 24
HMAC_SHA1 = 19
HMAC_SHA256 = 20
HMAC_SHA384 = 21
HMAC_SHA512 = 22
AES128_CCM_WRAP = 29
OPAQUE_DATA = 30
OPAQUE_X509_CERTIFICATE = 31
TEMPLATE_SSH = 36
AES128_YUBICO_OTP = 37
AES128_YUBICO_AUTHENTICATION = 38
AES192_YUBICO_OTP = 39
AES256_YUBICO_OTP = 40
AES192_CCM_WRAP = 41
AES256_CCM_WRAP = 42
EC_ECDSA_SHA256 = 43
EC_ECDSA_SHA384 = 44
EC_ECDSA_SHA512 = 45
EC_ED25519 = 46
EC_P224 = 47
RSA_PKCS1_DECRYPT = 48
EC_P256_YUBICO_AUTHENTICATION = 49
AES128 = 50
AES192 = 51
AES256 = 52
AES_ECB = 53
AES_CBC = 54
AES_KWP = 55
[docs] def to_curve(self) -> ec.EllipticCurve:
"""Return a Cryptography EC curve instance for a given member.
:return: The corresponding curve.
:rtype: cryptography.hazmat.primitives.ec.
:Example:
>>> isinstance(ALGORITHM.EC_P256.to_curve(), ec.SECP256R1)
True
"""
return _curve_table[self]() # type: ignore
[docs] @staticmethod
def for_curve(curve: ec.EllipticCurve) -> "ALGORITHM":
"""Returns a member corresponding to a Cryptography curve instance.
:Example:
>>> ALGORITHM.for_curve(ec.SECP256R1()) == ALGORITHM.EC_P256
True
"""
curve_type = type(curve)
for key, val in _curve_table.items():
if val == curve_type:
return key
raise ValueError("Unsupported curve type: %s" % curve.name)
[docs] def to_key_size(self) -> int:
"""Return the expected size (in bytes) of a key corresponding to an algorithm.
:return: The corresponding key size (in bytes) to an algorithm.
:Example:
>>> ALGORITHM.AES128.to_key_size()
16
"""
return _key_size_table[self]
[docs] def to_hash_algorithm(self) -> hashes.HashAlgorithm:
"""Return the cryptography hash algorithm object corresponding to the algorithm.
:return The corresponding cryptography hash algorithm object.
:Example:
>>> ALGORITHM.HMAC_SHA1.to_hash_algorithm()
hashes.SHA1
"""
return _hash_table[self]()
_curve_table = {
ALGORITHM.EC_P224: ec.SECP224R1,
ALGORITHM.EC_P256: ec.SECP256R1,
ALGORITHM.EC_P384: ec.SECP384R1,
ALGORITHM.EC_P521: ec.SECP521R1,
ALGORITHM.EC_K256: ec.SECP256K1,
ALGORITHM.EC_BP256: ec.BrainpoolP256R1,
ALGORITHM.EC_BP384: ec.BrainpoolP384R1,
ALGORITHM.EC_BP512: ec.BrainpoolP512R1,
}
_key_size_table = {
ALGORITHM.AES128_CCM_WRAP: 16,
ALGORITHM.AES192_CCM_WRAP: 24,
ALGORITHM.AES256_CCM_WRAP: 32,
ALGORITHM.HMAC_SHA1: 64, # Maximum key size
ALGORITHM.HMAC_SHA256: 64, # Maximum key size
ALGORITHM.HMAC_SHA384: 128, # Maximum key size
ALGORITHM.HMAC_SHA512: 128, # Maximum key size
ALGORITHM.AES128_YUBICO_OTP: 16,
ALGORITHM.AES192_YUBICO_OTP: 24,
ALGORITHM.AES256_YUBICO_OTP: 32,
ALGORITHM.AES128: 16,
ALGORITHM.AES192: 24,
ALGORITHM.AES256: 32,
ALGORITHM.RSA_2048: 256,
ALGORITHM.RSA_3072: 384,
ALGORITHM.RSA_4096: 512,
}
_hash_table = {
ALGORITHM.HMAC_SHA1: hashes.SHA1,
ALGORITHM.HMAC_SHA256: hashes.SHA256,
ALGORITHM.HMAC_SHA384: hashes.SHA384,
ALGORITHM.HMAC_SHA512: hashes.SHA512,
}
[docs]@unique
class LIST_FILTER(IntEnum):
"""Keys for use to filter on in list_objects"""
ID = 0x01
TYPE = 0x02
DOMAINS = 0x03
CAPABILITIES = 0x04
ALGORITHM = 0x05
LABEL = 0x06
[docs]@unique
class OBJECT(IntEnum):
"""YubiHSM object types"""
OPAQUE = 0x01
AUTHENTICATION_KEY = 0x02
ASYMMETRIC_KEY = 0x03
WRAP_KEY = 0x04
HMAC_KEY = 0x05
TEMPLATE = 0x06
OTP_AEAD_KEY = 0x07
SYMMETRIC_KEY = 0x08
PUBLIC_WRAP_KEY = 0x09
[docs]@unique
class OPTION(IntEnum):
"""YubiHSM device options"""
FORCE_AUDIT = 0x01
COMMAND_AUDIT = 0x03
ALGORITHM_TOGGLE = 0x04
FIPS_MODE = 0x05
[docs]@unique
class AUDIT(IntEnum):
"""Values for audit options"""
OFF = 0x00
ON = 0x01
FIXED = 0x02
[docs]@unique
class FIPS_STATUS(IntEnum):
"""Values for FIPS status"""
OFF = 0x00
ON = 0x01
PENDING = 0x03
class _enum_prop:
# Static property for use with enums.
def __init__(self, getter):
self.getter = getter
def __get__(self, instance, cls):
return self.getter(cls)
[docs]@unique
class CAPABILITY(IntFlag):
"""YubiHSM object capability flags"""
GET_OPAQUE = 1 << 0x00
PUT_OPAQUE = 1 << 0x01
PUT_AUTHENTICATION_KEY = 1 << 0x02
PUT_ASYMMETRIC = 1 << 0x03
GENERATE_ASYMMETRIC_KEY = 1 << 0x04
SIGN_PKCS = 1 << 0x05
SIGN_PSS = 1 << 0x06
SIGN_ECDSA = 1 << 0x07
SIGN_EDDSA = 1 << 0x08
DECRYPT_PKCS = 1 << 0x09
DECRYPT_OAEP = 1 << 0x0A
DERIVE_ECDH = 1 << 0x0B
EXPORT_WRAPPED = 1 << 0x0C
IMPORT_WRAPPED = 1 << 0x0D
PUT_WRAP_KEY = 1 << 0x0E
GENERATE_WRAP_KEY = 1 << 0x0F
EXPORTABLE_UNDER_WRAP = 1 << 0x10
SET_OPTION = 1 << 0x11
GET_OPTION = 1 << 0x12
GET_PSEUDO_RANDOM = 1 << 0x13
PUT_HMAC_KEY = 1 << 0x14
GENERATE_HMAC_KEY = 1 << 0x15
SIGN_HMAC = 1 << 0x16
VERIFY_HMAC = 1 << 0x17
GET_LOG_ENTRIES = 1 << 0x18
SIGN_SSH_CERTIFICATE = 1 << 0x19
GET_TEMPLATE = 1 << 0x1A
PUT_TEMPLATE = 1 << 0x1B
RESET_DEVICE = 1 << 0x1C
DECRYPT_OTP = 1 << 0x1D
CREATE_OTP_AEAD = 1 << 0x1E
RANDOMIZE_OTP_AEAD = 1 << 0x1F
REWRAP_FROM_OTP_AEAD_KEY = 1 << 0x20
REWRAP_TO_OTP_AEAD_KEY = 1 << 0x21
SIGN_ATTESTATION_CERTIFICATE = 1 << 0x22
PUT_OTP_AEAD_KEY = 1 << 0x23
GENERATE_OTP_AEAD_KEY = 1 << 0x24
WRAP_DATA = 1 << 0x25
UNWRAP_DATA = 1 << 0x26
DELETE_OPAQUE = 1 << 0x27
DELETE_AUTHENTICATION_KEY = 1 << 0x28
DELETE_ASYMMETRIC_KEY = 1 << 0x29
DELETE_WRAP_KEY = 1 << 0x2A
DELETE_HMAC_KEY = 1 << 0x2B
DELETE_TEMPLATE = 1 << 0x2C
DELETE_OTP_AEAD_KEY = 1 << 0x2D
CHANGE_AUTHENTICATION_KEY = 1 << 0x2E
PUT_SYMMETRIC_KEY = 1 << 0x2F
GENERATE_SYMMETRIC_KEY = 1 << 0x30
DELETE_SYMMETRIC_KEY = 1 << 0x31
DECRYPT_ECB = 1 << 0x32
ENCRYPT_ECB = 1 << 0x33
DECRYPT_CBC = 1 << 0x34
ENCRYPT_CBC = 1 << 0x35
PUBLIC_WRAP_KEY_WRITE = 1 << 0x36
PUBLIC_WRAP_KEY_DELETE = 1 << 0x37
[docs] @_enum_prop
def NONE(cls) -> "CAPABILITY":
return cls(0) # type: ignore
[docs] @_enum_prop
def ALL(cls) -> "CAPABILITY":
return cls(sum(cls)) # type: ignore
[docs]class ORIGIN(IntFlag):
GENERATED = 0x01
IMPORTED = 0x02
IMPORTED_WRAPPED = 0x10 # Set in combination with GENERATED/IMPORTED