]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[base16] Add buffer size parameter to base16_encode() and base16_decode()
authorMichael Brown <mcb30@ipxe.org>
Fri, 24 Apr 2015 13:34:32 +0000 (14:34 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 24 Apr 2015 13:41:32 +0000 (14:41 +0100)
The current API for Base16 (and Base64) encoding requires the caller
to always provide sufficient buffer space.  This prevents the use of
the generic encoding/decoding functionality in some situations, such
as in formatting the hex setting types.

Implement a generic hex_encode() (based on the existing
format_hex_setting()), implement base16_encode() and base16_decode()
in terms of the more generic hex_encode() and hex_decode(), and update
all callers to provide the additional buffer length parameter.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
12 files changed:
src/core/base16.c
src/core/settings.c
src/crypto/x509.c
src/drivers/net/ecm.c
src/drivers/net/netfront.c
src/include/ipxe/base16.h
src/interface/efi/efi_debug.c
src/net/infiniband/ib_srp.c
src/net/pccrc.c
src/net/tcp/httpcore.c
src/net/tcp/iscsi.c
src/tests/base16_test.c

index f5177c07c5e4f502080ea63333eaca8d0f36aacc..f9e0f3364f2077cae6dde1fc3158a2d87f2a2bb7 100644 (file)
@@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <errno.h>
 #include <assert.h>
 #include <ipxe/string.h>
+#include <ipxe/vsprintf.h>
 #include <ipxe/base16.h>
 
 /** @file
@@ -37,48 +38,42 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  */
 
 /**
- * Base16-encode data
+ * Encode hexadecimal string (with optional byte separator character)
  *
+ * @v separator                Byte separator character, or 0 for no separator
  * @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.
+ * @v raw_len          Length of raw data
+ * @v data             Buffer
+ * @v len              Length of buffer
+ * @ret len            Encoded length
  */
-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;
-
-       /* Encode each byte */
-       for ( ; remaining-- ; encoded_bytes += 2 ) {
-               sprintf ( encoded_bytes, "%02x", *(raw_bytes++) );
+size_t hex_encode ( char separator, const void *raw, size_t raw_len,
+                   char *data, size_t len ) {
+       const uint8_t *bytes = raw;
+       const char delimiter[2] = { separator, '\0' };
+       size_t used = 0;
+       unsigned int i;
+
+       if ( len )
+               data[0] = 0; /* Ensure that a terminating NUL exists */
+       for ( i = 0 ; i < raw_len ; i++ ) {
+               used += ssnprintf ( ( data + used ), ( len - used ),
+                                   "%s%02x", ( used ? delimiter : "" ),
+                                   bytes[i] );
        }
-
-       /* Ensure terminating NUL exists even if length was zero */
-       *encoded_bytes = '\0';
-
-       DBG ( "Base16-encoded to \"%s\":\n", encoded );
-       DBG_HDA ( 0, raw, len );
-       assert ( strlen ( encoded ) == base16_encoded_len ( len ) );
+       return used;
 }
 
 /**
- * Decode hexadecimal string
+ * Decode hexadecimal string (with optional byte separator character)
  *
- * @v encoded          Encoded string
  * @v separator                Byte separator character, or 0 for no separator
+ * @v encoded          Encoded string
  * @v data             Buffer
  * @v len              Length of buffer
  * @ret len            Length of data, or negative error
  */
-int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
+int hex_decode ( char separator, const char *encoded, void *data, size_t len ) {
        uint8_t *out = data;
        unsigned int count = 0;
        unsigned int sixteens;
@@ -110,31 +105,3 @@ int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
        }
        return count;
 }
-
-/**
- * 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 ) {
-       int len;
-
-       len = hex_decode ( encoded, 0, raw, -1UL );
-       if ( len < 0 )
-               return len;
-
-       DBG ( "Base16-decoded \"%s\" to:\n", encoded );
-       DBG_HDA ( 0, raw, len );
-       assert ( len <= ( int ) base16_decoded_max_len ( encoded ) );
-
-       return len;
-}
index bd242f6b6fc5ae4ae208b82dc008b3656509350e..be48ea7a7d85d68db97627ea329d831516f9b990 100644 (file)
@@ -2005,32 +2005,6 @@ const struct setting_type setting_type_uint16 __setting_type =
 const struct setting_type setting_type_uint32 __setting_type =
        SETTING_TYPE_UINT ( SETTING_TYPE_INT32 );
 
-/**
- * Format hex string setting value
- *
- * @v delimiter                Byte delimiter
- * @v raw              Raw setting value
- * @v raw_len          Length of raw setting value
- * @v buf              Buffer to contain formatted value
- * @v len              Length of buffer
- * @ret len            Length of formatted value, or negative error
- */
-static int format_hex_setting ( const char *delimiter, const void *raw,
-                               size_t raw_len, char *buf, size_t len ) {
-       const uint8_t *bytes = raw;
-       int used = 0;
-       unsigned int i;
-
-       if ( len )
-               buf[0] = 0; /* Ensure that a terminating NUL exists */
-       for ( i = 0 ; i < raw_len ; i++ ) {
-               used += ssnprintf ( ( buf + used ), ( len - used ),
-                                   "%s%02x", ( used ? delimiter : "" ),
-                                   bytes[i] );
-       }
-       return used;
-}
-
 /**
  * Parse hex string setting value (using colon delimiter)
  *
@@ -2043,7 +2017,7 @@ static int format_hex_setting ( const char *delimiter, const void *raw,
  */
 static int parse_hex_setting ( const struct setting_type *type __unused,
                               const char *value, void *buf, size_t len ) {
-       return hex_decode ( value, ':', buf, len );
+       return hex_decode ( ':', value, buf, len );
 }
 
 /**
@@ -2059,7 +2033,7 @@ static int parse_hex_setting ( const struct setting_type *type __unused,
 static int format_hex_colon_setting ( const struct setting_type *type __unused,
                                      const void *raw, size_t raw_len,
                                      char *buf, size_t len ) {
-       return format_hex_setting ( ":", raw, raw_len, buf, len );
+       return hex_encode ( ':', raw, raw_len, buf, len );
 }
 
 /**
@@ -2075,7 +2049,7 @@ static int format_hex_colon_setting ( const struct setting_type *type __unused,
 static int parse_hex_hyphen_setting ( const struct setting_type *type __unused,
                                      const char *value, void *buf,
                                      size_t len ) {
-       return hex_decode ( value, '-', buf, len );
+       return hex_decode ( '-', value, buf, len );
 }
 
 /**
@@ -2091,7 +2065,7 @@ static int parse_hex_hyphen_setting ( const struct setting_type *type __unused,
 static int format_hex_hyphen_setting ( const struct setting_type *type __unused,
                                       const void *raw, size_t raw_len,
                                       char *buf, size_t len ) {
-       return format_hex_setting ( "-", raw, raw_len, buf, len );
+       return hex_encode ( '-', raw, raw_len, buf, len );
 }
 
 /**
@@ -2106,7 +2080,7 @@ static int format_hex_hyphen_setting ( const struct setting_type *type __unused,
  */
 static int parse_hex_raw_setting ( const struct setting_type *type __unused,
                                   const char *value, void *buf, size_t len ) {
-       return hex_decode ( value, 0, buf, len );
+       return hex_decode ( 0, value, buf, len );
 }
 
 /**
@@ -2122,7 +2096,7 @@ static int parse_hex_raw_setting ( const struct setting_type *type __unused,
 static int format_hex_raw_setting ( const struct setting_type *type __unused,
                                    const void *raw, size_t raw_len,
                                    char *buf, size_t len ) {
-       return format_hex_setting ( "", raw, raw_len, buf, len );
+       return hex_encode ( 0, raw, raw_len, buf, len );
 }
 
 /** A hex-string setting (colon-delimited) */
index 49a1bce771faf6b47410cda3f82ee51ec36aaf1f..00eb226e0864dc8f313adfafe2a930e99f364023 100644 (file)
@@ -143,7 +143,8 @@ const char * x509_name ( struct x509_certificate *cert ) {
        } else {
                /* Certificate has no commonName: use SHA-1 fingerprint */
                x509_fingerprint ( cert, digest, fingerprint );
-               base16_encode ( fingerprint, sizeof ( fingerprint ), buf );
+               base16_encode ( fingerprint, sizeof ( fingerprint ),
+                               buf, sizeof ( buf ) );
        }
        return buf;
 }
index 33f80e02ba8213a3599178b65a12ba5b8051c415..8c84ea9e910cdef0a5b663c51dca1826962131e1 100644 (file)
@@ -105,7 +105,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
                return -EINVAL;
 
        /* Decode MAC address */
-       len = base16_decode ( buf, hw_addr );
+       len = base16_decode ( buf, hw_addr, ETH_ALEN );
        if ( len < 0 ) {
                rc = len;
                return rc;
index 6a1e4fc1f4bdff30feb8115e93dd51b392ad6fe3..2f4bbf2a0df6aa85e150ff90422fe286d490f547 100644 (file)
@@ -139,7 +139,7 @@ static int netfront_read_mac ( struct netfront_nic *netfront, void *hw_addr ) {
                xendev->key, mac );
 
        /* Decode MAC address */
-       len = hex_decode ( mac, ':', hw_addr, ETH_ALEN );
+       len = hex_decode ( ':', mac, hw_addr, ETH_ALEN );
        if ( len < 0 ) {
                rc = len;
                DBGC ( netfront, "NETFRONT %s could not decode MAC address "
index fb20c9d5a8c0993376ad7a699e3dcb48007623c2..8c44da17eb4551355c72986d94e8f12ba43eca0d 100644 (file)
@@ -32,9 +32,36 @@ 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 hex_decode ( const char *string, char separator, void *data,
+extern size_t hex_encode ( char separator, const void *raw, size_t raw_len,
+                          char *data, size_t len );
+extern int hex_decode ( char separator, const char *encoded, void *data,
                        size_t len );
-extern int base16_decode ( const char *encoded, uint8_t *raw );
+
+/**
+ * Base16-encode data
+ *
+ * @v raw              Raw data
+ * @v raw_len          Length of raw data
+ * @v data             Buffer
+ * @v len              Length of buffer
+ * @ret len            Encoded length
+ */
+static inline __attribute__ (( always_inline )) size_t
+base16_encode ( const void *raw, size_t raw_len, char *data, size_t len ) {
+       return hex_encode ( 0, raw, raw_len, data, len );
+}
+
+/**
+ * Base16-decode data
+ *
+ * @v encoded          Encoded string
+ * @v data             Buffer
+ * @v len              Length of buffer
+ * @ret len            Length of data, or negative error
+ */
+static inline __attribute__ (( always_inline )) int
+base16_decode ( const char *encoded, void *data, size_t len ) {
+       return hex_decode ( 0, encoded, data, len );
+}
 
 #endif /* _IPXE_BASE16_H */
index e426c795e0a5dd79698e537b464f946ae8b4be5f..4738039510cf8721d00f79d874aea2dd0e827872 100644 (file)
@@ -330,7 +330,7 @@ const char * efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) {
                max_len = ( ( sizeof ( text ) - 1 /* NUL */ ) / 2 /* "xx" */ );
                if ( len > max_len )
                        len = max_len;
-               base16_encode ( start, len, text );
+               base16_encode ( start, len, text, sizeof ( text ) );
                return text;
        }
 
index 7b2b2b4ea27e68b0354e5ffa2bacc0c0013fbc17..3700184c0317bdc52e8a15bc619bfd96a2f44ba6 100644 (file)
@@ -291,7 +291,7 @@ static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
                return -EINVAL_BYTE_STRING_LEN;
 
        /* Parse byte string */
-       decoded_size = base16_decode ( rp_comp, bytes );
+       decoded_size = base16_decode ( rp_comp, bytes, size );
        if ( decoded_size < 0 )
                return decoded_size;
 
index 10342207944c22f8fa683789dbcc9ea7e3ea1369..6ea26b3d1c9f09ea3b99ecd9c2a35aa9cbc0d8fe 100644 (file)
@@ -63,7 +63,7 @@ peerdist_info_hash_ntoa ( const struct peerdist_info *info, const void *hash ) {
        assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );
 
        /* Transcribe hash value */
-       base16_encode ( hash, digestsize, buf );
+       base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
        return buf;
 }
 
index 42a0f90e99f6dbcd2e177348b1e5d9d79c8c0030..d94ab5f0e8c90f5692fd09d4c7ddb9a850dddf11 100644 (file)
@@ -1122,12 +1122,14 @@ static void http_digest_update ( struct md5_context *ctx, const char *string ) {
  *
  * @v ctx              Digest context
  * @v out              Buffer for digest output
+ * @v len              Buffer length
  */
-static void http_digest_final ( struct md5_context *ctx, char *out ) {
+static void http_digest_final ( struct md5_context *ctx, char *out,
+                               size_t len ) {
        uint8_t digest[MD5_DIGEST_SIZE];
 
        digest_final ( &md5_algorithm, ctx, digest );
-       base16_encode ( digest, sizeof ( digest ), out );
+       base16_encode ( digest, sizeof ( digest ), out, len );
 }
 
 /**
@@ -1172,20 +1174,20 @@ static char * http_digest_auth ( struct http_request *http,
        http_digest_update ( &ctx, user );
        http_digest_update ( &ctx, realm );
        http_digest_update ( &ctx, password );
-       http_digest_final ( &ctx, ha1 );
+       http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
        if ( md5sess ) {
                http_digest_init ( &ctx );
                http_digest_update ( &ctx, ha1 );
                http_digest_update ( &ctx, nonce );
                http_digest_update ( &ctx, cnonce );
-               http_digest_final ( &ctx, ha1 );
+               http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
        }
 
        /* Generate HA2 */
        http_digest_init ( &ctx );
        http_digest_update ( &ctx, method );
        http_digest_update ( &ctx, uri );
-       http_digest_final ( &ctx, ha2 );
+       http_digest_final ( &ctx, ha2, sizeof ( ha2 ) );
 
        /* Generate response */
        http_digest_init ( &ctx );
@@ -1197,7 +1199,7 @@ static char * http_digest_auth ( struct http_request *http,
                http_digest_update ( &ctx, "auth" /* qop */ );
        }
        http_digest_update ( &ctx, ha2 );
-       http_digest_final ( &ctx, response );
+       http_digest_final ( &ctx, response, sizeof ( response ) );
 
        /* Generate the authorisation string */
        len = asprintf ( &auth, "Authorization: Digest username=\"%s\", "
index 2e420d9ace108ef945f5cdab4bf43e582290eccb..e553b214845c4707e9e2b8069a3579318e75a1fa 100644 (file)
@@ -709,7 +709,7 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
                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 );
+                               buf, sizeof ( buf ) );
                used += ssnprintf ( data + used, len - used,
                                    "CHAP_N=%s%cCHAP_R=0x%s%c",
                                    iscsi->initiator_username, 0, buf, 0 );
@@ -719,7 +719,7 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
                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 );
+                               buf, sizeof ( buf ) );
                used += ssnprintf ( data + used, len - used,
                                    "CHAP_I=%d%cCHAP_C=0x%s%c",
                                    iscsi->chap_challenge[0], 0, buf, 0 );
@@ -833,15 +833,17 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
  *
  * @v encoded          Encoded large binary value
  * @v raw              Raw data
+ * @v len              Length of data buffer
  * @ret len            Length of raw data, or negative error
  */
-static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw ) {
+static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw,
+                                      size_t len ) {
 
        /* Check for initial '0x' or '0b' and decode as appropriate */
        if ( *(encoded++) == '0' ) {
                switch ( tolower ( *(encoded++) ) ) {
                case 'x' :
-                       return base16_decode ( encoded, raw );
+                       return base16_decode ( encoded, raw, len );
                case 'b' :
                        return base64_decode ( encoded, raw );
                }
@@ -980,7 +982,7 @@ static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
        int rc;
 
        /* Process challenge */
-       len = iscsi_large_binary_decode ( value, buf );
+       len = iscsi_large_binary_decode ( value, buf, sizeof ( buf ) );
        if ( len < 0 ) {
                rc = len;
                DBGC ( iscsi, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
@@ -1065,7 +1067,7 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
        chap_respond ( &iscsi->chap );
 
        /* Process response */
-       len = iscsi_large_binary_decode ( value, buf );
+       len = iscsi_large_binary_decode ( value, buf, sizeof ( buf ) );
        if ( len < 0 ) {
                rc = len;
                DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",
index 04bf4e6c9cad699496836a90a6985a37f6f3da0a..46884aef738536a819717ab5e2b377cff5ed74f5 100644 (file)
@@ -77,30 +77,42 @@ BASE16 ( random_test,
  * Report a base16 encoding test result
  *
  * @v test             Base16 test
+ * @v file             Test code file
+ * @v line             Test code line
  */
-#define base16_encode_ok( test ) do {                                  \
-       size_t len = base16_encoded_len ( (test)->len );                \
-       char buf[ len + 1 /* NUL */ ];                                  \
-       ok ( len == strlen ( (test)->encoded ) );                       \
-       base16_encode ( (test)->data, (test)->len, buf );               \
-       ok ( strcmp ( (test)->encoded, buf ) == 0 );                    \
-       } while ( 0 )
+static void base16_encode_okx ( struct base16_test *test, const char *file,
+                               unsigned int line ) {
+       size_t len = base16_encoded_len ( test->len );
+       char buf[ len + 1 /* NUL */ ];
+       size_t check_len;
+
+       okx ( len == strlen ( test->encoded ), file, line );
+       check_len = base16_encode ( test->data, test->len, buf, sizeof ( buf ));
+       okx ( check_len == len, file, line );
+       okx ( strcmp ( test->encoded, buf ) == 0, file, line );
+}
+#define base16_encode_ok( test ) base16_encode_okx ( test, __FILE__, __LINE__ )
 
 /**
  * Report a base16 decoding test result
  *
  * @v test             Base16 test
+ * @v file             Test code file
+ * @v line             Test code line
  */
-#define base16_decode_ok( test ) do {                                  \
-       size_t max_len = base16_decoded_max_len ( (test)->encoded );    \
-       uint8_t buf[max_len];                                           \
-       int len;                                                        \
-       len = base16_decode ( (test)->encoded, buf );                   \
-       ok ( len >= 0 );                                                \
-       ok ( ( size_t ) len <= max_len );                               \
-       ok ( ( size_t ) len == (test)->len );                           \
-       ok ( memcmp ( (test)->data, buf, len ) == 0 );                  \
-       } while ( 0 )
+static void base16_decode_okx ( struct base16_test *test, const char *file,
+                               unsigned int line ) {
+       size_t max_len = base16_decoded_max_len ( test->encoded );
+       uint8_t buf[max_len];
+       int len;
+
+       len = base16_decode ( test->encoded, buf, sizeof ( buf ) );
+       okx ( len >= 0, file, line );
+       okx ( ( size_t ) len <= max_len, file, line );
+       okx ( ( size_t ) len == test->len, file, line );
+       okx ( memcmp ( test->data, buf, len ) == 0, file, line );
+}
+#define base16_decode_ok( test ) base16_decode_okx ( test, __FILE__, __LINE__ )
 
 /**
  * Perform Base16 self-tests