diff --git a/examples/dpp/README.md b/examples/dpp/README.md new file mode 100644 index 000000000..f9108fa7c --- /dev/null +++ b/examples/dpp/README.md @@ -0,0 +1,60 @@ +This example exercises the DPP functionality in hostapd / wpa_supplicant + +Please enable INTERWORKING in your hostap/.config file and build it with this flag. + + CONFIG_INTERWORKING=y + +Please ensure the following flag is set both in your .config file for wpa\_supplicant AND hostapd. + + CONFIG_DPP=y + +In wpa\_supplicant .config file, you need the following + + CONFIG_IEEE80211W=y + +Build hostapd and wpa\_supplicant with these flags enabled. + +The DPP protocol is used to onboard headless (IOT) devices. + +Here is the sequence of commands we are trying to exercise (this is in the script, you don't need to do this manually): + +Configurator: add a configurator object + + wpa_cli -p /var/run/wpa_supplicant1 dpp_configurator_add + +Configurator: get the configurator key using the returned ID + + wpa_cli -p /var/run/wpa_supplicant1 dpp_configurator_get_key 1 + +Configurator: self sign the configurator + + wpa_cli -p /var/run/wpa_supplicant1 dpp_configurator_sign conf=sta-psk psk=29153c1e60c0e50afa47530eb7b6db1193b0131616c139e9f1785d174861cca7 ssid=012a configurator=1' + +Enrollee: generate QR code for device + + wpa_cli -p /var/run/wpa_supplicant2 dpp_bootstrap_gen type=qrcode mac=00:00:00:00:00:82 key=..... + +Enrollee: get the qr code using the returned bootstrap\_info\_id + + wpa_cli -p /var/run/wpa_supplicant2 dpp_bootstrap_get_uri 1 + +Enrollee: listen for dpp provisioning request + + wpa_cli -p /var/run/wpa_supplicant2 dpp_listen 2412 + +Configurator: Enter the sta QR Code in the Configurator. + + wpa_cli -p /var/run/wpa_supplicant1 dpp_qr_code 'DPP:.....' + +Configurator: Send provisioning request to enrollee. + + wpa_cli -p /var/run/wpa_supplicant1 dpp_auth_init peer=1 conf=sta-psk ssid=012a psk=.... configurator=1 + +Enrollee: save the config file + + wpa_cli -p /var/run/wpa_supplicant2 save_config + +Enrollee: reload the config file +wpa_cli -p /var/run/wpa_supplicant2 reconfigure + +In the provided example, sta1 is the configurator and sta2 is the enrollee diff --git a/examples/dpp/dpp-auth.py b/examples/dpp/dpp-auth.py new file mode 100755 index 000000000..b0baef3f8 --- /dev/null +++ b/examples/dpp/dpp-auth.py @@ -0,0 +1,201 @@ +#!/usr/bin/python + +'This example shows how to work with authentication' + +from mininet.log import setLogLevel, info +from mn_wifi.cli import CLI_wifi +from mn_wifi.net import Mininet_wifi +import time +import os +import os.path +import os +from os import path +import subprocess +import socket +import sys +import json + +import binascii + + +def get_hex_key_from_der_key(derfile): + with open(derfile, mode="rb") as file: + fileContent = file.read() + hex_str = binascii.b2a_hex(fileContent) + return hex_str + + +def onboard_device(configurator,configurator_clicmd, sta, sta_clicmd, mac_addr, passwd,ssid, cacertpath) : + + # On enrolee side + # Generate QR code for the device. Store the qr code id returned by the command. + # The private key of the certificate. + dpp_configurator_key="3077020101042026F1181A112402FC90A286B299997A146B5C311C15753211DF9927641702CC58A00A06082A8648CE3D030107A14403420004883D409D7FDED9CBD4800991D615E4F559FCCC0B347D6AFF561FF5EFB60FD94B4E96D46235D0EA99B07B14C032AAD3404EB41DF630215ACDD2C5778FC81A2B57" + + dpp_configurator_id = sta.cmdPrint( sta_clicmd + ' dpp_configurator_add key=' + dpp_configurator_key + " curve=prime256v1").split('\n')[1] + info("enrollee: generate QR code for device public key = {}\n".format(dpp_configurator_key)) + bootstrapping_info_id = sta.cmd( sta_clicmd + " dpp_bootstrap_gen type=qrcode mac=" + mac_addr + " key=" + dpp_configurator_key ).split('\n')[1] + #Get QR Code of device using the bootstrap info id. + info("enrollee: get the qr code using the returned bootstrap_info_id\n") + bootstrapping_uri = "'" + sta.cmd(sta_clicmd + " dpp_bootstrap_get_uri " + str(bootstrapping_info_id)).split('\n')[1] + "'" + info("enrollee : show the dpp bootstrap info\n") + sta.cmdPrint(sta_clicmd + " dpp_bootstrap_info " + bootstrapping_info_id) + info("bootstrapping_uri = " + bootstrapping_uri + "\n") + info("enrollee: listen for dpp provisioning request\n") + #Make device listen to DPP request (The central frequency of channel 1 is 2412) in case if enrollee is a client device. + sta.cmd(sta_clicmd + " dpp_listen " + str(2412) ) + time.sleep(3) + + info("Configurator: Enter the sta QR Code in the Configurator.\n") + bootstrapping_info_id = configurator.cmdPrint(configurator_clicmd + " dpp_qr_code " + bootstrapping_uri).split("\n")[1] + info("Configurator: Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an AP. conf is sta-dpp if enrollee is a client). configurator_id = {} \n".format(dpp_configurator_id)) + result = configurator.cmd(configurator_clicmd + ' dpp_auth_init peer={} conf=sta-psk ssid={} psk={} configurator={} cacert={}'.format(bootstrapping_info_id,ssid,passwd, dpp_configurator_id ,cacertpath)) + time.sleep(3) + result = configurator.cmd(configurator_clicmd + " dpp_config_status id=" + str(bootstrapping_info_id)).split("\n")[1] + print("dpp_config_status returned " + str(result)) + jsonval = json.loads(result) + mud_url = jsonval["config_status"]["mud_url"] + idevid = jsonval["config_status"]["idevid"] + print("idevid "+ idevid) + print ("mud_url " + mud_url) + + + info("Enrollee: save the config file\n") + sta.cmd(sta_clicmd + " save_config") + info("Enrollee: reload the config file\n") + sta.cmd(sta_clicmd + " reconfigure") + +def topology(): + "Create a network." + cwd = os.getcwd() + net = Mininet_wifi() + # Note - there is a bug in the DPP code. This only works for short ssids + ssid = "012a" + passwd = '12345678' + cmd = ["wpa_passphrase", ssid, passwd] + + p = subprocess.Popen(cmd,shell=False, stdin= subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + res,err = p.communicate() + lines = res.split("\n") + + for line in lines: + if "psk" in line: + start = line.strip().find("psk=") + if start == 0: + psk=line[5:] + + info("Psk = " + psk + "\n") + + info("*** Creating nodes\n") + cwd = os.path.realpath(os.getcwd()) + + + ap1 = net.addAccessPoint('ap1', ssid=ssid, mode="g", channel="1", + hostapd_flags='-dd > /tmp/hostapd.txt', + passwd=passwd, encrypt='wpa2', + failMode="standalone", datapath='user') + + # sta1 is the configurator + sta1 = net.addStation('sta1', ssid=ssid, passwd=passwd, encrypt='wpa2', + wpasup_flags='-dd -f /tmp/debug1.txt', + wpasup_globals='ctrl_interface=/var/run/wpa_supplicant1\n' + 'ctrl_interface_group=0\n') + + # sta2 is the enrolee. Note that it does not have the + # PSK and it does not know the access point. + # It will be configured by the configurator + sta2 = net.addStation('sta2', + wpasup_flags='-dd -f /tmp/debug2.txt', + wpasup_globals= 'ctrl_interface=/var/run/wpa_supplicant2\n' + 'ctrl_interface_group=0\n' + 'update_config=1\n' + 'pmf=1\n' + 'dpp_mud_url=https://www.nist.local/nistmud1\n' + 'dpp_idevid={}/DevID50/DevIDCredentials/IDevID50.cert.pem\n' + 'dpp_name=MyDpp\n' + 'dpp_config_processing=2'.format(cwd), + + encrypt='wpa2') + + info("*** Configuring wifi nodes\n") + net.configureWifiNodes() + + info("*** Associating Stations\n") + net.addLink(sta1, ap1) + net.addLink(sta2, ap1) + + sta1.setMAC("00:00:00:00:00:81","sta1-wlan0") + sta2.setMAC("00:00:00:00:00:82","sta2-wlan0") + + info("*** Starting network\n") + net.build() + ap1.start([]) + + info("*** Adding openflow wireless rule : \n ") + # For wireless isolation hack. Put a normal flow in there so stations + # can ping each other + ap1.cmd('ovs-ofctl add-flow ap1 "priority=10,actions=in_port,normal"') + #sta1.cmdPrint("python sockserver.py&") + + + # on the configurator + + cli_cmd = "wpa_cli -p /var/run/wpa_supplicant1 " + configurator = sta1 + dpp_version = configurator.cmd( cli_cmd + " get_capability dpp").split('\n')[1] + print("dpp_version is " + dpp_version) + if dpp_version != "DPP=2": + sys.exit() + + # todo -- this is redundant remove it. + configurator.cmdPrint( cli_cmd + " dpp_controller_start tcp_port=9090").split('\n')[1] + + configurator.cmd( cli_cmd+" log_level debug") + info("Configurator: add a configurator object\n") + dpp_configurator_id = configurator.cmd( cli_cmd + ' dpp_configurator_add ').split('\n')[1] + info("Configurator: self sign the configurator\n") + configurator.cmdPrint( cli_cmd + " dpp_configurator_sign conf=sta-psk psk={} ssid={} configurator={}".format(psk,ssid,str(dpp_configurator_id)) ) + + + + f = open("sta2_0.staconf","r") + lines = f.read() + print("******************************\n") + print("sta2 staconf BEFORE CONFIGURATION\n") + print(lines) + print("******************************") + f.close() + + time.sleep(5) + + onboard_device(sta1,cli_cmd,sta2,"wpa_cli -p /var/run/wpa_supplicant2","00:00:00:00:00:82", psk,ssid.encode('hex'),"{}/DevID50/CredentialChain/ca-chain.cert.pem".format(cwd)) + + time.sleep(3) + + f = open("sta2_0.staconf","r") + lines = f.read() + print("******************************\n") + print("sta2 staconf AFTER CONFIGURATION\n") + print(lines) + print("******************************") + f.close() + + info("\n*** Try the following at the CLI \n") + info("sta1 ping sta2 \n") + info("/tmp/debug*.txt and /tmp/hostapd.txt contain logs \n") + info("cat /var/log/syslog | grep hostapd shows you if the authentication succeeded\n") + CLI_wifi(net) + + info("*** Stopping network\n") + net.stop() + + +if __name__ == '__main__': + if path.exists("/tmp/debug1.txt") : + os.remove("/tmp/debug1.txt") + if path.exists("/tmp/debug2.txt") : + os.remove("/tmp/debug2.txt") + if path.exists("/tmp/hostapd.txt") : + os.remove("/tmp/hostapd.txt") + setLogLevel('info') + topology() diff --git a/examples/eap-tls/eap-tls-auth.py b/examples/eap-tls/eap-tls-auth.py index 490983880..fb62f821c 100755 --- a/examples/eap-tls/eap-tls-auth.py +++ b/examples/eap-tls/eap-tls-auth.py @@ -12,12 +12,12 @@ def topology(): "Create a network." - cwd = os.getcwd() + cwd = os.path.realpath(os.getcwd()) net = Mininet_wifi() info("*** Creating nodes\n") sta1 = net.addStation('sta1', - wpasup_flags='-dd > /tmp/debug1.txt', + wpasup_flags='-dd -f /tmp/debug1.txt', wpasup_globals='eapol_version=2', encrypt='wpa2', config='key_mgmt=WPA-EAP,' @@ -25,13 +25,13 @@ def topology(): 'ssid="simplewifi",' 'eap=TLS,' 'scan_ssid=1,' - 'ca_cert="{}/examples/eap-tls/CA/ca.crt",' - 'client_cert="{}/examples/eap-tls/CA/client.crt",' - 'private_key="{}/examples/eap-tls/CA/client.key"' + 'ca_cert="{}/CA/ca.crt",' + 'client_cert="{}/CA/client.crt",' + 'private_key="{}/CA/client.key"' .format(cwd, cwd, cwd)) sta2 = net.addStation('sta2', - wpasup_flags='-dd > /tmp/debug2.txt', + wpasup_flags='-dd -f /tmp/debug2.txt', wpasup_globals='eapol_version=2', encrypt='wpa2', config='key_mgmt=WPA-EAP,' @@ -39,9 +39,9 @@ def topology(): 'identity="mranga@nist.gov",' 'eap=TLS,' 'ssid="simplewifi",' - 'ca_cert="{}/examples/eap-tls/CA/ca.crt",' - 'client_cert="{}/examples/eap-tls/CA/client.crt",' - 'private_key="{}/examples/eap-tls/CA/client.key"' + 'ca_cert="{}/CA/ca.crt",' + 'client_cert="{}/CA/client.crt",' + 'private_key="{}/CA/client.key"' .format(cwd, cwd, cwd)) ap1 = net.addAccessPoint('ap1', @@ -57,10 +57,10 @@ def topology(): 'wpa_key_mgmt=WPA-EAP,' 'logger_syslog=-1,' 'logger_syslog_level=0,' - 'ca_cert={}/examples/eap-tls/CA/ca.crt,' - 'server_cert={}/examples/eap-tls/CA/server.crt,' - 'private_key={}/examples/eap-tls/CA/server.key,' - 'eap_user_file={}/examples/eap-tls/eap_users' + 'ca_cert={}/CA/ca.crt,' + 'server_cert={}/CA/server.crt,' + 'private_key={}/CA/server.key,' + 'eap_user_file={}/eap_users' .format(cwd, cwd, cwd, cwd), isolate_clients=True) @@ -80,6 +80,9 @@ def topology(): # can ping each other ap1.cmd('ovs-ofctl add-flow ap1 "priority=10,actions=in_port,normal"') + # cmd = "/usr/bin/wireshark"+ " -k"+ " -i ap1-wlan1" + # ap1.cmdPrint(cmd + "&") + info("\n*** Try the following at the CLI \n") info("sta1 ping sta2 \n") info("/tmp/debug*.txt and /tmp/hostapd.txt contain logs \n") diff --git a/mn_wifi/link.py b/mn_wifi/link.py index 6016471e4..c32e12b32 100644 --- a/mn_wifi/link.py +++ b/mn_wifi/link.py @@ -1344,7 +1344,10 @@ def updateParams(cls, sta, ap, wlan): sta.params['freq'][wlan] = ap.get_freq(0) sta.params['channel'][wlan] = ap.params['channel'][0] sta.params['mode'][wlan] = ap.params['mode'][0] - sta.params['ssid'][wlan] = ap.params['ssid'][0] + # For dpp, the sta params may not have the ssid (this has to be configured + # by dpp + if 'ssid' in sta.params and type(sta.params['ssid']) == dict: + sta.params['ssid'][wlan] = ap.params['ssid'][0] @classmethod def associate(cls, sta, ap, wlan, ap_wlan): @@ -1417,7 +1420,9 @@ def wpaFile(cls, sta, ap, wlan, ap_wlan): if 'passwd' not in sta.params: passwd = ap.params['passwd'][ap_wlan] else: - passwd = sta.params['passwd'][wlan] + # For dpp the password is not specified. + if 'passwd' in sta.params: + passwd = sta.params['passwd'][wlan] if 'wpasup_globals' not in sta.params \ or ('wpasup_globals' in sta.params @@ -1425,6 +1430,13 @@ def wpaFile(cls, sta, ap, wlan, ap_wlan): cmd = 'ctrl_interface=/var/run/wpa_supplicant\n' if 'wpasup_globals' in sta.params: cmd += sta.params['wpasup_globals'] + '\n' + # For dpp, we cannot specify the network. This is configured + # by the DPP protocol + if "dpp_config_processing" in sta.params['wpasup_globals'] \ + and 'config' not in sta.params: + fileName = '%s_%s.staconf' % (sta.name, wlan) + os.system('echo \'%s\' > %s' % (cmd, fileName)) + return cmd = cmd + 'network={\n' if 'config' in sta.params: