[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