def match_xy(self, public_key): x = self.openssl.lib.BN_new() y = self.openssl.lib.BN_new() common_util.assert_in_error( self.openssl.lib.EC_POINT_get_affine_coordinates_GFp( self.openssl.lib.EC_KEY_get0_group(public_key), self.openssl.lib.EC_KEY_get0_public_key(public_key), x, y, None, ), "match_xy() failed to EC_POINT_get_affine_coordinates_GFp()", ) cpointer = self.get_char_point_from_bignum(x, self.curve_info.size) cpointer.compare_data( self.xy.data[:self.curve_info.size], ("X of Public key from QKY does not match " + "with private key from PEM file"), ) del cpointer cpointer = self.get_char_point_from_bignum(y, self.curve_info.size) cpointer.compare_data( self.xy.data[self.curve_info.size:], ("Y of Public key from QKY does not match " + "with private key from PEM file"), ) del cpointer self.openssl.lib.BN_clear_free(x) self.openssl.lib.BN_clear_free(y)
def __init__(self, args): self.args = args self.database = database.FAMILY_LIST["PAC_CARD"] log.debug(args.main_command) self.bitstream_type = self.database.SUPPORTED_TYPES[ args.main_command].ENUM self.verify = True if args.root_bitstream else False if self.verify: offset = 0 self.reh = common_util.BYTE_ARRAY("FILE", args.root_bitstream) con_type = self.reh.get_dword(offset + 8) if (self.reh.get_dword(offset) != database.DESCRIPTOR_BLOCK_MAGIC_NUM or self.reh.get_dword(offset + 4) != 128 or (con_type >> 8) & 0xFF != database.BITSTREAM_TYPE_RK_256 or self.reh.get_dword(offset + 128) != database.SIGNATURE_BLOCK_MAGIC_NUM): common_util.assert_in_error( False, "File '{}' is not a root entry hash programming bitstream". format(args.root_bitstream), ) if con_type & 0xFF != self.bitstream_type: log.warn("File '{}' different type than bitstream." " Validation impossible".format(args.root_bitstream)) self.verify = False if self.verify: self.val_root_hash = int.from_bytes(self.reh.data[1024:1056], byteorder="big") self.val_root_hash_dc = int.from_bytes(self.reh.data[1072:1104], byteorder="big")
def retrive_key_info(self): assert self.key is not None assert self.curve_info is None # Checking support type group = self.openssl.lib.EC_KEY_get0_group(self.key) common_util.assert_in_error( group is not None, "generate_openssl_key() failed to EC_KEY_get0_group()") type = self.openssl.lib.EC_GROUP_get_curve_name(group) self.curve_info = openssl.get_curve_info_from_enum(type) common_util.assert_in_error( self.curve_info is not None, "EC curve enum (%d) name (%s) is not supported" % (type, self.openssl.lib.OBJ_nid2ln(type)), ) log.debug("Curve info={}, group={}, type={}".format( self.curve_info, group, self.openssl.lib.OBJ_nid2ln(type))) # Get XY pub = self.openssl.lib.EC_KEY_get0_public_key(self.key) x = self.openssl.lib.BN_new() y = self.openssl.lib.BN_new() common_util.assert_in_error( self.openssl.lib.EC_POINT_get_affine_coordinates_GFp( group, pub, x, y, None), "Fail to EC_POINT_get_affine_coordinates_GFp()", ) temp = common_util.get_byte_size(self.openssl.lib.BN_num_bits(x)) common_util.assert_in_error( self.curve_info.size >= temp, ("Public key X size (%d Bytes) does not aligned " + "with EC curve (%d Bytes)") % (temp, self.curve_info.size), ) temp = common_util.get_byte_size(self.openssl.lib.BN_num_bits(y)) common_util.assert_in_error( self.curve_info.size >= temp, ("Public key Y size (%d Bytes) does not aligned " + "with EC curve (%d Bytes)") % (temp, self.curve_info.size), ) # Copy X and Y cpointer = self.get_char_point_from_bignum(x, self.curve_info.size) self.xy.append_data(cpointer.data) log.debug("".join("{:02x} ".format(x) for x in self.xy.data)) del cpointer cpointer = self.get_char_point_from_bignum(y, self.curve_info.size) self.xy.append_data(cpointer.data) log.debug("".join("{:02x} ".format(x) for x in self.xy.data)) del cpointer log.debug(self.xy) self.openssl.lib.BN_clear_free(x) self.openssl.lib.BN_clear_free(y)
def __init__(self, file, openssl, key_info): self.key_info = key_info super(_PRIVATE_KEY, self).__init__(file, openssl, key_info) public_pem = self.check_pem_file() common_util.assert_in_error( public_pem is False, ("Expect the PEM file %s to be private PEM, " + "but detected as public PEM") % self.file, ) self.key = self.openssl.read_private_key(self.file) self.retrive_key_info()
def get_bignums_from_byte_array(self, byte_array): common_util.assert_in_error( len(byte_array) == 64 or len(byte_array) == 96, ("get_bignums_from_byte_array() expects data size to be " + "64 or 96 Bytes, but found %d Bytes") % len(byte_array), ) byte_array_size = int(len(byte_array) / 2) return [ self.get_bignum_from_byte_array(byte_array[:byte_array_size]), self.get_bignum_from_byte_array(byte_array[byte_array_size:]), ]
def generate_public_pem(self, pem, key): bio = self.lib.BIO_new(self.lib.BIO_s_file()) status = self.lib.BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE, pem.encode("utf-8")) common_util.assert_in_error(status > 0, "Fail to open file %s for BIO write" % pem) status = self.lib.PEM_write_bio_EC_PUBKEY(bio, key) common_util.assert_in_error(status > 0, "Fail to write EC Publick Key to PEM BIO") self.lib.BIO_free_all(bio)
def generate_key(self, group): key = self.lib.EC_KEY_new() common_util.assert_in_error( self.lib.EC_KEY_set_group(key, group) != 0, "generate_key() failed to EC_KEY_set_group()", ) common_util.assert_in_error( self.lib.EC_KEY_generate_key(key) != 0, "generate_key() failed to EC_KEY_generate_key()", ) return key
def __init__(self, min_csk, max_csk, enum, permission, supported_size=None): self.MIN_CODE_SIGNING_KEY_ENTRIES = min_csk self.MAX_CODE_SIGNING_KEY_ENTRIES = max_csk common_util.assert_in_error( self.MAX_CODE_SIGNING_KEY_ENTRIES >= self.MIN_CODE_SIGNING_KEY_ENTRIES, "Impossible Code Signing Key entry count [min: %d, max: %d]" % (self.MIN_CODE_SIGNING_KEY_ENTRIES, self.MAX_CODE_SIGNING_KEY_ENTRIES), ) self.ENUM = enum self.PERMISSION = permission self.SUPPORTED_SIZE = supported_size
def read_private_key(self, private_pem): bio = self.lib.BIO_new(self.lib.BIO_s_file()) status = self.lib.BIO_ctrl( bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, private_pem.encode("utf-8"), ) common_util.assert_in_error( status > 0, "Fail to read file %s for BIO read" % private_pem) key = self.lib.PEM_read_bio_ECPrivateKey( bio, None, callback, ("Reading %s" % private_pem).encode("utf-8")) common_util.assert_in_error( key is not None, "Fail to read EC Private Key from PEM BIO %s" % private_pem) self.lib.BIO_free_all(bio) return key
def __init__(self, cfg_file): self.openssl = openssl.openssl() self.key_path = None self.curve = None self.keys = None if cfg_file is not None: with open(cfg_file, "r") as read_file: j_data = json.load(read_file) try: self.key_path = j_data["key_path"] self.curve = j_data["curve"] self.keys = j_data["keys"] except KeyError as ke: common_util.assert_in_error( False, "No key '{}' in config file".format(ke))
def get_public_key(self, public_pem): pem = public_pem local_key = None if self.keys: for k in self.keys: if pem == k["label"]: local_key = k break common_util.assert_in_error( local_key is not None, "Key '{}' not found".format(pem), ) common_util.assert_in_error( "pub_key" in local_key, "Public key for '{}' not found".format(pem), ) pem = os.path.join(self.key_path, local_key["pub_key"]) return _PUBLIC_KEY(pem, self.openssl, local_key)
def sign(self, sha, data, fixed_RS_size=0): log.debug("Sign: sha_size:{}".format(len(sha))) common_util.assert_in_error( len(sha) == 32 or len(sha) == 48 or len(sha) == 64, ("Supported SHA is SHA256, SHA314 and SHA512, " + "but found sha size of %d") % (len(sha) * 8), ) signature = self.openssl.lib.ECDSA_do_sign(sha, len(sha), self.key) common_util.assert_in_error( self.openssl.lib.ECDSA_do_verify(sha, len(sha), signature, self.key), "Fail to verify after the signing", ) r = c_void_p(None) s = c_void_p(None) self.openssl.lib.ECDSA_SIG_get0(signature, byref(r), byref(s)) # assign r cpointer = self.get_char_point_from_bignum(r, self.curve_info.size) log.debug("Sign: curve_info.size={}, cpointer.size={}".format( self.curve_info.size, cpointer.size())) data.append_data(cpointer.data) del cpointer if fixed_RS_size: assert fixed_RS_size == 48 or fixed_RS_size == 64 for _ in range(self.curve_info.size, fixed_RS_size): data.append_byte(0) # assign s cpointer = self.get_char_point_from_bignum(s, self.curve_info.size) data.append_data(cpointer.data) del cpointer if fixed_RS_size: assert fixed_RS_size == 48 or fixed_RS_size == 64 for _ in range(self.curve_info.size, fixed_RS_size): data.append_byte(0) # Free signature self.openssl.lib.ECDSA_SIG_free(signature)
def get_private_key(self, private_pem): pem = private_pem local_key = None if self.keys: for k in self.keys: if pem == k["label"]: local_key = k break common_util.assert_in_error( local_key is not None, "Key '{}' not found".format(pem), ) common_util.assert_in_error( "priv_key" in local_key, "Private key for '{}' not found".format(pem), ) pem = os.path.join(self.key_path, local_key["priv_key"]) else: pem = private_pem.replace("_public_", "_private_", 1) return _PRIVATE_KEY(pem, self.openssl, local_key)
def get_byte_array_sha(self, type, bytes): common_util.assert_in_error( type == 32 or type == 48 or type == 64, ("Expect SHA supported type size is 32, 48 or " + "64 Bytes, but found %d Bytes") % type, ) common_util.assert_in_error( len(bytes) > 0 and (len(bytes) % 128) == 0, ("Data to be hashed must have size greater than " + "zero and multiple of 128 Bytes, but found %d Bytes") % len(bytes), ) common_util.assert_in_error( memoryview(bytes).c_contiguous, "Byte array is not contiguous in memory") cpointer = c_char_p(bytes.buffer_info()[0]) sha = common_util.CHAR_POINTER(type) if type == 32: self.get_sha256(cpointer, bytes.buffer_info()[1], sha) elif type == 48: self.get_sha384(cpointer, bytes.buffer_info()[1], sha) else: self.get_sha512(cpointer, bytes.buffer_info()[1], sha) del cpointer return sha
def __init__(self, cfg_file=None): common_util.assert_in_error( cfg_file, "PKCS11 HSM manager requires a configuration file") self.session = None with open(cfg_file, "r") as read_file: self.j_data = json.load(read_file) j_data = self.j_data lib = pkcs11.lib(j_data["lib_path"]) common_util.assert_in_error( j_data["library_version"] == list(lib.library_version), "PKCS11 HSM manager library version mismatch", ) common_util.assert_in_error( j_data["cryptoki_version"] == list(lib.cryptoki_version), "PKCS11 HSM manager cryptoki version mismatch", ) token = lib.get_token(token_label=j_data["token"]["label"]) self.session = token.open(user_pin=j_data["token"]["user_password"]) self.curve = j_data["curve"] self.ecparams = self.session.create_domain_parameters( pkcs11.KeyType.EC, { pkcs11.Attribute: pkcs11.util.ec.encode_named_curve_parameters(self.curve) }, local=True, )
def get_char_point_from_bignum(self, bignum, size): common_util.assert_in_error( size == 32 or size == 48, ("get_char_point_from_bignum() expects data size to be " + "32 or 48 Bytes, but found %d Bytes") % size, ) cpointer = common_util.CHAR_POINTER(size) bn_byte = self.openssl.lib.BN_bn2bin(bignum, cpointer.data) common_util.assert_in_error( bn_byte <= size, ("BN_bn2bin() expects BN size to be %d Bytes, " + "but found %d Bytes") % (size, bn_byte), ) if bn_byte != size: cpointer1 = common_util.CHAR_POINTER(size) cpointer1.assign_partial_data(cpointer.data, 0, size - bn_byte, bn_byte) del cpointer return cpointer1 else: return cpointer
def __init__( self, family, supported_types, max_csk, signature_max_size, supported_cancels, cert_types, ): self.FAMILY = family # You can set the types to None, if this family has only one type data self.SUPPORTED_TYPES = supported_types self.MAX_CODE_SIGNING_KEY_ENTRIES = max_csk self.SIGNATURE_MAX_SIZE = signature_max_size self.SUPPORTED_CANCELS = ( supported_cancels ) # You can set cancels to None, if it does not support cancel self.SUPPORTED_CERT_TYPES = cert_types common_util.assert_in_error( self.SIGNATURE_MAX_SIZE > 0 and self.SIGNATURE_MAX_SIZE <= 880 and (self.SIGNATURE_MAX_SIZE % 4) == 0, ("Maximum signature reserved field should greater than zero, " + "less than 880 Bytes and multiple of 4 Bytes, but found %d") % self.SIGNATURE_MAX_SIZE, ) for key in self.SUPPORTED_TYPES: common_util.assert_in_error( self.SUPPORTED_TYPES[key].MIN_CODE_SIGNING_KEY_ENTRIES <= self.MAX_CODE_SIGNING_KEY_ENTRIES, ("File type (%s) minimum Code Signing Key entry (%d) " + "cannot be more than family (%s) maximum " + "Code Signing Key entry (%d)") % ( key, self.SUPPORTED_TYPES[key].MIN_CODE_SIGNING_KEY_ENTRIES, self.FAMILY, self.MAX_CODE_SIGNING_KEY_ENTRIES, ), ) common_util.assert_in_error( self.SUPPORTED_TYPES[key].MAX_CODE_SIGNING_KEY_ENTRIES <= self.MAX_CODE_SIGNING_KEY_ENTRIES, ("File type (%s) maximum Code Signing Key entry (%d) " + "cannot be more than family (%s) maximum " + "Code Signing Key entry (%d)") % ( key, self.SUPPORTED_TYPES[key].MAX_CODE_SIGNING_KEY_ENTRIES, self.FAMILY, self.MAX_CODE_SIGNING_KEY_ENTRIES, ), ) self.CURRENT_TYPE = None self.CURRENT_TYPE_NAME = None self.CURRENT_CERT_TYPE = None self.CURRENT_CERT_TYPE_NAME = None
def get_public_key(self, public_key): try: key_, local_key = self.get_key(public_key, ObjectClass.PUBLIC_KEY) key_ = key_[Attribute.EC_POINT] common_util.assert_in_error( key_[0] == 0x04, "PKCS11 HSM manager key not in DER format") common_util.assert_in_error( key_[1] == 0x41, "PKCS11 HSM manager key not in DER format") common_util.assert_in_error( key_[2] == 0x04, "PKCS11 HSM manager key not in DER format") except pkcs11.NoSuchKey: log.error("No such key") except pkcs11.MultipleObjectsReturned: log.error("multiple") return _PUBLIC_KEY(key_[3:], local_key)
def password_callback(buf, bufsiz, verify, cb_temp): comment = "" if cb_temp is not None: for char in cb_temp: if char != 0: comment += chr(char) common_util.assert_in_error( bufsiz >= 4, ("Minimum password must be 4 characters," + " but only %d buffer size is being provided") % bufsiz, ) try: if verify: (password, error) = common_util.get_password( [ ("Enter PEM passphrase (4 to %d characters per OpenSSL " + "spec, Intel recommends minumum 13 characters): ") % (bufsiz - 1), ("Re-enter PEM passphrase (4 to %d characters per OpenSSL " + "spec, Intel recommends minumum 13 characters): ") % (bufsiz - 1), ], 4, bufsiz - 1, comment, ) else: (password, error) = common_util.get_password( [("Enter PEM passphrase (4 to %d characters per OpenSSL" + " spec, Intel recommends minumum 13 characters): ") % (bufsiz - 1)], 4, bufsiz - 1, comment, ) common_util.assert_in_error(len(error) == 0, error) except Exception: common_util.assert_in_error(False, "Fail to get passphrase") password_size = len(password) if password_size < 13: common_util.print_warning(PEM_PASSWORD_WARNING) for i in range(password_size): buf[i] = password[i] del password password = [] return password_size
def generate_ec_key_using_xy_and_curve_info(self, xy, curve_info): common_util.assert_in_error( len(xy) == (curve_info.size * 2), "%s xy size should be %d Bytes, but found %d Bytes" % (curve_info.name, curve_info.size * 2, len(xy)), ) (x, y) = self.get_bignums_from_byte_array(xy) key = self.lib.EC_KEY_new_by_curve_name(curve_info.enum) status = self.lib.EC_KEY_set_public_key_affine_coordinates(key, x, y) common_util.assert_in_error( status > 0, "Fail to set public key affine coordinates") status = self.lib.EC_KEY_check_key(key) common_util.assert_in_error(status > 0, "Invalid key") self.lib.BN_clear_free(x) self.lib.BN_clear_free(y) return key
def read_public_key(self, public_pem): bio = self.lib.BIO_new(self.lib.BIO_s_file()) status = self.lib.BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, public_pem.encode("utf-8")) common_util.assert_in_error( status > 0, "Fail to read file %s for BIO read" % public_pem) pub_key = self.lib.PEM_read_bio_PUBKEY(bio, None, None, None) common_util.assert_in_error( pub_key is not None, "Fail to read EC Public Key from PEM BIO %s" % public_pem, ) key = self.lib.EVP_PKEY_get1_EC_KEY(pub_key) common_util.assert_in_error(key is not None, "Fail to get EC Key from public key") self.lib.EVP_PKEY_free(pub_key) self.lib.BIO_free_all(bio) return key
def generate_private_pem(self, pem, group, key, encrypt): bio = self.lib.BIO_new(self.lib.BIO_s_file()) status = self.lib.BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE, pem.encode("utf-8")) common_util.assert_in_error(status > 0, "Fail to open file %s for BIO write" % pem) status = self.lib.PEM_write_bio_ECPKParameters(bio, group) common_util.assert_in_error(status > 0, "Fail to write EC Param to PEM BIO") if encrypt is None or not encrypt: status = self.lib.PEM_write_bio_ECPrivateKey( bio, key, None, None, 0, None, None) else: enc = self.lib.EVP_get_cipherbyname("aes256".encode("utf-8")) status = self.lib.PEM_write_bio_ECPrivateKey( bio, key, enc, None, 0, callback, ("Writing %s" % pem).encode("utf-8")) common_util.assert_in_error(status > 0, "Fail to write EC Private Key to PEM BIO") self.lib.BIO_free_all(bio)
def verify_signature(self, sha, rs): common_util.assert_in_error( len(sha.data) == 32 or len(sha.data) == 48 or len(sha.data) == 64, ("verify_signature() data size to be veried must be 32, " + "48 or 64 Bytes, but found %d Bytes") % len(sha.data), ) common_util.assert_in_error( len(rs) == (self.curve_info.size * 2), "Key expects RS size to be %d Bytes, but found %d Bytes" % (self.curve_info.size * 2, len(rs)), ) (r, s) = self.openssl.get_bignums_from_byte_array(rs) signature = self.openssl.lib.ECDSA_SIG_new() self.openssl.lib.ECDSA_SIG_set0(signature, r, s) common_util.assert_in_error( self.openssl.lib.ECDSA_do_verify(sha.data, len(sha.data), signature, self.key), "verify_signature() failed to ECDSA_do_verify()", ) self.openssl.lib.ECDSA_SIG_free(signature)
def test_assert_in_error(): assert_in_error_boolean = mock.MagicMock() assert_in_error_string = mock.MagicMock() assert_in_error(assert_in_error_boolean, assert_in_error_string)
def run(self, fname, file_offset, block0, block1, payload): log.info("Starting verification") payload_content = common_util.BYTE_ARRAY("FILE", fname) # Skip JSON and old signature if they exist has_json = self.is_JSON(payload_content) log.debug("has_json = {}".format(has_json)) sig_offset = 0 if not has_json else self.skip_JSON(payload_content) # Determine if platform is RC or DC self.dc_pr = self.is_Darby_PR(payload_content, sig_offset) fd = open(fname, "rb") fd.seek(file_offset, 0) b0 = fd.read(block0.size()) b1 = fd.read(block1.size()) if self.dc_pr: pay = fd.read(len(payload)) pay_good = pay == bytes(payload) else: pay = fd.read(payload.size()) pay_good = pay == bytes(payload.data) fd.close() common_util.assert_in_error( b0 == bytes(block0.data) and b1 == bytes(block1.data) and pay_good, "File not written properly", ) log.info("Bitstream file written properly (bits match expected)") pay_sha256_v = int.from_bytes(sha256(pay).digest(), byteorder="big") pay_sha384_v = int.from_bytes(sha384(pay).digest(), byteorder="big") if not self.dc_pr: if pay_sha256_v != int.from_bytes(b0[16:16 + 32], byteorder="big"): log.error("SHA-256 in Block 0 does not match") if pay_sha384_v != int.from_bytes(b0[48:48 + 48], byteorder="big"): log.error("SHA-384 in Block 0 does not match") # Check root hash if self.dc_pr: hash = int.from_bytes(sha256(b1[152:152 + 64]).digest(), byteorder="big") good = hash == self.val_root_hash_dc else: hash = int.from_bytes(sha256(b1[20:148]).digest(), byteorder="big") good = hash == self.val_root_hash if good: log.info("Root hash matches") else: log.error("Root hash mismatch:") log.error("Signed bitstream: {}".format( hex(hash))) log.error("Root entry hash bitstream provided: {}".format( hex(self.val_root_hash_dc if self.dc_pr else self.val_root_hash ))) if self.dc_pr: root_pub_key_x = int.from_bytes(b1[152:152 + 32], byteorder="big") root_pub_key_y = int.from_bytes(b1[152 + 32:152 + 64], byteorder="big") root_pub_key_v = (root_pub_key_x, root_pub_key_y) csk_pub_key_x = int.from_bytes(b1[264:264 + 32], byteorder="big") csk_pub_key_y = int.from_bytes(b1[264 + 32:264 + 64], byteorder="big") csk_pub_key_v = (csk_pub_key_x, csk_pub_key_y) csk_rs_r = int.from_bytes(b1[344:344 + 32], byteorder="big") csk_rs_s = int.from_bytes(b1[344 + 32:344 + 64], byteorder="big") csk_rs_v = (csk_rs_r, csk_rs_s) b0e_rs_r = int.from_bytes(b1[448:448 + 32], byteorder="big") b0e_rs_s = int.from_bytes(b1[448 + 32:448 + 64], byteorder="big") b0e_rs_v = (b0e_rs_r, b0e_rs_s) root_sha_v = hash csk_sha_v = int.from_bytes(sha256(b1[240:240 + 88]).digest(), byteorder="big") b0_sha_v = int.from_bytes(sha256(b0).digest(), byteorder="big") else: if self.cert_type == database.BITSTREAM_TYPE_CANCEL: b0e_off = 156 csk_pub_key_v = (0, 0) csk_rs_v = (0, 0) csk_sha_v = 0 else: b0e_off = 388 csk_pub_key_x = int.from_bytes(b1[164:164 + 32], byteorder="big") csk_pub_key_y = int.from_bytes(b1[212:212 + 32], byteorder="big") csk_pub_key_v = (csk_pub_key_x, csk_pub_key_y) csk_rs_r = int.from_bytes(b1[284:284 + 32], byteorder="big") csk_rs_s = int.from_bytes(b1[332:332 + 32], byteorder="big") csk_rs_v = (csk_rs_r, csk_rs_s) csk_sha_v = int.from_bytes(sha256(b1[152:152 + 128]).digest(), byteorder="big") root_pub_key_x = int.from_bytes(b1[32:32 + 32], byteorder="big") root_pub_key_y = int.from_bytes(b1[80:80 + 32], byteorder="big") root_pub_key_v = (root_pub_key_x, root_pub_key_y) b0e_rs_r = int.from_bytes(b1[b0e_off:b0e_off + 32], byteorder="big") b0e_rs_s = int.from_bytes(b1[b0e_off + 48:b0e_off + 48 + 32], byteorder="big") b0e_rs_v = (b0e_rs_r, b0e_rs_s) root_sha_v = hash b0_sha_v = int.from_bytes(sha256(b0).digest(), byteorder="big") # validate signatures if self.cert_type != database.BITSTREAM_TYPE_CANCEL: if ecdsa.verify_signature(root_pub_key_v, csk_sha_v, csk_rs_v): log.info("Signature of CSK with root key OK") else: log.error("Signature of CSK with root key mismatch") if ecdsa.verify_signature(csk_pub_key_v, b0_sha_v, b0e_rs_v): log.info("Signature of Block 0 with CSK OK") else: log.error("Signature of Block 0 with CSK mismatch") else: if ecdsa.verify_signature(root_pub_key_v, b0_sha_v, b0e_rs_v): log.info("Signature of Block 0 with root key OK") else: log.error("Signature of Block 0 with root key mismatch") return
def __init__(self, version='1.1.1g'): path = "%s/library" % os.path.dirname(os.path.abspath(__file__)) self.nanotime = None if _platform == "win32" or _platform == "win64": dll_name = 'libcrypto-1_1-x64.dll' else: dll_name = '*libcrypto*.so' dlls = glob.glob(os.path.join(path, dll_name)) self.lib = self._find_openssl_so(version, *dlls) common_util.assert_in_error(self.lib, "Failed to find crypto library") # Initialize OPEN algorithm self.lib.OPENSSL_init_crypto.argtypes = [c_uint, c_void_p] self.lib.OPENSSL_init_crypto.restype = None # Create new key self.lib.EC_KEY_new.argtypes = [] self.lib.EC_KEY_new.restype = c_void_p # Create new group with the curve e self.lib.EC_GROUP_new_by_curve_name.argtypes = [c_uint] self.lib.EC_GROUP_new_by_curve_name.restype = c_void_p # pair the group and key self.lib.EC_KEY_set_group.argtypes = [c_void_p, c_void_p] self.lib.EC_KEY_set_group.restype = c_int # Generate key self.lib.EC_KEY_generate_key.argtypes = [c_void_p] self.lib.EC_KEY_generate_key.restype = c_int # Create BIO self.lib.BIO_new.argtypes = [c_void_p] self.lib.BIO_new.restype = c_void_p # Create BIO method self.lib.BIO_s_file.argtypes = [] self.lib.BIO_s_file.restype = c_void_p # Read PEM file self.lib.BIO_ctrl.argtypes = [c_void_p, c_int, c_long, c_char_p] self.lib.BIO_ctrl.restype = c_int # Create encryption self.lib.EVP_get_cipherbyname.argtypes = [c_char_p] self.lib.EVP_get_cipherbyname.restype = c_void_p # Write EC Param to PEM self.lib.PEM_write_bio_ECPKParameters.argtypes = [c_void_p, c_void_p] self.lib.PEM_write_bio_ECPKParameters.restype = c_int # Write key to PEM self.lib.PEM_write_bio_ECPrivateKey.argtypes = [ c_void_p, c_void_p, c_void_p, c_char_p, c_int, c_void_p, c_void_p, ] self.lib.PEM_write_bio_ECPrivateKey.restype = c_int # Write public key to PEM self.lib.PEM_write_bio_EC_PUBKEY.argtypes = [c_void_p, c_void_p] self.lib.PEM_write_bio_EC_PUBKEY.restype = c_int # Read Private key from PEM self.lib.PEM_read_bio_ECPrivateKey.argtypes = [ c_void_p, c_void_p, c_void_p, c_char_p, ] self.lib.PEM_read_bio_ECPrivateKey.restype = c_void_p # Read Public key from PEM self.lib.PEM_read_bio_PUBKEY.argtypes = [ c_void_p, c_void_p, c_void_p, c_char_p ] self.lib.PEM_read_bio_PUBKEY.restype = c_void_p # Get public key self.lib.EC_KEY_get0_public_key.argtypes = [c_void_p] self.lib.EC_KEY_get0_public_key.restype = c_void_p # Convert a public key to key self.lib.EVP_PKEY_get1_EC_KEY.argtypes = [c_void_p] self.lib.EVP_PKEY_get1_EC_KEY.restype = c_void_p # Create new Big Number self.lib.BN_new.argtypes = [] self.lib.BN_new.restype = c_void_p # Get group from key self.lib.EC_KEY_get0_group.argtypes = [c_void_p] self.lib.EC_KEY_get0_group.restype = c_void_p # Get EC curve from group self.lib.EC_GROUP_get_curve_name.argtypes = [c_void_p] self.lib.EC_GROUP_get_curve_name.restype = c_int # Generate key from curve self.lib.EC_KEY_new_by_curve_name.argtypes = [c_int] self.lib.EC_KEY_new_by_curve_name.restype = c_void_p # Set public key coordinate info self.lib.EC_KEY_set_public_key_affine_coordinates.argtypes = [ c_void_p, c_void_p, c_void_p, ] self.lib.EC_KEY_set_public_key_affine_coordinates.restype = c_int # Verify key self.lib.EC_KEY_check_key.argtypes = [c_void_p] self.lib.EC_KEY_check_key.restype = c_int # Set Group ASN1 flag self.lib.EC_GROUP_set_asn1_flag.argtypes = [c_void_p, c_int] self.lib.EC_GROUP_set_asn1_flag.restype = None # Set Group conversion self.lib.EC_GROUP_set_point_conversion_form.argtypes = [ c_void_p, c_int ] self.lib.EC_GROUP_set_point_conversion_form.restype = None # Get XY from of a public key self.lib.EC_POINT_get_affine_coordinates_GFp.argtypes = [ c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, ] self.lib.EC_POINT_get_affine_coordinates_GFp.restype = c_int # Get number of bit of Big Number self.lib.BN_num_bits.argtypes = [c_void_p] self.lib.BN_num_bits.restype = c_int # Convert Big Number to Byte array self.lib.BN_bn2bin.argtypes = [c_void_p, c_char_p] self.lib.BN_bn2bin.restype = c_int # Convert Byte array to Big Number self.lib.BN_bin2bn.argtypes = [c_char_p, c_int, c_void_p] self.lib.BN_bin2bn.restype = c_void_p # Convert Big Number to char * self.lib.BN_bn2hex.argtypes = [c_void_p] self.lib.BN_bn2hex.restype = c_char_p self.lib.BN_copy.argtypes = [c_void_p, c_void_p] self.lib.BN_copy.restype = c_void_p self.lib.ECDSA_SIG_set0.argtypes = [c_void_p, c_void_p, c_void_p] self.lib.ECDSA_SIG_set0.restype = c_int self.lib.ECDSA_SIG_get0.argtypes = [ c_void_p, POINTER(c_void_p), POINTER(c_void_p) ] self.lib.ECDSA_SIG_get0.restype = None # Convert enum to char * self.lib.OBJ_nid2ln.argtypes = [c_int] self.lib.OBJ_nid2ln.restype = c_char_p # Free Big Number self.lib.BN_clear_free.argtypes = [c_void_p] self.lib.BN_clear_free.restype = None # Free key self.lib.EC_KEY_free.argtypes = [c_void_p] self.lib.EC_KEY_free.restype = None # Free public key self.lib.EVP_PKEY_free.argtypes = [c_void_p] self.lib.EVP_PKEY_free.restype = None # Free group self.lib.EC_GROUP_free.argtypes = [c_void_p] self.lib.EC_GROUP_free.restype = None # Free bio self.lib.BIO_free_all.argtypes = [c_void_p] self.lib.BIO_free_all.restype = None # Sign self.lib.ECDSA_do_sign.argtypes = [c_char_p, c_int, c_void_p] self.lib.ECDSA_do_sign.restype = POINTER(OPENSSL_SIGNATURE) # New signature self.lib.ECDSA_SIG_new.argtypes = [] self.lib.ECDSA_SIG_new.restype = POINTER(OPENSSL_SIGNATURE) # Verify self.lib.ECDSA_do_verify.argtypes = [ c_char_p, c_int, POINTER(OPENSSL_SIGNATURE), c_void_p, ] self.lib.ECDSA_do_verify.restype = c_int # Free signature self.lib.ECDSA_SIG_free.argtypes = [c_void_p] self.lib.ECDSA_SIG_free.restype = None # Free generic self.lib.CRYPTO_free.argtypes = [c_void_p] self.lib.CRYPTO_free.restype = None # Initialize self.lib.OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CONFIG, None) # SHA256 self.lib.SHA256.argtypes = [c_void_p, c_size_t, c_char_p] self.lib.SHA256.restype = c_char_p self.lib.SHA256_Init.argtypes = [POINTER(OPENSSL_SHA256)] self.lib.SHA256_Init.restype = c_int self.lib.SHA256_Update.argtypes = [ POINTER(OPENSSL_SHA256), c_void_p, c_size_t ] self.lib.SHA256_Update.restype = c_int self.lib.SHA256_Final.argtypes = [c_char_p, POINTER(OPENSSL_SHA256)] self.lib.SHA256_Final.restype = c_int # SHA384 self.lib.SHA384.argtypes = [c_void_p, c_size_t, c_char_p] self.lib.SHA384.restype = c_char_p self.lib.SHA384_Init.argtypes = [POINTER(OPENSSL_SHA512)] self.lib.SHA384_Init.restype = c_int self.lib.SHA384_Update.argtypes = [ POINTER(OPENSSL_SHA512), c_void_p, c_size_t ] self.lib.SHA384_Update.restype = c_int self.lib.SHA384_Final.argtypes = [c_char_p, POINTER(OPENSSL_SHA512)] self.lib.SHA384_Final.restype = c_int # SHA512 self.lib.SHA512.argtypes = [c_void_p, c_size_t, c_char_p] self.lib.SHA512.restype = c_char_p self.lib.SHA512_Init.argtypes = [POINTER(OPENSSL_SHA512)] self.lib.SHA512_Init.restype = c_int self.lib.SHA512_Update.argtypes = [ POINTER(OPENSSL_SHA512), c_void_p, c_size_t ] self.lib.SHA512_Update.restype = c_int self.lib.SHA512_Final.argtypes = [c_char_p, POINTER(OPENSSL_SHA512)] self.lib.SHA512_Final.restype = c_int
def check_pem_file(self): common_util.assert_in_error(os.path.exists(self.file), "PEM file %s does not exist" % self.file) lines = open(self.file, "r") private_tracking = 0 encrypted_tracking = 0 public_tracking = 0 for line in lines: if line.find("-----BEGIN EC PRIVATE KEY-----") == 0: common_util.assert_in_error( private_tracking == 0, ("Basic checking on %s failed. Keyword " + '"-----BEGIN EC PRIVATE KEY-----" is detected twice') % self.file, ) common_util.assert_in_error( encrypted_tracking == 0, ("Basic checking on %s failed. Encrypted " + "Private Key is already detected") % self.file, ) common_util.assert_in_error( public_tracking == 0, ("Basic checking on %s failed. Public Key " + "is already detected") % self.file, ) private_tracking += 1 elif line.find("-----BEGIN ENCRYPTED PRIVATE KEY-----") == 0: common_util.assert_in_error( encrypted_tracking == 0, ("Basic checking on %s failed. Keyword " + '"-----BEGIN ENCRYPTED PRIVATE KEY-----" is ' + "detected twice") % self.file, ) common_util.assert_in_error( private_tracking == 0, ("Basic checking on %s failed. EC Private " + "Key is already detected") % self.file, ) common_util.assert_in_error( public_tracking == 0, ("Basic checking on %s failed. Public " + "Key is already detected") % self.file, ) encrypted_tracking += 1 elif line.find("-----BEGIN PUBLIC KEY-----") == 0: common_util.assert_in_error( public_tracking == 0, ("Basic checking on %s failed. Keyword " + '"-----BEGIN PUBLIC KEY-----" is detected twice') % self.file, ) common_util.assert_in_error( private_tracking == 0, ("Basic checking on %s failed. EC Private " + "Key is already detected") % self.file, ) common_util.assert_in_error( encrypted_tracking == 0, ("Basic checking on %s failed. Encrypted " + "Private Key is already detected") % self.file, ) public_tracking += 1 elif line.find("-----END EC PRIVATE KEY-----") == 0: common_util.assert_in_error( encrypted_tracking == 0, ("Basic checking on %s failed. Encrypted Private " + "Key is already detected") % self.file, ) common_util.assert_in_error( public_tracking == 0, ("Basic checking on %s failed. Public " + "Key is already detected") % self.file, ) common_util.assert_in_error( private_tracking != 0, ("Basic checking on %s failed. Keyword " + '"-----BEGIN EC PRIVATE KEY-----" is not detected ' + 'before keyword "-----END EC PRIVATE KEY-----"') % self.file, ) common_util.assert_in_error( private_tracking == 1, ("Basic checking on %s failed. Keyword " + '"-----END EC PRIVATE KEY-----" is detected twice') % self.file, ) private_tracking += 1 elif line.find("-----END ENCRYPTED PRIVATE KEY-----") == 0: common_util.assert_in_error( private_tracking == 0, ("Basic checking on %s failed. EC Private " + "Key is already detected") % self.file, ) common_util.assert_in_error( public_tracking == 0, ("Basic checking on %s failed. Public " + "Key is already detected") % self.file, ) common_util.assert_in_error( encrypted_tracking != 0, ("Basic checking on %s failed. Keyword " + '"-----BEGIN ENCRYPTED PRIVATE KEY-----" ' + "is not detected before keyword " + '"-----END ENCRYPTED PRIVATE KEY-----"') % self.file, ) common_util.assert_in_error( encrypted_tracking == 1, ("Basic checking on %s failed. Keyword " + '"-----END ENCRYPTED PRIVATE KEY-----" ' + "is detected twice") % self.file, ) encrypted_tracking += 1 elif line.find("-----END PUBLIC KEY-----") == 0: common_util.assert_in_error( private_tracking == 0, ("Basic checking on %s failed. EC Private " + "Key is already detected") % self.file, ) common_util.assert_in_error( encrypted_tracking == 0, ("Basic checking on %s failed. Encrypted Private " + "Key is already detected") % self.file, ) common_util.assert_in_error( public_tracking != 0, ("Basic checking on %s failed. Keyword " + '"-----BEGIN PUBLIC KEY-----" is not ' + 'detected before keyword "-----END PUBLIC KEY-----"') % self.file, ) common_util.assert_in_error( public_tracking == 1, ("Basic checking on %s failed. Keyword " + '"-----END PUBLIC KEY-----" is detected twice') % self.file, ) public_tracking += 1 lines.close() common_util.assert_in_error( (private_tracking == 2 and encrypted_tracking == 0 and public_tracking == 0) or (private_tracking == 0 and encrypted_tracking == 2 and public_tracking == 0) or (private_tracking == 0 and encrypted_tracking == 0 and public_tracking == 2), ("Basic checking on %s failed. Problem in detected " + "EC Private, Encrypted Private or Public Key") % self.file, ) return public_tracking == 2
def main(): parser = argparse.ArgumentParser(prog='pacsign', description="Sign PAC bitstreams") subparsers = parser.add_subparsers( title="Commands", description="Image types", help="Allowable image types", dest="main_command", ) parser_sr = subparsers.add_parser("SR", aliases=["FIM", "BBS"], help="Static FPGA image") parser_bmc = subparsers.add_parser("BMC", aliases=["BMC_FW"], help="BMC image") parser_pr = subparsers.add_parser("PR", aliases=["AFU", "GBS"], help="Reconfigurable FPGA image") parser_print = subparsers.add_parser("print", help="Print header information") add_common_options(parser_sr) add_common_options(parser_bmc) add_common_options(parser_pr) parser_print.add_argument("files", nargs="+", help="List of files whose contents" " are to be printed") parser_print.add_argument( "-v", "--verbose", help="Increase verbosity. Can be specified multiple times", action="count", ) args = parser.parse_args() if len(sys.argv) == 1: parser.print_help() sys.exit() if not args.verbose: args.verbose = 0 if args.verbose > 2: args.verbose = 2 log.handlers[0].setLevel(LOGLEVELS[args.verbose]) if args.main_command == "print": return reader.print_file_contents(args.files) manager = args.HSM_manager.rstrip('_manager') # Load HSM handler try: hsm_manager = importlib.import_module('.{}'.format(manager), 'pacsign.hsm_managers') except ImportError as err: common_util.assert_in_error( False, "Error '{}' importing module {}".format(err, args.HSM_manager)) try: importlib.invalidate_caches() except AttributeError: pass try: _method = getattr(hsm_manager, "HSM_MANAGER") except AttributeError: common_util.assert_in_error( False, "Invalid key manager module %s" % args.HSM_manager) if args.cert_type == "RK_384": common_util.assert_in_error(False, "384-bit keys not supported") # Validate arguments if args.cert_type == "UPDATE": common_util.assert_in_error( args.input_file is not None and args.output_file is not None, "Update requires both an input and output file", ) if os.path.isfile(args.output_file): common_util.assert_in_error( answer_y_n( args, "Output file {} exists. Overwrite".format( args.output_file)), "Aborting.", ) if args.root_key is None: common_util.assert_in_error( answer_y_n( args, "No root key specified. Generate unsigned bitstream"), "Aborting.", ) if args.code_signing_key is None: common_util.assert_in_error( answer_y_n(args, "No CSK specified. Generate unsigned bitstream"), "Aborting.", ) if args.root_bitstream is None: common_util.assert_in_error( answer_y_n( args, "No root entry hash bitstream specified." " Verification will not be done. Continue", ), "Aborting.", ) else: common_util.assert_in_error( os.path.isfile(args.root_bitstream), "File doesn't exist '{}'".format(args.root_bitstream), ) if args.csk_id is not None: common_util.assert_in_error( False, "CSK ID cannot be specified for update types") maker = reader.UPDATE_reader(args, hsm_manager, args.HSM_config) elif args.cert_type == "CANCEL": common_util.assert_in_error(args.root_key is not None, "Cancellation type requires a root key") if args.code_signing_key is not None: common_util.assert_in_error( answer_y_n(args, "CSK specified but not required. Continue"), "Aborting.", ) common_util.assert_in_error( args.csk_id is not None, "CSK ID must be specified for cancellation types") common_util.assert_in_error( args.input_file is None, "Cancellation not allowed with input file.") common_util.assert_in_error(args.output_file is not None, "No output file specified") if args.root_bitstream is None: common_util.assert_in_error( answer_y_n( args, "No root entry hash bitstream specified." " Verification will not be done. Continue", ), "Aborting.", ) else: common_util.assert_in_error( os.path.isfile(args.root_bitstream), "File doesn't exist '{}'".format(args.root_bitstream), ) if os.path.isfile(args.output_file): common_util.assert_in_error( answer_y_n( args, "Output file {} exists. Overwrite".format( args.output_file)), "Aborting.", ) maker = reader.CANCEL_reader(args, hsm_manager, args.HSM_config) elif args.cert_type in ["RK_256", "RK_384"]: common_util.assert_in_error( args.root_key is not None, "Root hash programming requires a root key") if args.code_signing_key is not None: common_util.assert_in_error( answer_y_n(args, "CSK specified and will be ignored. Continue"), "Aborting.", ) if args.csk_id is not None: common_util.assert_in_error( answer_y_n(args, "CSK ID specified and will be ignored. Continue"), "Aborting.", ) common_util.assert_in_error( args.input_file is None, "Root hash programming not allowed with input file.", ) common_util.assert_in_error(args.output_file is not None, "No output file specified") if args.root_bitstream is not None: common_util.assert_in_error( False, "--root_bitstream option not allowed for hash programming generation.", ) if os.path.isfile(args.output_file): common_util.assert_in_error( answer_y_n( args, "Output file {} exists. Overwrite".format( args.output_file)), "Aborting.", ) maker = reader.RHP_reader(args, hsm_manager, args.HSM_config) logging.shutdown() return maker.run()