def verify(self, message, key, signature, padding=RsaBase.RSA_PAD_PSS, hash_algo=RsaBase.RSA_HASH_SHA256, salt_len=RsaBase.RSA_PAD_PSS_SALT_1): # Create options for the rsa operation pad_opts = [ '-pkeyopt', 'rsa_padding_mode:' + self._get_pad_opt(OPENSSL_PKEYUTL_MODE, padding) ] if padding == self.RSA_PAD_PSS: hash_opt = self._get_hash_opt(hash_algo) pad_opts += [ '-pkeyopt', 'rsa_pss_saltlen:' + salt_len, '-pkeyopt', 'digest:' + hash_opt ] signature_path = c_path.create_tmp_file(signature) pad_opts = ['-sigfile', signature_path] + pad_opts # Return if message matches signature try: output = self._pkeyutl(message, key, ['-verify', '-pubin'], pad_opts, expected_retcode=1) return 'Signature Verified Successfully' in output finally: c_path.remove_tmp_file(signature_path)
def get_asn1_text(self, cert): cert_path = c_path.create_tmp_file(cert) try: cmd = [self.openssl, 'asn1parse', '-in', cert_path, '-inform', self._get_format_opt(self.get_cert_format(cert))] return run_command(cmd, large_output=True) finally: c_path.remove_tmp_file(cert_path)
def get_public_key_from_private(self, priv_key): key_path = c_path.create_tmp_file(priv_key) try: cmd = [ self.openssl, OPENSSL_ECDSA_MODE, '-in', key_path, '-pubout' ] return run_command(cmd) finally: c_path.remove_tmp_file(key_path)
def create_cert(self, priv_key, subject_params=None, config=None, hash_algo=CertBase.HASH_ALGO_SHA256, self_sign=False, days=None, serial=None, padding=CertBase.PAD_PKCS, pad_hash_algo=CertBase.HASH_ALGO_SHA256, pad_salt_len=CertBase.PAD_PSS_SALT_1): """ Create a self signed certificate input: subject_params = { 'C' : "US", 'ST' : "California", 'L' : "San Diego", 'O' : "ASIC", 'CN' : "Qualcomm", } Dictionary of parameters to put in the certificate. The parameters above are an example days = validity period of certificate in days configfile = configfile used by openssl serial_num = Serial number of certificate padding = Type of padding output: certificate: String representation of PEM certificate. """ priv_path = c_path.create_tmp_file(priv_key) try: cmd = [self.openssl, 'req', '-new', '-key', priv_path] if subject_params is not None: subject = self.get_subject_from_params(subject_params) cmd += ['-subj', subject] if config is not None: cmd += ['-config', config] if hash_algo is not None: cmd += ['-' + hash_algo] if self_sign: cmd += ['-x509'] if padding == self.PAD_PSS: cmd += [ '-sigopt', 'rsa_padding_mode:pss', '-sigopt', 'rsa_pss_saltlen:' + pad_salt_len, '-sigopt', 'digest:' + pad_hash_algo ] if serial is not None: cmd += ['-set_serial', str(serial)] if days is not None: cmd += ['-days', str(days)] return run_command(cmd) finally: c_path.remove_tmp_file(priv_path)
def _pkeyutl(self, message, key, preopts, options, expected_retcode=0): message_path = c_path.create_tmp_file(message) key_path = c_path.create_tmp_file(key) cmd = ([self.openssl, OPENSSL_PKEYUTL_MODE] + preopts + ['-inkey', key_path, '-in', message_path] + options) try: return run_command(cmd, expected_retcode) finally: c_path.remove_tmp_file(message_path) c_path.remove_tmp_file(key_path)
def get_asn1_text(self, signature): signature_path = c_path.create_tmp_file(signature) try: cmd = [ self.openssl, 'asn1parse', '-in', signature_path, '-inform', utils.FORMAT_DER ] return run_command(cmd, large_output=True) finally: c_path.remove_tmp_file(signature_path)
def get_pubkey(self, cert): cert_path = c_path.create_tmp_file(cert) try: cmd = [self.openssl, OPENSSL_CERT_MODE, '-in', cert_path, '-pubkey', '-noout', '-inform', self._get_format_opt(self.get_cert_format(cert))] return run_command(cmd) finally: c_path.remove_tmp_file(cert_path)
def get_text(self, cert): cert_path = c_path.create_tmp_file(cert) try: cmd = [self.openssl, OPENSSL_CERT_MODE, '-in', cert_path, '-inform', self._get_format_opt(self.get_cert_format(cert)), '-noout', '-text', '-certopt', 'ext_dump'] return run_command(cmd, large_output=True, ret_binary=False) finally: c_path.remove_tmp_file(cert_path)
def get_text_from_key(self, key, inform, is_public=False): key_path = c_path.create_tmp_file(key) try: cmd = [self.openssl, 'rsa', '-text', '-noout', '-in', key_path, '-inform', self._get_format_opt(inform)] if is_public: cmd.append('-pubin') return run_command(cmd) finally: c_path.remove_tmp_file(key_path)
def verify(self, message, key, signature): # Remove padding and save signature to file signature = EcdsaOpenSSLImpl.strip_sig_padding(signature) signature_path = c_path.create_tmp_file(signature) # Return if message matches signature try: output = self._pkeyutl(message, key, ['-verify', '-pubin'], ['-sigfile', signature_path], expected_retcode=1) return output.strip() == 'Signature Verified Successfully' finally: c_path.remove_tmp_file(signature_path)
def get_cert_text(self, cert, inform, outform): """ Return text contents of certificate input: der_certificate_path = path to DER certficate output: certificate_text = String representation certificate contents """ # Any preprocessing if outform == CertBase.CERT_TEXT_FORM_X509 and inform == utils.FORMAT_PEM: cert = self.get_cert_in_format(cert, utils.FORMAT_PEM, utils.FORMAT_DER) inform = utils.FORMAT_DER elif outform == CertBase.CERT_TEXT_FORM_ASN1 and inform == utils.FORMAT_DER: cert = self.get_cert_in_format(cert, utils.FORMAT_DER, utils.FORMAT_PEM) inform = utils.FORMAT_PEM cert_path = c_path.create_tmp_file(cert) try: cmd = [ self.openssl, outform, '-in', cert_path, '-inform', inform, ] # Create command based on formats if outform == CertBase.CERT_TEXT_FORM_X509: if inform != utils.FORMAT_DER: raise RuntimeError( 'Invalid input format specified for output format ' + outform) cmd += ['-noout', '-text', '-certopt', 'ext_dump'] elif outform == CertBase.CERT_TEXT_FORM_ASN1: if inform != utils.FORMAT_PEM: raise RuntimeError( 'Invalid input format specified for output format ' + outform) else: raise RuntimeError('Invalid output format ' + str(outform)) return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] finally: c_path.remove_tmp_file(cert_path)
def get_key_in_format(self, key, inform, outform, is_public=False): inform_opt = self._get_format_opt(inform) outform_opt = self._get_format_opt(outform) key_path = c_path.create_tmp_file(key) try: cmd = [ self.openssl, 'ec', '-in', key_path, '-inform', inform_opt, '-outform', outform_opt ] if is_public: cmd.append('-pubin') return run_command(cmd) finally: c_path.remove_tmp_file(key_path)
def decrypt(self, message, key, iv, ciphername=AesCbcBase.CIPHERNAME_128): message_path, decrypted_message_path = None, None try: message_path = c_path.create_tmp_file(message) decrypted_message_path = c_path.create_tmp_file() cmd = [ self.openssl, 'enc', ciphername, '-d', '-in', message_path, '-K', key, '-iv', iv, '-out', decrypted_message_path, '-nopad' ] run_command(cmd) return c_path.load_data_from_file(decrypted_message_path) finally: c_path.remove_tmp_file(message_path) c_path.remove_tmp_file(decrypted_message_path)
def encrypt(self, message, key, iv, aad): message_path, encrypted_message_path = None, None try: message_path = c_path.create_tmp_file(message) encrypted_message_path = c_path.create_tmp_file() cmd = [ self.crypto_ccm, '--input-file', message_path, '--key', key, '--iv', iv, '--output', encrypted_message_path, '--operation=encrypt', '--aad', aad ] run_command(cmd, log=False) return c_path.load_data_from_file(encrypted_message_path) finally: c_path.remove_tmp_file(message_path) c_path.remove_tmp_file(encrypted_message_path)
def decrypt(self, message, key, iv): message_path, decrypted_message_path = None, None try: message_path = c_path.create_tmp_file(message) decrypted_message_path = c_path.create_tmp_file() cmd = [ self.crypto_cbc, '--input-file', message_path, '--key', key, '--iv', iv, '--output', decrypted_message_path, '--operation=decrypt' ] run_command(cmd, log=False) return c_path.load_data_from_file(decrypted_message_path) finally: c_path.remove_tmp_file(message_path) c_path.remove_tmp_file(decrypted_message_path)
def get_cert_in_format(self, cert, inform, outform): if "BEGIN CERTIFICATE" not in cert and outform == utils.FORMAT_DER: return cert inform_opt = self._get_format_opt(inform) outform_opt = self._get_format_opt(outform) cert_path = c_path.create_tmp_file(cert) try: cmd = [ self.openssl, OPENSSL_CERT_MODE, '-in', cert_path, '-inform', inform_opt, '-outform', outform_opt ] return run_command(cmd) finally: c_path.remove_tmp_file(cert_path)
def get_cert_in_format(self, cert, outform): # Avoid error by reconverting inform = self.get_cert_format(cert) if inform == outform: return cert inform_opt = self._get_format_opt(inform) outform_opt = self._get_format_opt(outform) cert_path = c_path.create_tmp_file(cert) try: cmd = [self.openssl, OPENSSL_CERT_MODE, '-in', cert_path, '-inform', inform_opt, '-outform', outform_opt] return run_command(cmd) finally: c_path.remove_tmp_file(cert_path)
def get_key_in_format(self, key, outform, is_public=False): # Avoid error by reconverting inform = self.get_key_format(key) if inform == outform: return key key_path = c_path.create_tmp_file(key) try: cmd = [self.openssl, OPENSSL_RSA_MODE, '-in', key_path, '-inform', self._get_format_opt(inform), '-outform', self._get_format_opt(outform)] if is_public: cmd.append('-pubin') return run_command(cmd) finally: c_path.remove_tmp_file(key_path)
def verify(self, message, key, signature): # Remove padding and save signature to file signature = self.strip_sig_padding(signature) signature_path = c_path.create_tmp_file(signature) # Return if message matches signature try: expected_retcode = True ^ OpenSSLDiscoveryImpl.is_supported_version( self.openssl, min_version=OPENSSL_PKEYUTL_FIXED_VERSION_MIN) output = self._pkeyutl(message, key, ['-verify', '-pubin'], ['-sigfile', signature_path], expected_retcode=expected_retcode, ignore_retcode=True) return output.strip() == b'Signature Verified Successfully' finally: c_path.remove_tmp_file(signature_path)
def gen_keys(self, exponent, keysize, priv_key_path=None, pub_key_path=None): """ Generate RSA Key pair input: key_size_in_bits: Size of the key in bits. key_exponent: [3, 65537] Exponent used in key calculation. priv_key_path: File name for storing private key pub_key_path: File name for storing public key output: returned value: {"public_key": [Generated public key], "private_key": [Generated private key] } Dictionary holding the values of public and private keys """ # Generate the key pair using openssl priv_key = self._gen_rsa_key_pair(exponent, keysize) # Generate the public key file try: # Save the private key to file priv_path = priv_key_path if priv_key_path is not None else c_path.create_tmp_file() logger.debug('Writing generated private key to PEM file: ' + priv_path) with open(priv_path, 'wb') as fd: fd.write(priv_key) # Extract the public key from the private key pub_key = self._get_pub_from_priv(priv_path) finally: # Cleanup temp file if priv_key_path is None: c_path.remove_tmp_file(priv_path) # Save the public key to file if pub_key_path is not None: logger.debug('Writing generated public key to PEM file: ' + pub_key_path) with open(pub_key_path, 'wb') as fd: fd.write(pub_key) return (priv_key, pub_key)
def verify(self, message, key, signature, padding=RsaBase.RSA_PAD_PSS, hash_algo=RsaBase.RSA_HASH_SHA256, salt_len=RsaBase.RSA_PAD_PSS_SALT_1): # Create options for the rsa operation pad_opts = ['-pkeyopt', 'rsa_padding_mode:' + self._get_pad_opt(OPENSSL_PKEYUTL_MODE, padding)] if padding == self.RSA_PAD_PSS: hash_opt = self._get_hash_opt(hash_algo) pad_opts += ['-pkeyopt', 'rsa_pss_saltlen:' + salt_len, '-pkeyopt', 'digest:' + hash_opt] signature_path = c_path.create_tmp_file(signature) pad_opts = ['-sigfile', signature_path] + pad_opts # Return if message matches signature try: expected_retcode = 0 if OpenSSLDiscoveryImpl.is_supported_version(self.openssl, min_version=OPENSSL_PKEYUTL_FIXED_VERSION_MIN) else 1 output = self._pkeyutl(message, key, ['-verify', '-pubin'], pad_opts, expected_retcode=expected_retcode, ignore_retcode=True) return b'Signature Verified Successfully' in output finally: c_path.remove_tmp_file(signature_path)
def gen_keys(self, curve, priv_key_path=None, pub_key_path=None): """ Generate ECDSA Key pair :param curve: Name of curve to use. Either "secp256r1" or "secp384r1" :type curve: str :param priv_key_path: File path to store private key :type priv_key_path: str :param pub_key_path: File path to store public key :type pub_key_path: str :return: generated private_key and public_key """ # Generate the key pair using openssl priv_key = self._gen_ecdsa_key_pair(curve) # Generate the public key file try: # Save the private key to file priv_path = priv_key_path if priv_key_path is not None else c_path.create_tmp_file( ) logger.debug('Writing generated private key to PEM file: ' + priv_path) with open(priv_path, 'wb') as fd: fd.write(priv_key) # Extract the public key from the private key pub_key = self._get_pub_from_priv(priv_path) finally: # Cleanup temp file if priv_key_path is None: c_path.remove_tmp_file(priv_path) # Save the public key to file if pub_key_path is not None: logger.debug('Writing generated public key to PEM file: ' + pub_key_path) with open(pub_key_path, 'wb') as fd: fd.write(pub_key) return priv_key, pub_key
def decrypt(self, message, key, iv, aad): message_path, decrypted_message_path = None, None try: message_path = c_path.create_tmp_file(message) decrypted_message_path = c_path.create_tmp_file() cmd = [ self.crypto_ccm, '--input-file', message_path, '--key', key, '--iv', iv, '--output', decrypted_message_path, '--operation=decrypt', '--aad', aad ] output = run_command(cmd, log=False) # Check there is no issue with the output if "Caught HashVerificationFailed..." in output: raise RuntimeError(output) return c_path.load_data_from_file(decrypted_message_path) finally: c_path.remove_tmp_file(message_path) c_path.remove_tmp_file(decrypted_message_path)
def get_pubkey_from_cert(self, cert, inform, text_output=False): inform_opt = self._get_format_opt(inform) cert_path, pub_path = None, None try: cert_path = c_path.create_tmp_file(cert) cmd = [ self.openssl, OPENSSL_CERT_MODE, '-pubkey', '-noout', '-in', cert_path, '-inform', inform_opt ] pub_key = run_command(cmd) if text_output: pub_path = c_path.create_tmp_file(pub_key) cmd = [ self.openssl, 'rsa', '-pubin', '-text', '-noout' '-in', cert_path, '-inform', inform_opt ] pub_key = run_command(cmd) finally: if cert_path is not None: c_path.remove_tmp_file(cert_path) if pub_path is not None: c_path.remove_tmp_file(pub_path) return pub_key
def validate_cert_chain(self, cert, ca_cert_chain): ca_cert_chain_path, cert_path = None, None try: ca_cert_chain_path = c_path.create_tmp_file(ca_cert_chain) cert_path = c_path.create_tmp_file(cert) # Check validity time valid_from, _ = self.get_validity(self.get_text(cert)) lag = calendar.timegm(valid_from) - int(time.time()) if lag > 0: logger.warning('Local machine\'s time is slow by at least ' + str(lag) + ' seconds.') cmd = [self.openssl, 'verify', '-attime', str(calendar.timegm(valid_from)), '-CAfile', ca_cert_chain_path, cert_path] return (cert_path + ': OK') in run_command(cmd, ret_binary=False) except RuntimeError: return False finally: c_path.remove_tmp_file(ca_cert_chain_path) c_path.remove_tmp_file(cert_path)
def sign_cert(self, cert, ca_cert, ca_priv_key, extfile=None, hash_algo=CertBase.HASH_ALGO_SHA256, days=None, serial=None, sign_algo=CertBase.SIGN_ALGO_RSA_PKCS, pad_hash_algo=CertBase.HASH_ALGO_SHA256, pad_salt_len=CertBase.PAD_PSS_SALT_1): cert_path, ca_cert_path, ca_priv_path = None, None, None try: cert_path = c_path.create_tmp_file(cert) ca_cert_path = c_path.create_tmp_file(ca_cert) ca_priv_path = c_path.create_tmp_file(ca_priv_key) cmd = [self.openssl, OPENSSL_CERT_MODE, '-req', '-in', cert_path, '-CAkey', ca_priv_path, '-CA', ca_cert_path, ] if days is not None: cmd += ['-days', str(days)] if serial is not None: cmd += ['-set_serial', str(serial)] if extfile is not None: cmd += ['-extfile', extfile] if hash_algo is not None: cmd += ['-' + hash_algo] if sign_algo == self.SIGN_ALGO_RSA_PSS: cmd += ['-sigopt', 'rsa_padding_mode:pss', '-sigopt', 'rsa_pss_saltlen:' + pad_salt_len, '-sigopt', 'digest:' + pad_hash_algo] else: cmd += ['-CAcreateserial'] return run_command(cmd) finally: c_path.remove_tmp_file(cert_path) c_path.remove_tmp_file(ca_cert_path) c_path.remove_tmp_file(ca_priv_path)
def verify(self, message, key, signature): """ Decrypt and verify an encrypted message using a public key and signature :param message: message to verify :param key: public key :param signature: signature :return verified: boolean outcome of verification :rtype: bool """ signature = EcdsaOpenSSLImpl.strip_sig_padding(signature) expected_retcode = 1 message_path = c_path.create_tmp_file(message) key_path = c_path.create_tmp_file(key) signature_path = c_path.create_tmp_file(signature) cmd = ([ self.openssl, OPENSSL_PKEYUTL_MODE, '-verify', '-pubin', '-inkey', key_path, '-sigfile', signature_path, '-in', message_path ]) try: output = run_command(cmd, expected_retcode) if output.strip() == 'Signature Verified Successfully': return True else: return False finally: c_path.remove_tmp_file(message_path) c_path.remove_tmp_file(key_path) c_path.remove_tmp_file(signature_path)
def encrypt(self, message, key, iv): """ Function to encrypt binary with a CBC 128 bit cipher. input: binary_blob: Binary blob to encrypt hex_preexisting_128_bit_key: hex representarion of 128bit key | None, if None, the key is generated hex_preexisting_iv: hex representarion of image IV | None, if None, the IV is generated output: (encrypted_binary, encryption_key, image_iv): Tuple with the encrypted binary, the key, and the IV """ message_path, encrypted_message_path = None, None try: message_path = c_path.create_tmp_file(message) encrypted_message_path = c_path.create_tmp_file() cmd = [ self.crypto_cbc, '--operation=encrypt', '--input-file', message_path, '--output', encrypted_message_path, '--key', key, '--iv', iv, ] run_command(cmd) return c_path.load_data_from_file(encrypted_message_path) finally: if message_path is not None: c_path.remove_tmp_file(message_path) if encrypted_message_path is not None: c_path.remove_tmp_file(encrypted_message_path)
def create_cert(self, priv_key, subject_params=None, config=None, self_sign=False, hash_algo=CertBase.HASH_ALGO_SHA256, days=None, serial=None, sign_algo=CertBase.SIGN_ALGO_RSA_PKCS, pad_hash_algo=CertBase.HASH_ALGO_SHA256, pad_salt_len=CertBase.PAD_PSS_SALT_1): priv_path = c_path.create_tmp_file(priv_key) try: cmd = [self.openssl, 'req', '-new', '-key', priv_path] if subject_params is not None: subject = self.get_subject_from_params(subject_params) cmd += ['-subj', subject] if config is not None: cmd += ['-config', config] if self_sign: cmd += ['-x509'] if days is not None: cmd += ['-days', str(days)] if serial is not None: cmd += ['-set_serial', str(serial)] if hash_algo is not None: cmd += ['-' + hash_algo] if sign_algo == self.SIGN_ALGO_RSA_PSS: cmd += [ '-sigopt', 'rsa_padding_mode:pss', '-sigopt', 'rsa_pss_saltlen:' + pad_salt_len, '-sigopt', 'digest:' + pad_hash_algo ] return run_command(cmd) finally: c_path.remove_tmp_file(priv_path)
def gen_keys(self, exponent, keysize, priv_key_path=None, pub_key_path=None): # Generate the key pair using openssl priv_key = self._gen_rsa_key_pair(exponent, keysize) # Save the private key to file priv_path = priv_key_path if priv_key_path is not None else c_path.create_tmp_file() # Generate the public key file try: logger.debug('Writing generated private key to PEM file: ' + priv_path) c_path.store_data_to_file(priv_path, priv_key) # Extract the public key from the private key pub_key = self.get_public_key_from_private(priv_key) finally: # Cleanup temp file c_path.remove_tmp_file(priv_path) # Save the public key to file if pub_key_path is not None: logger.debug('Writing generated public key to PEM file: ' + pub_key_path) c_path.store_data_to_file(pub_key_path, pub_key) return priv_key, pub_key