Home | History | Annotate | Download | only in 80211
      1 /*
      2  * Copyright (c) 2009 Joshua Oreman <oremanj (at) rwcr.net>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <gpxe/net80211.h>
     22 #include <gpxe/sha1.h>
     23 #include <gpxe/wpa.h>
     24 #include <errno.h>
     25 
     26 /** @file
     27  *
     28  * Frontend for WPA using a pre-shared key.
     29  */
     30 
     31 /**
     32  * Initialise WPA-PSK state
     33  *
     34  * @v dev	802.11 device
     35  * @ret rc	Return status code
     36  */
     37 static int wpa_psk_init ( struct net80211_device *dev )
     38 {
     39 	return wpa_make_rsn_ie ( dev, &dev->rsn_ie );
     40 }
     41 
     42 /**
     43  * Start WPA-PSK authentication
     44  *
     45  * @v dev	802.11 device
     46  * @ret rc	Return status code
     47  */
     48 static int wpa_psk_start ( struct net80211_device *dev )
     49 {
     50 	char passphrase[64+1];
     51 	u8 pmk[WPA_PMK_LEN];
     52 	int len;
     53 	struct wpa_common_ctx *ctx = dev->handshaker->priv;
     54 
     55 	len = fetch_string_setting ( netdev_settings ( dev->netdev ),
     56 				     &net80211_key_setting, passphrase,
     57 				     64 + 1 );
     58 
     59 	if ( len <= 0 ) {
     60 		DBGC ( ctx, "WPA-PSK %p: no passphrase provided!\n", ctx );
     61 		net80211_deauthenticate ( dev, -EACCES );
     62 		return -EACCES;
     63 	}
     64 
     65 	pbkdf2_sha1 ( passphrase, len, dev->essid, strlen ( dev->essid ),
     66 		      4096, pmk, WPA_PMK_LEN );
     67 
     68 	DBGC ( ctx, "WPA-PSK %p: derived PMK from passphrase `%s':\n", ctx,
     69 	       passphrase );
     70 	DBGC_HD ( ctx, pmk, WPA_PMK_LEN );
     71 
     72 	return wpa_start ( dev, ctx, pmk, WPA_PMK_LEN );
     73 }
     74 
     75 /**
     76  * Step WPA-PSK authentication
     77  *
     78  * @v dev	802.11 device
     79  * @ret rc	Return status code
     80  */
     81 static int wpa_psk_step ( struct net80211_device *dev )
     82 {
     83 	struct wpa_common_ctx *ctx = dev->handshaker->priv;
     84 
     85 	switch ( ctx->state ) {
     86 	case WPA_SUCCESS:
     87 		return 1;
     88 	case WPA_FAILURE:
     89 		return -EACCES;
     90 	default:
     91 		return 0;
     92 	}
     93 }
     94 
     95 /**
     96  * Do-nothing function; you can't change a WPA key post-authentication
     97  *
     98  * @v dev	802.11 device
     99  * @ret rc	Return status code
    100  */
    101 static int wpa_psk_no_change_key ( struct net80211_device *dev __unused )
    102 {
    103 	return 0;
    104 }
    105 
    106 /**
    107  * Disable handling of received WPA authentication frames
    108  *
    109  * @v dev	802.11 device
    110  */
    111 static void wpa_psk_stop ( struct net80211_device *dev )
    112 {
    113 	wpa_stop ( dev );
    114 }
    115 
    116 /** WPA-PSK security handshaker */
    117 struct net80211_handshaker wpa_psk_handshaker __net80211_handshaker = {
    118 	.protocol = NET80211_SECPROT_PSK,
    119 	.init = wpa_psk_init,
    120 	.start = wpa_psk_start,
    121 	.step = wpa_psk_step,
    122 	.change_key = wpa_psk_no_change_key,
    123 	.stop = wpa_psk_stop,
    124 	.priv_len = sizeof ( struct wpa_common_ctx ),
    125 };
    126