Hello, reposting the patches so you can take another look.
=== iscsi implementation is missing base64 encoding support. At least StarWind uses it for CHAP and hence fails with gpxe. Patches tested by a user who originally reported the problem and myself. base64 +300 iscsi +63 TOTAL: +363 http://git.etherboot.org/?p=people/peper/gpxe.git;a=shortlog;h=refs/heads/base64 http://github.com/peper/gpxe-peper/compare/master...base64 -- Best Regards Piotr Jaroszyński
From c61e33703253d4ccd5510e4c2b4fc6bac44b87e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Jaroszy=C5=84ski?= <[email protected]> Date: Sat, 27 Mar 2010 02:10:34 +0100 Subject: [PATCH 1/2] [base64] Add decoding support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piotr Jaroszyński <[email protected]> --- src/core/base64.c | 70 +++++++++++++++++++++++++++++++++++++++++++++ src/include/gpxe/base64.h | 12 ++++++++ 2 files changed, 82 insertions(+), 0 deletions(-) diff --git a/src/core/base64.c b/src/core/base64.c index 5619ef7..3c0d354 100644 --- a/src/core/base64.c +++ b/src/core/base64.c @@ -66,3 +66,73 @@ void base64_encode ( const char *raw, char *encoded ) { DBG ( "Base64-encoded \"%s\" as \"%s\"\n", raw, encoded ); assert ( strlen ( encoded ) == base64_encoded_len ( strlen ( raw ) ) ); } + +static const char base64d[80] = + "\x3e\x80\x80\x80\x3f\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x80" +// + (,) (-) (.) / 0 1 2 3 4 5 6 7 8 9 (:) + "\x80\x80\xc0\x80\x80\x80\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" +// (;) (<) = (>) (?) (@) A B C D E F G H I J + "\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" +// K L M N O P Q R S T U V W X Y Z + "\x80\x80\x80\x80\x80\x80\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23" +// ([) (\) (]) (^) (_) (`) a b c d e f g h i j + "\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33"; +// k l m n o p q r s t u v w x y z + +/** + * Base64-decode a string + * + * @v encoded Encoded string + * @v raw Buffer for raw data + * @ret rc Return length of the decoded data or -1 to indicate an error + * + * The buffer must be the correct length for the raw data. Use + * something like + * + * char buf[ base64_decode_buf_len ( strlen ( encoded ) ) ]; + * + * to provide a buffer of the correct size. + */ +int base64_decode ( const char *encoded, char *raw ) { + size_t encoded_len = strlen ( encoded ); + size_t len = ( encoded_len / 4 ) * 3; + unsigned int byte; + unsigned int i; + unsigned char buf[4]; + + if ( encoded_len % 4 != 0 ) + return -1; + + for ( byte = 0 ; byte < len ; byte += 3 ) { + for ( i = 0 ; i < 4 ; ++i) { + if ( ( *encoded < '+' ) || ( *encoded > 'z' ) ) + return -1; + + buf[ i ] = base64d[ *(encoded++) - '+' ]; + + if ( buf[ i ] & 0x80 ) { + if ( ( buf[ i ] == 0xc0 ) && ( byte + i + 1 >= len ) && + ( ( i == 3 ) || ( *encoded == '=' ) ) ) { + buf[ i ] = 0; + --len; + } else { + return -1; + } + } + } + + /* + * this loop does: + * *(raw++) = ( buf[ 0 ] << 2 ) | ( buf[ 1 ] >> 4 ); + * *(raw++) = ( buf[ 1 ] << 4 ) | ( buf[ 2 ] >> 2 ); + * *(raw++) = ( buf[ 2 ] << 6 ) | ( buf[ 3 ] >> 0 ); + */ + for ( i = 0 ; i < 3 ; ++i ) + *(raw++) = ( buf[ i ] << ( i * 2 + 2 ) ) | + ( buf[ i + 1 ] >> ( 4 - i * 2 ) ); + } + + DBG ( "Base64-decoded \"%s\" to \"%s\"\n", encoded, raw ); + + return len; +} diff --git a/src/include/gpxe/base64.h b/src/include/gpxe/base64.h index e38bef0..e4255a3 100644 --- a/src/include/gpxe/base64.h +++ b/src/include/gpxe/base64.h @@ -21,6 +21,18 @@ static inline size_t base64_encoded_len ( size_t raw_len ) { return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 ); } +/** + * Calculate length of the buffer needed to base64-decode string + * + * @v encoded_len Encoded string length (excluding NUL) + * @ret buf_len Buffer length + */ +static inline size_t base64_decode_buf_len ( size_t encoded_len ) { + return ( ( encoded_len / 4 ) * 3 ); +} + extern void base64_encode ( const char *raw, char *encoded ); +extern int base64_decode ( const char *encoded, char *raw ); + #endif /* _GPXE_BASE64_H */ -- 1.7.1
From 879bf68ae5815c56fe48a2bc1935f6f10f282d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Jaroszy=C5=84ski?= <[email protected]> Date: Sat, 27 Mar 2010 02:15:36 +0100 Subject: [PATCH 2/2] [iscsi] Add base64 support for CHAP. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piotr Jaroszyński <[email protected]> --- src/net/tcp/iscsi.c | 89 +++++++++++++++++++++++++++------------------------ 1 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index b13a107..c6708ae 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <gpxe/tcpip.h> #include <gpxe/settings.h> #include <gpxe/features.h> +#include <gpxe/base64.h> #include <gpxe/iscsi.h> /** @file @@ -731,6 +732,38 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi, return 0; } +static int iscsi_decode_hex ( const char * encoded, char * raw ) +{ + char *endp; + char buf[3]; + unsigned int i; + + buf[2] = 0; + + for ( i = 0 ; ( encoded[0] && encoded[1] ) ; encoded += 2, i++ ) { + memcpy ( buf, encoded, 2 ); + raw[i] = strtoul ( buf, &endp, 16 ); + if ( *endp != '\0' ) { + return -1; + } + } + + return i; +} + +static int iscsi_decode_large_binary ( const char * encoded, char * raw ) +{ + if ( encoded[0] != '0' ) + return -1; + + if ( ( encoded[1] == 'x' ) || ( encoded[1] == 'X' ) ) + return iscsi_decode_hex ( encoded + 2, raw ); + if ( ( encoded[1] == 'b' ) || ( encoded[1] == 'B' ) ) + return base64_decode ( encoded + 2, raw ); + + return -1; +} + /** * Handle iSCSI CHAP_C text value * @@ -740,31 +773,17 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi, */ static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi, const char *value ) { - char buf[3]; - char *endp; - uint8_t byte; unsigned int i; + char raw[ base64_decode_buf_len ( strlen ( value ) ) ]; + int len; - /* Check and strip leading "0x" */ - if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) { + if ( ( len = iscsi_decode_large_binary ( value, raw ) ) < 0 ) { DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge \"%s\"\n", iscsi, value ); return -EPROTO_INVALID_CHAP_CHALLENGE; } - value += 2; - /* Process challenge an octet at a time */ - for ( ; ( value[0] && value[1] ) ; value += 2 ) { - memcpy ( buf, value, 2 ); - buf[2] = 0; - byte = strtoul ( buf, &endp, 16 ); - if ( *endp != '\0' ) { - DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge " - "byte \"%s\"\n", iscsi, buf ); - return -EPROTO_INVALID_CHAP_CHALLENGE; - } - chap_update ( &iscsi->chap, &byte, sizeof ( byte ) ); - } + chap_update ( &iscsi->chap, raw, len ); /* Build CHAP response */ DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi ); @@ -821,11 +840,9 @@ static int iscsi_handle_chap_n_value ( struct iscsi_session *iscsi, */ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi, const char *value ) { - char buf[3]; - char *endp; - uint8_t byte; - unsigned int i; int rc; + char raw[ base64_decode_buf_len ( strlen ( value ) ) ]; + size_t len; /* Generate CHAP response for verification */ chap_finish ( &iscsi->chap ); @@ -843,38 +860,26 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi, ( sizeof ( iscsi->chap_challenge ) - 1 ) ); chap_respond ( &iscsi->chap ); - /* Check and strip leading "0x" */ - if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) { + if ( ( rc = iscsi_decode_large_binary ( value, raw ) ) < 0 ) { DBGC ( iscsi, "iSCSI %p saw invalid CHAP response \"%s\"\n", iscsi, value ); return -EPROTO_INVALID_CHAP_RESPONSE; } - value += 2; + + len = rc; /* Check CHAP response length */ - if ( strlen ( value ) != ( 2 * iscsi->chap.response_len ) ) { + if ( len != iscsi->chap.response_len ) { DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n", iscsi ); return -EPROTO_INVALID_CHAP_RESPONSE; } - /* Process response an octet at a time */ - for ( i = 0 ; ( value[0] && value[1] ) ; value += 2, i++ ) { - memcpy ( buf, value, 2 ); - buf[2] = 0; - byte = strtoul ( buf, &endp, 16 ); - if ( *endp != '\0' ) { - DBGC ( iscsi, "iSCSI %p saw invalid CHAP response " - "byte \"%s\"\n", iscsi, buf ); - return -EPROTO_INVALID_CHAP_RESPONSE; - } - if ( byte != iscsi->chap.response[i] ) { - DBGC ( iscsi, "iSCSI %p saw incorrect CHAP " - "response\n", iscsi ); - return -EACCES_INCORRECT_TARGET_PASSWORD; - } + if ( memcmp ( raw, iscsi->chap.response, len ) != 0 ) { + DBGC ( iscsi, "iSCSI %p saw incorrect CHAP " + "response\n", iscsi ); + return -EACCES_INCORRECT_TARGET_PASSWORD; } - assert ( i == iscsi->chap.response_len ); /* Mark session as authenticated */ iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK; -- 1.7.1
_______________________________________________ gPXE-devel mailing list [email protected] http://etherboot.org/mailman/listinfo/gpxe-devel
