[gPXE git] mainline: 6 commits to master (447aa79..607e5f9)

git at etherboot.org git at etherboot.org
Sat May 29 15:15:05 EDT 2010


In the Main gPXE repository, branch master has been updated.
      adds  607e5f9 [iscsi] Allow base64 encoding in large binary values
      adds  4a8601d [infiniband] Use generic base16 functions for SRP
      adds  9cf1c45 [iscsi] Use generic base16 functions for iSCSI
      adds  87a7dee [base16] Add generic base16 encoding and decoding routines
      adds  e55e079 [base64] Add ability to decode base64 strings
      adds  b2cd381 [base64] Allow base64_encode() to handle arbitrary data
      from  447aa79 [dhcp] Use correct DHCP options on EFI systems

Summary of changes:
 src/core/base16.c           |  106 ++++++++++++++++++++++++++++++++
 src/core/base64.c           |  101 ++++++++++++++++++++++++++++--
 src/include/gpxe/base16.h   |   38 ++++++++++++
 src/include/gpxe/base64.h   |   21 ++++++-
 src/include/gpxe/errfile.h  |    2 +
 src/net/infiniband/ib_srp.c |   16 ++---
 src/net/tcp/http.c          |    8 +-
 src/net/tcp/iscsi.c         |  142 +++++++++++++++++++++++--------------------
 8 files changed, 344 insertions(+), 90 deletions(-)
 create mode 100644 src/core/base16.c
 create mode 100644 src/include/gpxe/base16.h


- Log -----------------------------------------------------------------
------
commit 607e5f9dd265e409121b58d5ae7a9e7a23c9ed81
Author: Piotr Jaroszyński <p.jaroszynski at gmail.com>
Date: Fri May 28 19:52:47 2010 +0100
Committer: Piotr Jaroszyński <p.jaroszynski at gmail.com>

[iscsi] Allow base64 encoding in large binary values

Modified-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/net/tcp/iscsi.c |   70 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c
index fa9fb98..dc05f6e 100644
--- a/src/net/tcp/iscsi.c
+++ b/src/net/tcp/iscsi.c
@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <gpxe/settings.h>
 #include <gpxe/features.h>
 #include <gpxe/base16.h>
+#include <gpxe/base64.h>
 #include <gpxe/iscsi.h>
 
 /** @file
@@ -56,7 +57,7 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
 #define EPERM_INITIATOR_AUTHORISATION ( EPERM | EUNIQ_02 )
 #define EPROTO_INVALID_CHAP_ALGORITHM ( EPROTO | EUNIQ_01 )
 #define EPROTO_INVALID_CHAP_IDENTIFIER ( EPROTO | EUNIQ_02 )
-#define EPROTO_INVALID_CHAP_CHALLENGE ( EPROTO | EUNIQ_03 )
+#define EPROTO_INVALID_LARGE_BINARY ( EPROTO | EUNIQ_03 )
 #define EPROTO_INVALID_CHAP_RESPONSE ( EPROTO | EUNIQ_04 )
 
 /** iSCSI initiator name (explicitly specified) */
@@ -614,6 +615,41 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
 }
 
 /**
+ * Calculate maximum length of decoded large binary value
+ *
+ * @v encoded		Encoded large binary value
+ * @v max_raw_len	Maximum length of raw data
+ */
+static inline size_t
+iscsi_large_binary_decoded_max_len ( const char *encoded ) {
+	return ( strlen ( encoded ) ); /* Decoding never expands data */
+}
+
+/**
+ * Decode large binary value
+ *
+ * @v encoded		Encoded large binary value
+ * @v raw		Raw data
+ * @ret len		Length of raw data, or negative error
+ */
+static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw ) {
+
+	if ( encoded[0] != '0' )
+		return -EPROTO_INVALID_LARGE_BINARY;
+
+	switch ( encoded[1] ) {
+	case 'x' :
+	case 'X' :
+		return base16_decode ( ( encoded + 2 ), raw );
+	case 'b' :
+	case 'B' :
+		return base64_decode ( ( encoded + 2 ), raw );
+	default:
+		return -EPROTO_INVALID_LARGE_BINARY;
+	}
+}
+
+/**
  * Handle iSCSI TargetAddress text value
  *
  * @v iscsi		iSCSI session
@@ -737,24 +773,19 @@ 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 ) {
-	uint8_t buf[ strlen ( value ) ]; /* Decoding never expands data */
+	uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
 	unsigned int i;
-	int len;
-
-	/* Check and strip leading "0x" */
-	if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
-		DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
-		       iscsi, value );
-		return -EPROTO_INVALID_CHAP_CHALLENGE;
-	}
+	size_t len;
+	int rc;
 
 	/* Process challenge */
-	len = base16_decode ( ( value + 2 ), buf );
-	if ( len < 0 ) {
+	rc = iscsi_large_binary_decode ( value, buf );
+	if ( rc < 0 ) {
 		DBGC ( iscsi, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
-		       iscsi, value, strerror ( len ) );
-		return len;
+		       iscsi, value, strerror ( rc ) );
+		return rc;
 	}
+	len = rc;
 	chap_update ( &iscsi->chap, buf, len );
 
 	/* Build CHAP response */
@@ -812,7 +843,7 @@ 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 ) {
-	uint8_t buf[ strlen ( value ) ]; /* Decoding never expands data */
+	uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
 	size_t len;
 	int rc;
 
@@ -832,15 +863,8 @@ 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' ) ) {
-		DBGC ( iscsi, "iSCSI %p saw invalid CHAP response \"%s\"\n",
-		       iscsi, value );
-		return -EPROTO_INVALID_CHAP_RESPONSE;
-	}
-
 	/* Process response */
-	rc = base16_decode ( ( value + 2 ), buf );
+	rc = iscsi_large_binary_decode ( value, buf );
 	if ( rc < 0 ) {
 		DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",
 		       iscsi, value, strerror ( rc ) );

------
commit 4a8601d41b33a39c7e2d9d55a670c2f3fb2ca80f
Author: Michael Brown <mcb30 at ipxe.org>
Date: Fri May 28 19:04:59 2010 +0100
Committer: Piotr Jaroszyński <p.jaroszynski at gmail.com>

[infiniband] Use generic base16 functions for SRP

Signed-off-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/net/infiniband/ib_srp.c |   16 +++++++---------
 1 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/src/net/infiniband/ib_srp.c b/src/net/infiniband/ib_srp.c
index c156d3a..8880904 100644
--- a/src/net/infiniband/ib_srp.c
+++ b/src/net/infiniband/ib_srp.c
@@ -32,6 +32,7 @@ FILE_LICENCE ( BSD2 );
 
 #include <stdlib.h>
 #include <errno.h>
+#include <gpxe/base16.h>
 #include <gpxe/srp.h>
 #include <gpxe/infiniband.h>
 #include <gpxe/ib_cmrc.h>
@@ -78,8 +79,7 @@ static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
 				      unsigned int size_flags ) {
 	size_t size = ( size_flags & ~IB_SRP_PARSE_FLAG_MASK );
 	size_t rp_comp_len = strlen ( rp_comp );
-	char buf[3];
-	char *buf_end;
+	int decoded_size;
 
 	/* Allow optional components to be empty */
 	if ( ( rp_comp_len == 0 ) &&
@@ -91,13 +91,11 @@ static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
 		return -EINVAL_BYTE_STRING_LEN;
 
 	/* Parse byte string */
-	for ( ; size ; size--, rp_comp += 2, bytes++ ) {
-		memcpy ( buf, rp_comp, 2 );
-		buf[2] = '\0';
-		*bytes = strtoul ( buf, &buf_end, 16 );
-		if ( buf_end != &buf[2] )
-			return -EINVAL_BYTE_STRING;
-	}
+	decoded_size = base16_decode ( rp_comp, bytes );
+	if ( decoded_size < 0 )
+		return decoded_size;
+	assert ( decoded_size == size );
+
 	return 0;
 }
 

------
commit 9cf1c45a2e6119c259002e66b484e8228db2472e
Author: Michael Brown <mcb30 at ipxe.org>
Date: Fri May 28 16:21:56 2010 +0100
Committer: Piotr Jaroszyński <p.jaroszynski at gmail.com>

[iscsi] Use generic base16 functions for iSCSI

Signed-off-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/net/tcp/iscsi.c |   94 +++++++++++++++++++++------------------------------
 1 files changed, 39 insertions(+), 55 deletions(-)

diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c
index b13a107..fa9fb98 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/base16.h>
 #include <gpxe/iscsi.h>
 
 /** @file
@@ -481,7 +482,6 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
 static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
 					       void *data, size_t len ) {
 	unsigned int used = 0;
-	unsigned int i;
 	const char *auth_method;
 
 	if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
@@ -508,26 +508,23 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
 	}
 	
 	if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) ) {
+		char buf[ base16_encoded_len ( iscsi->chap.response_len ) + 1 ];
 		assert ( iscsi->initiator_username != NULL );
+		base16_encode ( iscsi->chap.response, iscsi->chap.response_len,
+				buf );
 		used += ssnprintf ( data + used, len - used,
-				    "CHAP_N=%s%cCHAP_R=0x",
-				    iscsi->initiator_username, 0 );
-		for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
-			used += ssnprintf ( data + used, len - used, "%02x",
-					    iscsi->chap.response[i] );
-		}
-		used += ssnprintf ( data + used, len - used, "%c", 0 );
+				    "CHAP_N=%s%cCHAP_R=0x%s%c",
+				    iscsi->initiator_username, 0, buf, 0 );
 	}
 
 	if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_CHALLENGE ) ) {
+		size_t challenge_len = ( sizeof ( iscsi->chap_challenge ) - 1 );
+		char buf[ base16_encoded_len ( challenge_len ) + 1 ];
+		base16_encode ( ( iscsi->chap_challenge + 1 ), challenge_len,
+				buf );
 		used += ssnprintf ( data + used, len - used,
-				    "CHAP_I=%d%cCHAP_C=0x",
-				    iscsi->chap_challenge[0], 0 );
-		for ( i = 1 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) {
-			used += ssnprintf ( data + used, len - used, "%02x",
-					    iscsi->chap_challenge[i] );
-		}
-		used += ssnprintf ( data + used, len - used, "%c", 0 );
+				    "CHAP_I=%d%cCHAP_C=0x%s%c",
+				    iscsi->chap_challenge[0], 0, buf, 0 );
 	}
 
 	if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) {
@@ -740,10 +737,9 @@ 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;
+	uint8_t buf[ strlen ( value ) ]; /* Decoding never expands data */
 	unsigned int i;
+	int len;
 
 	/* Check and strip leading "0x" */
 	if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
@@ -751,20 +747,15 @@ static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
 		       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 ) );
+
+	/* Process challenge */
+	len = base16_decode ( ( value + 2 ), buf );
+	if ( len < 0 ) {
+		DBGC ( iscsi, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
+		       iscsi, value, strerror ( len ) );
+		return len;
 	}
+	chap_update ( &iscsi->chap, buf, len );
 
 	/* Build CHAP response */
 	DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi );
@@ -821,10 +812,8 @@ 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;
+	uint8_t buf[ strlen ( value ) ]; /* Decoding never expands data */
+	size_t len;
 	int rc;
 
 	/* Generate CHAP response for verification */
@@ -849,32 +838,27 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
 		       iscsi, value );
 		return -EPROTO_INVALID_CHAP_RESPONSE;
 	}
-	value += 2;
 
-	/* Check CHAP response length */
-	if ( strlen ( value ) != ( 2 * iscsi->chap.response_len ) ) {
+	/* Process response */
+	rc = base16_decode ( ( value + 2 ), buf );
+	if ( rc < 0 ) {
+		DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",
+		       iscsi, value, strerror ( rc ) );
+		return rc;
+	}
+	len = rc;
+
+	/* Check CHAP response */
+	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 ( buf, iscsi->chap.response, len ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p incorrect CHAP response \"%s\"\n",
+		       iscsi, value );
+		return -EACCES_INCORRECT_TARGET_PASSWORD;
 	}
-	assert ( i == iscsi->chap.response_len );
 
 	/* Mark session as authenticated */
 	iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK;

------
commit 87a7dee910b9c6d42ea866e86748268342a7c091
Author: Michael Brown <mcb30 at ipxe.org>
Date: Fri May 28 14:58:04 2010 +0100
Committer: Piotr Jaroszyński <p.jaroszynski at gmail.com>

[base16] Add generic base16 encoding and decoding routines

Base16 encoding is currently implemented in both iSCSI and SRP.

Signed-off-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/core/base16.c          |  106 ++++++++++++++++++++++++++++++++++++++++++++
 src/include/gpxe/base16.h  |   38 ++++++++++++++++
 src/include/gpxe/errfile.h |    1 +
 3 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/src/core/base16.c b/src/core/base16.c
new file mode 100644
index 0000000..d74556d
--- /dev/null
+++ b/src/core/base16.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <gpxe/base16.h>
+
+/** @file
+ *
+ * Base16 encoding
+ *
+ */
+
+/**
+ * Base16-encode data
+ *
+ * @v raw		Raw data
+ * @v len		Length of raw data
+ * @v encoded		Buffer for encoded string
+ *
+ * The buffer must be the correct length for the encoded string.  Use
+ * something like
+ *
+ *     char buf[ base16_encoded_len ( len ) + 1 ];
+ *
+ * (the +1 is for the terminating NUL) to provide a buffer of the
+ * correct size.
+ */
+void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
+	const uint8_t *raw_bytes = raw;
+	char *encoded_bytes = encoded;
+	size_t remaining = len;
+
+	for ( ; remaining-- ; encoded_bytes += 2 ) {
+		sprintf ( encoded_bytes, "%02x", *(raw_bytes++) );
+	}
+
+	DBG ( "Base16-encoded to \"%s\":\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( strlen ( encoded ) == base16_encoded_len ( len ) );
+}
+
+/**
+ * Base16-decode data
+ *
+ * @v encoded		Encoded string
+ * @v raw		Raw data
+ * @ret len		Length of raw data, or negative error
+ *
+ * The buffer must be large enough to contain the decoded data.  Use
+ * something like
+ *
+ *     char buf[ base16_decoded_max_len ( encoded ) ];
+ *
+ * to provide a buffer of the correct size.
+ */
+int base16_decode ( const char *encoded, uint8_t *raw ) {
+	const char *encoded_bytes = encoded;
+	uint8_t *raw_bytes = raw;
+	char buf[3];
+	char *endp;
+	size_t len;
+
+	while ( encoded_bytes[0] ) {
+		if ( ! encoded_bytes[1] ) {
+			DBG ( "Base16-encoded string \"%s\" has invalid "
+			      "length\n", encoded );
+			return -EINVAL;
+		}
+		memcpy ( buf, encoded_bytes, 2 );
+		buf[2] = '\0';
+		*(raw_bytes++) = strtoul ( buf, &endp, 16 );
+		if ( *endp != '\0' ) {
+			DBG ( "Base16-encoded string \"%s\" has invalid "
+			      "byte \"%s\"\n", encoded, buf );
+			return -EINVAL;
+		}
+		encoded_bytes += 2;
+	}
+	len = ( raw_bytes - raw );
+
+	DBG ( "Base16-decoded \"%s\" to:\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( len <= base16_decoded_max_len ( encoded ) );
+
+	return ( len );
+}
diff --git a/src/include/gpxe/base16.h b/src/include/gpxe/base16.h
new file mode 100644
index 0000000..f0c9842
--- /dev/null
+++ b/src/include/gpxe/base16.h
@@ -0,0 +1,38 @@
+#ifndef _IPXE_BASE16_H
+#define _IPXE_BASE16_H
+
+/** @file
+ *
+ * Base16 encoding
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+
+/**
+ * Calculate length of base16-encoded data
+ *
+ * @v raw_len		Raw data length
+ * @ret encoded_len	Encoded string length (excluding NUL)
+ */
+static inline size_t base16_encoded_len ( size_t raw_len ) {
+	return ( 2 * raw_len );
+}
+
+/**
+ * Calculate maximum length of base16-decoded string
+ *
+ * @v encoded		Encoded string
+ * @v max_raw_len	Maximum length of raw data
+ */
+static inline size_t base16_decoded_max_len ( const char *encoded ) {
+	return ( ( strlen ( encoded ) + 1 ) / 2 );
+}
+
+extern void base16_encode ( const uint8_t *raw, size_t len, char *encoded );
+extern int base16_decode ( const char *encoded, uint8_t *raw );
+
+#endif /* _IPXE_BASE16_H */
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index 46f6fb0..93efa52 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_xfer		       ( ERRFILE_CORE | 0x000e0000 )
 #define ERRFILE_bitmap		       ( ERRFILE_CORE | 0x000f0000 )
 #define ERRFILE_base64		       ( ERRFILE_CORE | 0x00100000 )
+#define ERRFILE_base16		       ( ERRFILE_CORE | 0x00110000 )
 
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

------
commit e55e079c42b73c79182034d9d6efc83df77b7796
Author: Michael Brown <mcb30 at ipxe.org>
Date: Fri May 28 12:42:00 2010 +0100
Committer: Piotr Jaroszyński <p.jaroszynski at gmail.com>

[base64] Add ability to decode base64 strings

Inspired-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
Signed-off-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/core/base64.c          |   85 ++++++++++++++++++++++++++++++++++++++++++++
 src/include/gpxe/base64.h  |   15 ++++++++
 src/include/gpxe/errfile.h |    1 +
 3 files changed, 101 insertions(+), 0 deletions(-)

diff --git a/src/core/base64.c b/src/core/base64.c
index ac878fa..971f634 100644
--- a/src/core/base64.c
+++ b/src/core/base64.c
@@ -20,6 +20,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 #include <string.h>
+#include <ctype.h>
+#include <errno.h>
 #include <assert.h>
 #include <gpxe/base64.h>
 
@@ -68,3 +70,86 @@ void base64_encode ( const uint8_t *raw, size_t len, char *encoded ) {
 	DBG_HDA ( 0, raw, len );
 	assert ( strlen ( encoded ) == base64_encoded_len ( len ) );
 }
+
+/**
+ * Base64-decode string
+ *
+ * @v encoded		Encoded string
+ * @v raw		Raw data
+ * @ret len		Length of raw data, or negative error
+ *
+ * The buffer must be large enough to contain the decoded data.  Use
+ * something like
+ *
+ *     char buf[ base64_decoded_max_len ( encoded ) ];
+ *
+ * to provide a buffer of the correct size.
+ */
+int base64_decode ( const char *encoded, uint8_t *raw ) {
+	const uint8_t *encoded_bytes = ( ( const uint8_t * ) encoded );
+	uint8_t *raw_bytes = ( ( uint8_t * ) raw );
+	uint8_t encoded_byte;
+	char *match;
+	int decoded;
+	unsigned int bit = 0;
+	unsigned int pad_count = 0;
+	size_t len;
+
+	/* Zero the raw data */
+	memset ( raw, 0, base64_decoded_max_len ( encoded ) );
+
+	/* Decode string */
+	while ( ( encoded_byte = *(encoded_bytes++) ) ) {
+
+		/* Ignore whitespace characters */
+		if ( isspace ( encoded_byte ) )
+			continue;
+
+		/* Process pad characters */
+		if ( encoded_byte == '=' ) {
+			if ( pad_count >= 2 ) {
+				DBG ( "Base64-encoded string \"%s\" has too "
+				      "many pad characters\n", encoded );
+				return -EINVAL;
+			}
+			pad_count++;
+			bit -= 2; /* unused_bits = ( 2 * pad_count ) */
+			continue;
+		}
+		if ( pad_count ) {
+			DBG ( "Base64-encoded string \"%s\" has invalid pad "
+			      "sequence\n", encoded );
+			return -EINVAL;
+		}
+
+		/* Process normal characters */
+		match = strchr ( base64, encoded_byte );
+		if ( ! match ) {
+			DBG ( "Base64-encoded string \"%s\" contains invalid "
+			      "character '%c'\n", encoded, encoded_byte );
+			return -EINVAL;
+		}
+		decoded = ( match - base64 );
+
+		/* Add to raw data */
+		decoded <<= 2;
+		raw_bytes[ bit / 8 ] |= ( decoded >> ( bit % 8 ) );
+		raw_bytes[ bit / 8 + 1 ] |= ( decoded << ( 8 - ( bit % 8 ) ) );
+		bit += 6;
+	}
+
+	/* Check that we decoded a whole number of bytes */
+	if ( ( bit % 8 ) != 0 ) {
+		DBG ( "Base64-encoded string \"%s\" has invalid bit length "
+		      "%d\n", encoded, bit );
+		return -EINVAL;
+	}
+	len = ( bit / 8 );
+
+	DBG ( "Base64-decoded \"%s\" to:\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( len <= base64_decoded_max_len ( encoded ) );
+
+	/* Return length in bytes */
+	return ( len );
+}
diff --git a/src/include/gpxe/base64.h b/src/include/gpxe/base64.h
index c85f070..d57d016 100644
--- a/src/include/gpxe/base64.h
+++ b/src/include/gpxe/base64.h
@@ -10,6 +10,7 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <string.h>
 
 /**
  * Calculate length of base64-encoded data
@@ -21,6 +22,20 @@ static inline size_t base64_encoded_len ( size_t raw_len ) {
 	return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 );
 }
 
+/**
+ * Calculate maximum length of base64-decoded string
+ *
+ * @v encoded		Encoded string
+ * @v max_raw_len	Maximum length of raw data
+ *
+ * Note that the exact length of the raw data cannot be known until
+ * the string is decoded.
+ */
+static inline size_t base64_decoded_max_len ( const char *encoded ) {
+	return ( ( ( strlen ( encoded ) + 4 - 1 ) / 4 ) * 3 );
+}
+
 extern void base64_encode ( const uint8_t *raw, size_t len, char *encoded );
+extern int base64_decode ( const char *encoded, uint8_t *raw );
 
 #endif /* _GPXE_BASE64_H */
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index f2be7c0..46f6fb0 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -53,6 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_vsprintf	       ( ERRFILE_CORE | 0x000d0000 )
 #define ERRFILE_xfer		       ( ERRFILE_CORE | 0x000e0000 )
 #define ERRFILE_bitmap		       ( ERRFILE_CORE | 0x000f0000 )
+#define ERRFILE_base64		       ( ERRFILE_CORE | 0x00100000 )
 
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

------
commit b2cd381369d4e30d0b91ada50e17e62750d07670
Author: Michael Brown <mcb30 at ipxe.org>
Date: Fri May 28 01:17:22 2010 +0100
Committer: Piotr Jaroszyński <p.jaroszynski at gmail.com>

[base64] Allow base64_encode() to handle arbitrary data

Signed-off-by: Michael Brown <mcb30 at ipxe.org>
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/core/base64.c         |   16 +++++++++-------
 src/include/gpxe/base64.h |    6 +++---
 src/net/tcp/http.c        |    8 ++++----
 3 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/src/core/base64.c b/src/core/base64.c
index 5619ef7..ac878fa 100644
--- a/src/core/base64.c
+++ b/src/core/base64.c
@@ -33,23 +33,24 @@ static const char base64[64] =
 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 /**
- * Base64-encode a string
+ * Base64-encode data
  *
- * @v raw		Raw string
+ * @v raw		Raw data
+ * @v len		Length of raw data
  * @v encoded		Buffer for encoded string
  *
  * The buffer must be the correct length for the encoded string.  Use
  * something like
  *
- *     char buf[ base64_encoded_len ( strlen ( raw ) ) + 1 ];
+ *     char buf[ base64_encoded_len ( len ) + 1 ];
  *
  * (the +1 is for the terminating NUL) to provide a buffer of the
  * correct size.
  */
-void base64_encode ( const char *raw, char *encoded ) {
+void base64_encode ( const uint8_t *raw, size_t len, char *encoded ) {
 	const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
 	uint8_t *encoded_bytes = ( ( uint8_t * ) encoded );
-	size_t raw_bit_len = ( 8 * strlen ( raw ) );
+	size_t raw_bit_len = ( 8 * len );
 	unsigned int bit;
 	unsigned int tmp;
 
@@ -63,6 +64,7 @@ void base64_encode ( const char *raw, char *encoded ) {
 		*(encoded_bytes++) = '=';
 	*(encoded_bytes++) = '\0';
 
-	DBG ( "Base64-encoded \"%s\" as \"%s\"\n", raw, encoded );
-	assert ( strlen ( encoded ) == base64_encoded_len ( strlen ( raw ) ) );
+	DBG ( "Base64-encoded to \"%s\":\n", encoded );
+	DBG_HDA ( 0, raw, len );
+	assert ( strlen ( encoded ) == base64_encoded_len ( len ) );
 }
diff --git a/src/include/gpxe/base64.h b/src/include/gpxe/base64.h
index e38bef0..c85f070 100644
--- a/src/include/gpxe/base64.h
+++ b/src/include/gpxe/base64.h
@@ -12,15 +12,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdint.h>
 
 /**
- * Calculate length of base64-encoded string
+ * Calculate length of base64-encoded data
  *
- * @v raw_len		Raw string length (excluding NUL)
+ * @v raw_len		Raw data length
  * @ret encoded_len	Encoded string length (excluding NUL)
  */
 static inline size_t base64_encoded_len ( size_t raw_len ) {
 	return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 );
 }
 
-extern void base64_encode ( const char *raw, char *encoded );
+extern void base64_encode ( const uint8_t *raw, size_t len, char *encoded );
 
 #endif /* _GPXE_BASE64_H */
diff --git a/src/net/tcp/http.c b/src/net/tcp/http.c
index a365b2a..3b2b5b1 100644
--- a/src/net/tcp/http.c
+++ b/src/net/tcp/http.c
@@ -424,7 +424,7 @@ static void http_step ( struct process *process ) {
 	size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
 					strlen ( password ) ) : 0 );
 	size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
-	char user_pw[ user_pw_len + 1 /* NUL */ ];
+	uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
 	char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
 	int rc;
 	int request_len = unparse_uri ( NULL, 0, http->uri,
@@ -443,11 +443,11 @@ static void http_step ( struct process *process ) {
 		/* Construct authorisation, if applicable */
 		if ( user ) {
 			/* Make "user:password" string from decoded fields */
-			snprintf ( user_pw, sizeof ( user_pw ), "%s:%s",
-				   user, password );
+			snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
+				   "%s:%s", user, password );
 
 			/* Base64-encode the "user:password" string */
-			base64_encode ( user_pw, user_pw_base64 );
+			base64_encode ( user_pw, user_pw_len, user_pw_base64 );
 		}
 
 		/* Send GET request */
-----------------------------------------------------------------------


-- 
Main gPXE repository


More information about the gPXE-commits mailing list