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)
Beispiel #4
0
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)
Beispiel #5
0
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)
Beispiel #6
0
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()
Beispiel #7
0
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)
Beispiel #8
0
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()