Browse Source

[base16] Add buffer size parameter to base16_encode() and base16_decode()

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>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
9aa8090d06

+ 24
- 57
src/core/base16.c View File

@@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 28
 #include <errno.h>
29 29
 #include <assert.h>
30 30
 #include <ipxe/string.h>
31
+#include <ipxe/vsprintf.h>
31 32
 #include <ipxe/base16.h>
32 33
 
33 34
 /** @file
@@ -37,48 +38,42 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
37 38
  */
38 39
 
39 40
 /**
40
- * Base16-encode data
41
+ * Encode hexadecimal string (with optional byte separator character)
41 42
  *
43
+ * @v separator		Byte separator character, or 0 for no separator
42 44
  * @v raw		Raw data
43
- * @v len		Length of raw data
44
- * @v encoded		Buffer for encoded string
45
- *
46
- * The buffer must be the correct length for the encoded string.  Use
47
- * something like
48
- *
49
- *     char buf[ base16_encoded_len ( len ) + 1 ];
50
- *
51
- * (the +1 is for the terminating NUL) to provide a buffer of the
52
- * correct size.
45
+ * @v raw_len		Length of raw data
46
+ * @v data		Buffer
47
+ * @v len		Length of buffer
48
+ * @ret len		Encoded length
53 49
  */
54
-void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
55
-	const uint8_t *raw_bytes = raw;
56
-	char *encoded_bytes = encoded;
57
-	size_t remaining = len;
58
-
59
-	/* Encode each byte */
60
-	for ( ; remaining-- ; encoded_bytes += 2 ) {
61
-		sprintf ( encoded_bytes, "%02x", *(raw_bytes++) );
50
+size_t hex_encode ( char separator, const void *raw, size_t raw_len,
51
+		    char *data, size_t len ) {
52
+	const uint8_t *bytes = raw;
53
+	const char delimiter[2] = { separator, '\0' };
54
+	size_t used = 0;
55
+	unsigned int i;
56
+
57
+	if ( len )
58
+		data[0] = 0; /* Ensure that a terminating NUL exists */
59
+	for ( i = 0 ; i < raw_len ; i++ ) {
60
+		used += ssnprintf ( ( data + used ), ( len - used ),
61
+				    "%s%02x", ( used ? delimiter : "" ),
62
+				    bytes[i] );
62 63
 	}
63
-
64
-	/* Ensure terminating NUL exists even if length was zero */
65
-	*encoded_bytes = '\0';
66
-
67
-	DBG ( "Base16-encoded to \"%s\":\n", encoded );
68
-	DBG_HDA ( 0, raw, len );
69
-	assert ( strlen ( encoded ) == base16_encoded_len ( len ) );
64
+	return used;
70 65
 }
71 66
 
72 67
 /**
73
- * Decode hexadecimal string
68
+ * Decode hexadecimal string (with optional byte separator character)
74 69
  *
75
- * @v encoded		Encoded string
76 70
  * @v separator		Byte separator character, or 0 for no separator
71
+ * @v encoded		Encoded string
77 72
  * @v data		Buffer
78 73
  * @v len		Length of buffer
79 74
  * @ret len		Length of data, or negative error
80 75
  */
81
-int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
76
+int hex_decode ( char separator, const char *encoded, void *data, size_t len ) {
82 77
 	uint8_t *out = data;
83 78
 	unsigned int count = 0;
84 79
 	unsigned int sixteens;
@@ -110,31 +105,3 @@ int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
110 105
 	}
111 106
 	return count;
112 107
 }
113
-
114
-/**
115
- * Base16-decode data
116
- *
117
- * @v encoded		Encoded string
118
- * @v raw		Raw data
119
- * @ret len		Length of raw data, or negative error
120
- *
121
- * The buffer must be large enough to contain the decoded data.  Use
122
- * something like
123
- *
124
- *     char buf[ base16_decoded_max_len ( encoded ) ];
125
- *
126
- * to provide a buffer of the correct size.
127
- */
128
-int base16_decode ( const char *encoded, uint8_t *raw ) {
129
-	int len;
130
-
131
-	len = hex_decode ( encoded, 0, raw, -1UL );
132
-	if ( len < 0 )
133
-		return len;
134
-
135
-	DBG ( "Base16-decoded \"%s\" to:\n", encoded );
136
-	DBG_HDA ( 0, raw, len );
137
-	assert ( len <= ( int ) base16_decoded_max_len ( encoded ) );
138
-
139
-	return len;
140
-}

+ 6
- 32
src/core/settings.c View File

@@ -2005,32 +2005,6 @@ const struct setting_type setting_type_uint16 __setting_type =
2005 2005
 const struct setting_type setting_type_uint32 __setting_type =
2006 2006
 	SETTING_TYPE_UINT ( SETTING_TYPE_INT32 );
2007 2007
 
2008
-/**
2009
- * Format hex string setting value
2010
- *
2011
- * @v delimiter		Byte delimiter
2012
- * @v raw		Raw setting value
2013
- * @v raw_len		Length of raw setting value
2014
- * @v buf		Buffer to contain formatted value
2015
- * @v len		Length of buffer
2016
- * @ret len		Length of formatted value, or negative error
2017
- */
2018
-static int format_hex_setting ( const char *delimiter, const void *raw,
2019
-				size_t raw_len, char *buf, size_t len ) {
2020
-	const uint8_t *bytes = raw;
2021
-	int used = 0;
2022
-	unsigned int i;
2023
-
2024
-	if ( len )
2025
-		buf[0] = 0; /* Ensure that a terminating NUL exists */
2026
-	for ( i = 0 ; i < raw_len ; i++ ) {
2027
-		used += ssnprintf ( ( buf + used ), ( len - used ),
2028
-				    "%s%02x", ( used ? delimiter : "" ),
2029
-				    bytes[i] );
2030
-	}
2031
-	return used;
2032
-}
2033
-
2034 2008
 /**
2035 2009
  * Parse hex string setting value (using colon delimiter)
2036 2010
  *
@@ -2043,7 +2017,7 @@ static int format_hex_setting ( const char *delimiter, const void *raw,
2043 2017
  */
2044 2018
 static int parse_hex_setting ( const struct setting_type *type __unused,
2045 2019
 			       const char *value, void *buf, size_t len ) {
2046
-	return hex_decode ( value, ':', buf, len );
2020
+	return hex_decode ( ':', value, buf, len );
2047 2021
 }
2048 2022
 
2049 2023
 /**
@@ -2059,7 +2033,7 @@ static int parse_hex_setting ( const struct setting_type *type __unused,
2059 2033
 static int format_hex_colon_setting ( const struct setting_type *type __unused,
2060 2034
 				      const void *raw, size_t raw_len,
2061 2035
 				      char *buf, size_t len ) {
2062
-	return format_hex_setting ( ":", raw, raw_len, buf, len );
2036
+	return hex_encode ( ':', raw, raw_len, buf, len );
2063 2037
 }
2064 2038
 
2065 2039
 /**
@@ -2075,7 +2049,7 @@ static int format_hex_colon_setting ( const struct setting_type *type __unused,
2075 2049
 static int parse_hex_hyphen_setting ( const struct setting_type *type __unused,
2076 2050
 				      const char *value, void *buf,
2077 2051
 				      size_t len ) {
2078
-	return hex_decode ( value, '-', buf, len );
2052
+	return hex_decode ( '-', value, buf, len );
2079 2053
 }
2080 2054
 
2081 2055
 /**
@@ -2091,7 +2065,7 @@ static int parse_hex_hyphen_setting ( const struct setting_type *type __unused,
2091 2065
 static int format_hex_hyphen_setting ( const struct setting_type *type __unused,
2092 2066
 				       const void *raw, size_t raw_len,
2093 2067
 				       char *buf, size_t len ) {
2094
-	return format_hex_setting ( "-", raw, raw_len, buf, len );
2068
+	return hex_encode ( '-', raw, raw_len, buf, len );
2095 2069
 }
2096 2070
 
2097 2071
 /**
@@ -2106,7 +2080,7 @@ static int format_hex_hyphen_setting ( const struct setting_type *type __unused,
2106 2080
  */
2107 2081
 static int parse_hex_raw_setting ( const struct setting_type *type __unused,
2108 2082
 				   const char *value, void *buf, size_t len ) {
2109
-	return hex_decode ( value, 0, buf, len );
2083
+	return hex_decode ( 0, value, buf, len );
2110 2084
 }
2111 2085
 
2112 2086
 /**
@@ -2122,7 +2096,7 @@ static int parse_hex_raw_setting ( const struct setting_type *type __unused,
2122 2096
 static int format_hex_raw_setting ( const struct setting_type *type __unused,
2123 2097
 				    const void *raw, size_t raw_len,
2124 2098
 				    char *buf, size_t len ) {
2125
-	return format_hex_setting ( "", raw, raw_len, buf, len );
2099
+	return hex_encode ( 0, raw, raw_len, buf, len );
2126 2100
 }
2127 2101
 
2128 2102
 /** A hex-string setting (colon-delimited) */

+ 2
- 1
src/crypto/x509.c View File

@@ -143,7 +143,8 @@ const char * x509_name ( struct x509_certificate *cert ) {
143 143
 	} else {
144 144
 		/* Certificate has no commonName: use SHA-1 fingerprint */
145 145
 		x509_fingerprint ( cert, digest, fingerprint );
146
-		base16_encode ( fingerprint, sizeof ( fingerprint ), buf );
146
+		base16_encode ( fingerprint, sizeof ( fingerprint ),
147
+				buf, sizeof ( buf ) );
147 148
 	}
148 149
 	return buf;
149 150
 }

+ 1
- 1
src/drivers/net/ecm.c View File

@@ -105,7 +105,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
105 105
 		return -EINVAL;
106 106
 
107 107
 	/* Decode MAC address */
108
-	len = base16_decode ( buf, hw_addr );
108
+	len = base16_decode ( buf, hw_addr, ETH_ALEN );
109 109
 	if ( len < 0 ) {
110 110
 		rc = len;
111 111
 		return rc;

+ 1
- 1
src/drivers/net/netfront.c View File

@@ -139,7 +139,7 @@ static int netfront_read_mac ( struct netfront_nic *netfront, void *hw_addr ) {
139 139
 		xendev->key, mac );
140 140
 
141 141
 	/* Decode MAC address */
142
-	len = hex_decode ( mac, ':', hw_addr, ETH_ALEN );
142
+	len = hex_decode ( ':', mac, hw_addr, ETH_ALEN );
143 143
 	if ( len < 0 ) {
144 144
 		rc = len;
145 145
 		DBGC ( netfront, "NETFRONT %s could not decode MAC address "

+ 30
- 3
src/include/ipxe/base16.h View File

@@ -32,9 +32,36 @@ static inline size_t base16_decoded_max_len ( const char *encoded ) {
32 32
 	return ( ( strlen ( encoded ) + 1 ) / 2 );
33 33
 }
34 34
 
35
-extern void base16_encode ( const uint8_t *raw, size_t len, char *encoded );
36
-extern int hex_decode ( const char *string, char separator, void *data,
35
+extern size_t hex_encode ( char separator, const void *raw, size_t raw_len,
36
+			   char *data, size_t len );
37
+extern int hex_decode ( char separator, const char *encoded, void *data,
37 38
 			size_t len );
38
-extern int base16_decode ( const char *encoded, uint8_t *raw );
39
+
40
+/**
41
+ * Base16-encode data
42
+ *
43
+ * @v raw		Raw data
44
+ * @v raw_len		Length of raw data
45
+ * @v data		Buffer
46
+ * @v len		Length of buffer
47
+ * @ret len		Encoded length
48
+ */
49
+static inline __attribute__ (( always_inline )) size_t
50
+base16_encode ( const void *raw, size_t raw_len, char *data, size_t len ) {
51
+	return hex_encode ( 0, raw, raw_len, data, len );
52
+}
53
+
54
+/**
55
+ * Base16-decode data
56
+ *
57
+ * @v encoded		Encoded string
58
+ * @v data		Buffer
59
+ * @v len		Length of buffer
60
+ * @ret len		Length of data, or negative error
61
+ */
62
+static inline __attribute__ (( always_inline )) int
63
+base16_decode ( const char *encoded, void *data, size_t len ) {
64
+	return hex_decode ( 0, encoded, data, len );
65
+}
39 66
 
40 67
 #endif /* _IPXE_BASE16_H */

+ 1
- 1
src/interface/efi/efi_debug.c View File

@@ -330,7 +330,7 @@ const char * efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) {
330 330
 		max_len = ( ( sizeof ( text ) - 1 /* NUL */ ) / 2 /* "xx" */ );
331 331
 		if ( len > max_len )
332 332
 			len = max_len;
333
-		base16_encode ( start, len, text );
333
+		base16_encode ( start, len, text, sizeof ( text ) );
334 334
 		return text;
335 335
 	}
336 336
 

+ 1
- 1
src/net/infiniband/ib_srp.c View File

@@ -291,7 +291,7 @@ static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
291 291
 		return -EINVAL_BYTE_STRING_LEN;
292 292
 
293 293
 	/* Parse byte string */
294
-	decoded_size = base16_decode ( rp_comp, bytes );
294
+	decoded_size = base16_decode ( rp_comp, bytes, size );
295 295
 	if ( decoded_size < 0 )
296 296
 		return decoded_size;
297 297
 

+ 1
- 1
src/net/pccrc.c View File

@@ -63,7 +63,7 @@ peerdist_info_hash_ntoa ( const struct peerdist_info *info, const void *hash ) {
63 63
 	assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );
64 64
 
65 65
 	/* Transcribe hash value */
66
-	base16_encode ( hash, digestsize, buf );
66
+	base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
67 67
 	return buf;
68 68
 }
69 69
 

+ 8
- 6
src/net/tcp/httpcore.c View File

@@ -1122,12 +1122,14 @@ static void http_digest_update ( struct md5_context *ctx, const char *string ) {
1122 1122
  *
1123 1123
  * @v ctx		Digest context
1124 1124
  * @v out		Buffer for digest output
1125
+ * @v len		Buffer length
1125 1126
  */
1126
-static void http_digest_final ( struct md5_context *ctx, char *out ) {
1127
+static void http_digest_final ( struct md5_context *ctx, char *out,
1128
+				size_t len ) {
1127 1129
 	uint8_t digest[MD5_DIGEST_SIZE];
1128 1130
 
1129 1131
 	digest_final ( &md5_algorithm, ctx, digest );
1130
-	base16_encode ( digest, sizeof ( digest ), out );
1132
+	base16_encode ( digest, sizeof ( digest ), out, len );
1131 1133
 }
1132 1134
 
1133 1135
 /**
@@ -1172,20 +1174,20 @@ static char * http_digest_auth ( struct http_request *http,
1172 1174
 	http_digest_update ( &ctx, user );
1173 1175
 	http_digest_update ( &ctx, realm );
1174 1176
 	http_digest_update ( &ctx, password );
1175
-	http_digest_final ( &ctx, ha1 );
1177
+	http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
1176 1178
 	if ( md5sess ) {
1177 1179
 		http_digest_init ( &ctx );
1178 1180
 		http_digest_update ( &ctx, ha1 );
1179 1181
 		http_digest_update ( &ctx, nonce );
1180 1182
 		http_digest_update ( &ctx, cnonce );
1181
-		http_digest_final ( &ctx, ha1 );
1183
+		http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
1182 1184
 	}
1183 1185
 
1184 1186
 	/* Generate HA2 */
1185 1187
 	http_digest_init ( &ctx );
1186 1188
 	http_digest_update ( &ctx, method );
1187 1189
 	http_digest_update ( &ctx, uri );
1188
-	http_digest_final ( &ctx, ha2 );
1190
+	http_digest_final ( &ctx, ha2, sizeof ( ha2 ) );
1189 1191
 
1190 1192
 	/* Generate response */
1191 1193
 	http_digest_init ( &ctx );
@@ -1197,7 +1199,7 @@ static char * http_digest_auth ( struct http_request *http,
1197 1199
 		http_digest_update ( &ctx, "auth" /* qop */ );
1198 1200
 	}
1199 1201
 	http_digest_update ( &ctx, ha2 );
1200
-	http_digest_final ( &ctx, response );
1202
+	http_digest_final ( &ctx, response, sizeof ( response ) );
1201 1203
 
1202 1204
 	/* Generate the authorisation string */
1203 1205
 	len = asprintf ( &auth, "Authorization: Digest username=\"%s\", "

+ 8
- 6
src/net/tcp/iscsi.c View File

@@ -709,7 +709,7 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
709 709
 		char buf[ base16_encoded_len ( iscsi->chap.response_len ) + 1 ];
710 710
 		assert ( iscsi->initiator_username != NULL );
711 711
 		base16_encode ( iscsi->chap.response, iscsi->chap.response_len,
712
-				buf );
712
+				buf, sizeof ( buf ) );
713 713
 		used += ssnprintf ( data + used, len - used,
714 714
 				    "CHAP_N=%s%cCHAP_R=0x%s%c",
715 715
 				    iscsi->initiator_username, 0, buf, 0 );
@@ -719,7 +719,7 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
719 719
 		size_t challenge_len = ( sizeof ( iscsi->chap_challenge ) - 1 );
720 720
 		char buf[ base16_encoded_len ( challenge_len ) + 1 ];
721 721
 		base16_encode ( ( iscsi->chap_challenge + 1 ), challenge_len,
722
-				buf );
722
+				buf, sizeof ( buf ) );
723 723
 		used += ssnprintf ( data + used, len - used,
724 724
 				    "CHAP_I=%d%cCHAP_C=0x%s%c",
725 725
 				    iscsi->chap_challenge[0], 0, buf, 0 );
@@ -833,15 +833,17 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
833 833
  *
834 834
  * @v encoded		Encoded large binary value
835 835
  * @v raw		Raw data
836
+ * @v len		Length of data buffer
836 837
  * @ret len		Length of raw data, or negative error
837 838
  */
838
-static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw ) {
839
+static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw,
840
+				       size_t len ) {
839 841
 
840 842
 	/* Check for initial '0x' or '0b' and decode as appropriate */
841 843
 	if ( *(encoded++) == '0' ) {
842 844
 		switch ( tolower ( *(encoded++) ) ) {
843 845
 		case 'x' :
844
-			return base16_decode ( encoded, raw );
846
+			return base16_decode ( encoded, raw, len );
845 847
 		case 'b' :
846 848
 			return base64_decode ( encoded, raw );
847 849
 		}
@@ -980,7 +982,7 @@ static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
980 982
 	int rc;
981 983
 
982 984
 	/* Process challenge */
983
-	len = iscsi_large_binary_decode ( value, buf );
985
+	len = iscsi_large_binary_decode ( value, buf, sizeof ( buf ) );
984 986
 	if ( len < 0 ) {
985 987
 		rc = len;
986 988
 		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,
1065 1067
 	chap_respond ( &iscsi->chap );
1066 1068
 
1067 1069
 	/* Process response */
1068
-	len = iscsi_large_binary_decode ( value, buf );
1070
+	len = iscsi_large_binary_decode ( value, buf, sizeof ( buf ) );
1069 1071
 	if ( len < 0 ) {
1070 1072
 		rc = len;
1071 1073
 		DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",

+ 29
- 17
src/tests/base16_test.c View File

@@ -77,30 +77,42 @@ BASE16 ( random_test,
77 77
  * Report a base16 encoding test result
78 78
  *
79 79
  * @v test		Base16 test
80
+ * @v file		Test code file
81
+ * @v line		Test code line
80 82
  */
81
-#define base16_encode_ok( test ) do {					\
82
-	size_t len = base16_encoded_len ( (test)->len );		\
83
-	char buf[ len + 1 /* NUL */ ];					\
84
-	ok ( len == strlen ( (test)->encoded ) );			\
85
-	base16_encode ( (test)->data, (test)->len, buf );		\
86
-	ok ( strcmp ( (test)->encoded, buf ) == 0 );			\
87
-	} while ( 0 )
83
+static void base16_encode_okx ( struct base16_test *test, const char *file,
84
+				unsigned int line ) {
85
+	size_t len = base16_encoded_len ( test->len );
86
+	char buf[ len + 1 /* NUL */ ];
87
+	size_t check_len;
88
+
89
+	okx ( len == strlen ( test->encoded ), file, line );
90
+	check_len = base16_encode ( test->data, test->len, buf, sizeof ( buf ));
91
+	okx ( check_len == len, file, line );
92
+	okx ( strcmp ( test->encoded, buf ) == 0, file, line );
93
+}
94
+#define base16_encode_ok( test ) base16_encode_okx ( test, __FILE__, __LINE__ )
88 95
 
89 96
 /**
90 97
  * Report a base16 decoding test result
91 98
  *
92 99
  * @v test		Base16 test
100
+ * @v file		Test code file
101
+ * @v line		Test code line
93 102
  */
94
-#define base16_decode_ok( test ) do {					\
95
-	size_t max_len = base16_decoded_max_len ( (test)->encoded );	\
96
-	uint8_t buf[max_len];						\
97
-	int len;							\
98
-	len = base16_decode ( (test)->encoded, buf );			\
99
-	ok ( len >= 0 );						\
100
-	ok ( ( size_t ) len <= max_len );				\
101
-	ok ( ( size_t ) len == (test)->len );				\
102
-	ok ( memcmp ( (test)->data, buf, len ) == 0 );			\
103
-	} while ( 0 )
103
+static void base16_decode_okx ( struct base16_test *test, const char *file,
104
+				unsigned int line ) {
105
+	size_t max_len = base16_decoded_max_len ( test->encoded );
106
+	uint8_t buf[max_len];
107
+	int len;
108
+
109
+	len = base16_decode ( test->encoded, buf, sizeof ( buf ) );
110
+	okx ( len >= 0, file, line );
111
+	okx ( ( size_t ) len <= max_len, file, line );
112
+	okx ( ( size_t ) len == test->len, file, line );
113
+	okx ( memcmp ( test->data, buf, len ) == 0, file, line );
114
+}
115
+#define base16_decode_ok( test ) base16_decode_okx ( test, __FILE__, __LINE__ )
104 116
 
105 117
 /**
106 118
  * Perform Base16 self-tests

Loading…
Cancel
Save