def generate_nvs_bin(args, spake2p_params): dac_raw_privkey = 'dac_raw_privkey.bin' dac_raw_pubkey = 'dac_raw_pubkey.bin' gen_raw_ec_keypair_from_der(args.dac_key, dac_raw_pubkey, dac_raw_privkey) csv_content = 'key,type,encoding,value\n' csv_content += 'chip-factory,namespace,,\n' csv_content += 'discriminator,data,u32,{}\n'.format(args.discriminator) csv_content += 'iteration-count,data,u32,{}\n'.format(spake2p_params['Iteration Count']) csv_content += 'salt,data,string,{}\n'.format(spake2p_params['Salt']) csv_content += 'verifier,data,string,{}\n'.format(spake2p_params['Verifier']) csv_content += 'dac-cert,file,binary,{}\n'.format(os.path.abspath(args.dac_cert)) csv_content += 'dac-key,file,binary,{}\n'.format(os.path.abspath(dac_raw_privkey)) csv_content += 'dac-pub-key,file,binary,{}\n'.format(os.path.abspath(dac_raw_pubkey)) csv_content += 'pai-cert,file,binary,{}\n'.format(os.path.abspath(args.pai_cert)) csv_content += 'cert-dclrn,file,binary,{}\n'.format(os.path.abspath(args.cd)) with open('nvs_partition.csv', 'w') as f: f.write(csv_content) nvs_args = SimpleNamespace(input='nvs_partition.csv', output='partition.bin', size=hex(args.size), outdir=os.getcwd(), version=2) nvs_partition_gen.generate(nvs_args) os.remove('nvs_partition.csv') os.remove(dac_raw_privkey) os.remove(dac_raw_pubkey)
def generate_nvs_bin(args): csv_content = 'key,type,encoding,value\n' csv_content += 'chip-factory,namespace,,\n' for k, v in FACTORY_DATA.items(): if v['value'] is None: continue csv_content += f"{k},{v['type']},{v['encoding']},{v['value']}\n" with open(FACTORY_PARTITION_CSV, 'w') as f: f.write(csv_content) if args.encrypt: nvs_args = SimpleNamespace(version=2, keygen=True, keyfile=NVS_KEY_PARTITION_BIN, inputkey=None, outdir=os.getcwd(), input=FACTORY_PARTITION_CSV, output=FACTORY_PARTITION_BIN, size=hex(args.size)) nvs_partition_gen.encrypt(nvs_args) else: nvs_args = SimpleNamespace(input=FACTORY_PARTITION_CSV, output=FACTORY_PARTITION_BIN, size=hex(args.size), outdir=os.getcwd(), version=2) nvs_partition_gen.generate(nvs_args)
def generate_nvs_partition(input_filename, output_filename): nvs_args = DefineArgs({ 'input': input_filename, 'outdir': os.getcwd(), 'output': output_filename, 'size': hex(0x3000), 'version': 2, 'keyfile':None, }) nvs_gen.generate(nvs_args, is_encr_enabled=False, encr_key=None)
def gen_nvs_partition_bin(dest_filedir, output_bin_filename): # Generate nvs args to be sent to NVS Partition Utility nvs_args = SimpleNamespace(input=dest_filedir + 'node_info.csv', output=output_bin_filename, size='0x6000', outdir=dest_filedir, version=2) # Run NVS Partition Utility to create binary of node info data print("\nGenerating NVS Partition Binary from claiming data: " + dest_filedir + output_bin_filename) log.debug("Generating NVS Partition Binary from claiming data: " + dest_filedir + output_bin_filename) nvs_partition_gen.generate(nvs_args)
def generate_nvs_bin(args): csv_content = 'key,type,encoding,value\n' csv_content += 'chip-factory,namespace,,\n' for k, v in FACTORY_DATA.items(): if v['value'] is None: continue csv_content += f"{k},{v['type']},{v['encoding']},{v['value']}\n" with open('nvs_partition.csv', 'w') as f: f.write(csv_content) nvs_args = SimpleNamespace(input='nvs_partition.csv', output='partition.bin', size=hex(args.size), outdir=os.getcwd(), version=2) nvs_partition_gen.generate(nvs_args)
def create_intermediate_csv(args, keys_in_config_file, keys_in_values_file, keys_repeat, is_encr=False): file_identifier_value = '0' csv_str = 'csv' bin_str = 'bin' set_output_keyfile = False # Add config data per namespace to `config_data_to_write` list config_data_to_write = add_config_data_per_namespace(args.conf) try: with open(args.values, 'r') as csv_values_file: values_file_reader = csv.reader(csv_values_file, delimiter=',') keys = next(values_file_reader) filename, file_ext = os.path.splitext(args.values) target_filename = filename + "_created" + file_ext if keys_repeat: target_values_file = set_repeat_value(keys_repeat, keys, args.values, target_filename) else: target_values_file = args.values csv_values_file = open(target_values_file, 'r') values_file_reader = csv.reader(csv_values_file, delimiter=',') next(values_file_reader) # Create new directory(if doesn't exist) to store csv file generated output_csv_target_dir = create_dir(csv_str, args.outdir) # Create new directory(if doesn't exist) to store bin file generated output_bin_target_dir = create_dir(bin_str, args.outdir) if args.keygen: set_output_keyfile = True for values_data_line in values_file_reader: key_value_data = list( zip_longest(keys_in_values_file, values_data_line)) # Get file identifier value from values file file_identifier_value = get_fileid_val( args.fileid, keys_in_config_file, keys_in_values_file, values_data_line, key_value_data, file_identifier_value) key_value_pair = key_value_data[:] # Verify if output csv file does not exist csv_filename = args.prefix + "-" + file_identifier_value + "." + csv_str output_csv_file = output_csv_target_dir + csv_filename if os.path.isfile(output_csv_file): raise SystemExit("Target csv file: %s already exists.`" % output_csv_file) # Add values corresponding to each key to csv intermediate file add_data_to_file(config_data_to_write, key_value_pair, output_csv_file) print("\nCreated CSV file: ===>", output_csv_file) # Verify if output bin file does not exist bin_filename = args.prefix + "-" + file_identifier_value + "." + bin_str output_bin_file = output_bin_target_dir + bin_filename if os.path.isfile(output_bin_file): raise SystemExit("Target binary file: %s already exists.`" % output_bin_file) args.input = output_csv_file args.output = os.path.join(bin_str, bin_filename) if set_output_keyfile: args.keyfile = "keys-" + args.prefix + "-" + file_identifier_value if is_encr: nvs_partition_gen.encrypt(args) else: nvs_partition_gen.generate(args) print("\nFiles generated in %s ..." % args.outdir) except Exception as e: print(e) exit(1) finally: csv_values_file.close()
def claim(port): """ Claim the node connected to the given serial port (Get cloud credentials) :param port: Serial Port :type port: str :raises Exception: If there is an HTTP issue while claiming SSLError: If there is an issue in SSL certificate validation ConnectionError: If there is network connection issue :return: None on Success :rtype: None """ try: node_id = None node_info = None hmac_challenge = None claim_verify_data = None claim_initiate_url = CLAIM_INITIATE_URL claim_verify_url = CLAIM_VERIFY_URL private_key = None curr_claim_data = None user_whitelist_err_msg = ('user is not allowed to claim esp32 device.' ' please contact administrator') config = configmanager.Config() userid = config.get_user_id() creds_dir = Path( path.expanduser( str(Path(path.expanduser(configmanager.HOME_DIRECTORY))) + '/' + str(Path(path.expanduser(configmanager.CONFIG_DIRECTORY))) + '/claim_data/' + userid)) if not creds_dir.exists(): os.makedirs(path.expanduser(creds_dir)) log.debug("Creating new directory " + str(creds_dir)) print("\nClaiming process started. This may take time.") log.info("Claiming process started. This may take time.") node_platform, mac_addr = get_node_platform_and_mac(esptool, port) print("Node platform detected is: ", node_platform) print("MAC address is: ", mac_addr) log.debug("MAC address received: " + mac_addr) log.debug("Node platform detected is: " + node_platform) log.info("Creating session") curr_session = session.Session() header = curr_session.request_header start = time.time() mac_dir = Path(path.expanduser(str(creds_dir) + '/' + mac_addr)) if not mac_dir.exists(): os.makedirs(path.expanduser(mac_dir)) log.debug("Creating new directory " + str(mac_dir)) output_bin_filename = mac_addr + '.bin' mac_dir_path = str(mac_dir) + '/' # Set values dest_filedir = mac_dir_path # Set csv file data node_info_csv = [ 'key,type,encoding,value', 'rmaker_creds,namespace,,', 'node_id,file,binary,' + dest_filedir + 'node.info', 'mqtt_host,file,binary,' + dest_filedir + 'endpoint.info', 'client_cert,file,binary,' + dest_filedir + 'node.crt', 'client_key,file,binary,' + dest_filedir + 'node.key' ] # Generate nvs args to be sent to NVS Partition Utility nvs_args = SimpleNamespace(input=dest_filedir + 'node_info.csv', output=output_bin_filename, size='0x6000', outdir=dest_filedir, version=2) # Set config mac addr path mac_addr_config_path = str(Path(path.expanduser( configmanager.CONFIG_DIRECTORY))) + '/claim_data/' +\ userid +\ '/' +\ mac_addr +\ '/' + output_bin_filename # Check if claim data for node exists in CONFIG directory log.debug("Checking if claim data for node exists in directory: " + configmanager.HOME_DIRECTORY + configmanager.CONFIG_DIRECTORY) curr_claim_data = configmanager.Config().get_binary_config( config_file=mac_addr_config_path) if curr_claim_data: print("\nClaiming data already exists at location: " + dest_filedir) log.debug("Claiming data already exists at location: " + dest_filedir) log.info("Using existing claiming data") print("Using existing claiming data") # Flashing existing binary onto node print("\nFlashing existing binary onto node\n") log.info("Flashing existing binary onto node") flash_bin_onto_node(port, esptool, dest_filedir + output_bin_filename) log.info("Binary flashed onto node") return # Generate Key log.info("Generate RSA key") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) log.info("RSA Private Key generated") # Set Claim initiate request data claim_initiate_data = {"mac_addr": mac_addr, "platform": node_platform} claim_init_enc_data = str(claim_initiate_data).replace("'", '"') print("Claim initiate started") # Sign the CSR using the CA try: # Claim Initiate Request log.info("Claim initiate started. Sending claim/initiate POST\ request") log.debug("Claim Initiate POST Request: url: " + claim_initiate_url + "data: " + str(claim_init_enc_data) + "headers: " + str(header) + "verify: " + CERT_FILE) claim_initiate_response = requests.post(url=claim_initiate_url, data=claim_init_enc_data, headers=header, verify=CERT_FILE) if claim_initiate_response.status_code != 200: log.error("Claim initiate failed.\n" + claim_initiate_response.text) exit(0) print("Claim initiate done") log.debug("Claim Initiate POST Response: status code: " + str(claim_initiate_response.status_code) + " and response text: " + claim_initiate_response.text) log.info("Claim initiate done") # Get data from response depending on node_platform if node_platform == "esp32": # Generate CSR with common_name=node_id received in response node_id = str( json.loads(claim_initiate_response.text)['node_id']) print("Generating CSR") log.info("Generating CSR") csr = gen_host_csr(private_key, common_name=node_id) if not csr: raise Exception("CSR Not Generated. Claiming Failed") log.info("CSR generated") claim_verify_data = {"csr": csr} # Save node id as node info to use while saving claim data # in csv file node_info = node_id else: auth_id = str( json.loads(claim_initiate_response.text)['auth_id']) hmac_challenge = str( json.loads(claim_initiate_response.text)['challenge']) print("Generating CSR") log.info("Generating CSR") csr = gen_host_csr(private_key, common_name=mac_addr) if not csr: raise Exception("CSR Not Generated. Claiming Failed") log.info("CSR generated") log.info("Getting secret key from device") secret_key = get_secret_key(port, esptool) log.info("Getting secret key from device") log.info("Generating hmac challenge response") hmac_challenge_response = gen_hmac_challenge_resp( secret_key, hmac_challenge) hmac_challenge_response = hmac_challenge_response.strip('\n') log.debug("Secret Key generated: " + secret_key) log.debug("HMAC Challenge Response: " + hmac_challenge_response) claim_verify_data = { "auth_id": auth_id, "challenge_response": hmac_challenge_response, "csr": csr } # Save node id as node info to use while saving claim data # in csv file node_info = mac_addr claim_verify_enc_data = str(claim_verify_data).replace("'", '"') log.debug("Claim Verify POST Request: url: " + claim_verify_url + "data: " + str(claim_verify_enc_data) + "headers: " + str(header) + "verify: " + CERT_FILE) claim_verify_response = requests.post(url=claim_verify_url, data=claim_verify_enc_data, headers=header, verify=CERT_FILE) if claim_verify_response.status_code != 200: claim_verify_response_json = json.loads( claim_verify_response.text.lower()) if (claim_verify_response_json["description"] in user_whitelist_err_msg): log.error('Claim verification failed.\n' + claim_verify_response.text) print( '\nYour account isn\'t whitelisted for ESP32.' ' Please send your registered email address to' ' [email protected] for whitelisting') else: log.error('Claim verification failed.\n' + claim_verify_response.text) exit(0) print("Claim verify done") log.debug("Claim Verify POST Response: status code: " + str(claim_verify_response.status_code) + " and response text: " + claim_verify_response.text) log.info("Claim verify done") node_cert = json.loads(claim_verify_response.text)['certificate'] print("Claim certificate received") log.info("Claim certificate received") except requests.exceptions.SSLError: raise SSLError except requests.ConnectionError: log.error("Please check the Internet connection.") exit(0) # Set node claim data sys.stdout = StringIO() log.info("Getting MQTT Host") endpointinfo = node.get_mqtt_host(None) log.debug("Endpoint info received: " + endpointinfo) sys.stdout = sys.__stdout__ # Extract private key in bytes from private key object generated log.info("Extracting private key in bytes") node_private_key = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) # Create files of each claim data info print("\nSaving claiming data info at location: ", dest_filedir) log.debug("Saving claiming data info at location: " + dest_filedir) create_files_of_claim_info(dest_filedir, node_info, node_private_key, node_cert, endpointinfo, node_info_csv) # Run NVS Partition Utility to create binary of node info data print("\nGenerating NVS Partition Binary from claiming data: " + dest_filedir + output_bin_filename) log.debug("Generating NVS Partition Binary from claiming data: " + dest_filedir + output_bin_filename) nvs_partition_gen.generate(nvs_args) print("\nFlashing onto node\n") log.info("Flashing binary onto node") flash_bin_onto_node(port, esptool, dest_filedir + output_bin_filename) print("Claiming done") log.info("Claiming done") print("Time(s):" + str(time.time() - start)) except Exception as err: log.error(err) sys.exit(err)
def create_intermediate_csv(args, keys_in_config_file, keys_in_values_file, keys_repeat, is_encr=False): file_identifier_value = '0' csv_str = 'csv' bin_str = 'bin' line = None set_output_keyfile = False # Add config data per namespace to `config_data_to_write` list config_data_to_write = add_config_data_per_namespace(args.conf) try: with open(args.values, 'r', newline=None) as csv_values_file: # first line must be keys in file line = csv_values_file.readline() if not isinstance(line, str): line = line.encode('utf-8') keys = line.strip().split(',') filename, file_ext = os.path.splitext(args.values) target_filename = filename + '_created' + file_ext if keys_repeat: target_values_file = set_repeat_value(keys_repeat, keys, args.values, target_filename) else: target_values_file = args.values csv_values_file = open(target_values_file, 'r', newline=None) # Read header line csv_values_file.readline() # Create new directory(if doesn't exist) to store csv file generated output_csv_target_dir = create_dir(csv_str, args.outdir) # Create new directory(if doesn't exist) to store bin file generated output_bin_target_dir = create_dir(bin_str, args.outdir) if args.keygen: set_output_keyfile = True line = csv_values_file.readline() if not isinstance(line, str): line = line.encode('utf-8') values_data_line = line.strip().split(',') while values_data_line: key_value_data = list( zip_longest(keys_in_values_file, values_data_line)) # Get file identifier value from values file file_identifier_value = get_fileid_val( args.fileid, keys_in_config_file, keys_in_values_file, values_data_line, key_value_data, file_identifier_value) key_value_pair = key_value_data[:] # Verify if output csv file does not exist csv_filename = args.prefix + '-' + file_identifier_value + '.' + csv_str output_csv_file = output_csv_target_dir + csv_filename if os.path.isfile(output_csv_file): raise SystemExit('Target csv file: %s already exists.`' % output_csv_file) # Add values corresponding to each key to csv intermediate file add_data_to_file(config_data_to_write, key_value_pair, output_csv_file) print('\nCreated CSV file: ===>', output_csv_file) # Verify if output bin file does not exist bin_filename = args.prefix + '-' + file_identifier_value + '.' + bin_str output_bin_file = output_bin_target_dir + bin_filename if os.path.isfile(output_bin_file): raise SystemExit('Target binary file: %s already exists.`' % output_bin_file) args.input = output_csv_file args.output = os.path.join(bin_str, bin_filename) if set_output_keyfile: args.keyfile = 'keys-' + args.prefix + '-' + file_identifier_value if is_encr: nvs_partition_gen.encrypt(args) else: nvs_partition_gen.generate(args) # Read next line line = csv_values_file.readline() if not isinstance(line, str): line = line.encode('utf-8') values_data_line = line.strip().split(',') if len(values_data_line) == 1 and '' in values_data_line: break print('\nFiles generated in %s ...' % args.outdir) except Exception as e: print(e) exit(1) finally: csv_values_file.close()