| # |
| # Copyright 2018-2020 NXP |
| # SPDX-License-Identifier: Apache-2.0 |
| # |
| # |
| |
| """License text""" |
| |
| import os |
| import ctypes |
| import binascii |
| import logging |
| from . import sss_api as apis |
| from .keystore import KeyStore |
| from .keyobject import KeyObject |
| from .asymmetric import Asymmetric |
| from .util import hash_convert, hash_convert_raw, save_to_file, \ |
| load_certificate, transform_key_to_list |
| from .const import HASH |
| log = logging.getLogger(__name__) |
| |
| |
| class Sign: # pylint: disable=too-few-public-methods |
| """ |
| Sign operation |
| """ |
| |
| def __init__(self, session_obj): |
| """ |
| Constructor |
| :param session_obj: Instance of session |
| """ |
| self._session = session_obj |
| self._ctx_ks = KeyStore(self._session) |
| self._ctx_key = KeyObject(self._ctx_ks) |
| self.signature_data = None |
| self.hash_algo = apis.kAlgorithm_None |
| |
| def do_signature(self, key_id, input_file, filename, # pylint: disable=too-many-locals, too-many-arguments |
| in_encode_format="", out_encode_format="", hash_algo=""): |
| """ |
| DO sign operation |
| :param key_id: Key index |
| :param input_file: Input data to be signed |
| :param filename: File name to store the signature data |
| :param in_encode_format: Input data file encode format |
| :param out_encode_format: Output Signature file encode format |
| :param hash_algo: Hash algorithm to sign |
| :return: Status |
| """ |
| status, object_type, cipher_type = self._ctx_key.get_handle(key_id) # pylint: disable=unused-variable |
| if status != apis.kStatus_SSS_Success: |
| return status |
| |
| if hash_algo == '': |
| # Default hash algorithm |
| if cipher_type in [apis.kSSS_CipherType_RSA, apis.kSSS_CipherType_RSA_CRT]: |
| log.debug("Considering Algorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA256 " |
| "as Default hash algorithm for RSA") |
| self.hash_algo = apis.kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA256 |
| elif cipher_type in [apis.kSSS_CipherType_EC_TWISTED_ED]: |
| log.debug("Considering Algorithm_SSS_SHA512 as Default hash algorithm") |
| self.hash_algo = apis.kAlgorithm_SSS_SHA512 |
| else: |
| log.debug("Considering Algorithm_SSS_SHA256 as Default hash algorithm") |
| self.hash_algo = apis.kAlgorithm_SSS_SHA256 |
| else: |
| # Take hash algorithm from user |
| self.hash_algo = HASH[hash_algo] |
| |
| try: |
| if not os.path.isfile(input_file): |
| raise Exception("Incorrect input file, try signing with correct input file !!") |
| |
| if cipher_type in [apis.kSSS_CipherType_EC_TWISTED_ED]: |
| digest, digest_len = load_certificate(input_file) |
| else: |
| (digest, digest_len) = hash_convert(input_file, in_encode_format, self.hash_algo) |
| except Exception as exc: # pylint: disable=broad-except |
| # If input data is not certificate, then load it as binary data |
| if 'Unable to load certificate' in str(exc): |
| if os.path.isfile(input_file): |
| with open(input_file, 'rb') as raw_data: |
| src_data = raw_data.read() |
| if cipher_type in [apis.kSSS_CipherType_EC_TWISTED_ED]: |
| cert_hex = binascii.hexlify(src_data) |
| digest = transform_key_to_list(cert_hex) |
| digest_len = len(digest) |
| else: |
| (digest, digest_len) = hash_convert_raw(src_data, self.hash_algo) |
| else: |
| raise Exception("Incorrect input file, try signing with correct input file !!") |
| else: |
| raise exc |
| |
| digest = (ctypes.c_ubyte * digest_len)(*digest) |
| mode = apis.kMode_SSS_Sign |
| # Signature length set to 1024 to support all EC curves and RSA key size |
| signature_len = 1024 |
| data_buf = (ctypes.c_uint8 * signature_len)(0) |
| signature_len = ctypes.c_size_t(signature_len) |
| |
| ctx_asymm = Asymmetric(self._session, self._ctx_key, self.hash_algo, mode) |
| if cipher_type in [apis.kSSS_CipherType_EC_TWISTED_ED]: |
| (signature_ctype, status) = ctx_asymm.se05x_sign(digest, digest_len, data_buf, signature_len) |
| else: |
| (signature_ctype, status) = ctx_asymm.sign(digest, digest_len, data_buf, signature_len) |
| if signature_ctype is None: |
| log.error("Received signature data is empty") |
| return status |
| signature_full_list = list(signature_ctype) |
| signature_list = signature_full_list[:int(signature_len.value)] |
| if filename is not None: |
| status = save_to_file(signature_list, filename, |
| apis.kSSS_KeyPart_NONE, out_encode_format) |
| der = "" |
| for signature_item in signature_list: |
| der += str(signature_item) |
| self.signature_data = binascii.unhexlify(der) |
| return status |