cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
int_string.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Internal String API *
4 * Copyright Peter Gutmann 1992-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10 #else
11  #include "crypt.h"
12 #endif /* Compiler-specific includes */
13 
14 /****************************************************************************
15 * *
16 * General-purpose String Functions *
17 * *
18 ****************************************************************************/
19 
20 /* Perform various string-processing operations */
21 
23 int strFindCh( IN_BUFFER( strLen ) const char *str,
25  IN_CHAR const int findCh )
26  {
27  int i;
28 
29  assert( isReadPtr( str, strLen ) );
30 
31  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
32  REQUIRES( findCh >= 0 && findCh <= 0x7F );
33 
34  for( i = 0; i < strLen; i++ )
35  {
36  if( str[ i ] == findCh )
37  return( i );
38  }
39 
40  return( -1 );
41  }
42 
44 int strFindStr( IN_BUFFER( strLen ) const char *str,
46  IN_BUFFER( findStrLen ) const char *findStr,
47  IN_LENGTH_SHORT const int findStrLen )
48  {
49  const int findCh = toUpper( findStr[ 0 ] );
50  int i;
51 
52  assert( isReadPtr( str, strLen ) );
53  assert( isReadPtr( findStr, findStrLen ) );
54 
55  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
56  REQUIRES( findStrLen > 0 && findStrLen < MAX_INTLENGTH_SHORT );
57  REQUIRES( findCh >= 0 && findCh <= 0x7F );
58 
59  for( i = 0; i <= strLen - findStrLen; i++ )
60  {
61  if( toUpper( str[ i ] ) == findCh && \
62  !strCompare( str + i, findStr, findStrLen ) )
63  return( i );
64  }
65 
66  return( -1 );
67  }
68 
70 int strSkipWhitespace( IN_BUFFER( strLen ) const char *str,
72  {
73  int i;
74 
75  assert( isReadPtr( str, strLen ) );
76 
77  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
78 
79  for( i = 0; i < strLen && ( str[ i ] == ' ' || str[ i ] == '\t' ); i++ );
80  return( ( i < strLen ) ? i : -1 );
81  }
82 
83 CHECK_RETVAL_STRINGOP( strLen ) STDC_NONNULL_ARG( ( 1 ) ) \
84 int strSkipNonWhitespace( IN_BUFFER( strLen ) const char *str,
85  IN_LENGTH_SHORT const int strLen )
86  {
87  int i;
88 
89  assert( isReadPtr( str, strLen ) );
90 
91  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
92 
93  /* This differs slightly from strSkipWhitespace() in that EOL is also
94  counted as whitespace so there's never an error condition unless
95  we don't find anything at all */
96  for( i = 0; i < strLen && str[ i ] != ' ' && str[ i ] != '\t'; i++ );
97  return( i > 0 ? i : -1 );
98  }
99 
100 CHECK_RETVAL_STRINGOP( strLen ) STDC_NONNULL_ARG( ( 1, 2 ) ) \
101 int strStripWhitespace( OUT_OPT_PTR const char **newStringPtr,
102  IN_BUFFER( strLen ) const char *string,
103  IN_LENGTH_SHORT const int strLen )
104  {
105  int startPos, endPos;
106 
107  assert( isReadPtr( newStringPtr, sizeof( char * ) ) );
108  assert( isReadPtr( string, strLen ) );
109 
110  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
111 
112  /* Clear return value */
113  *newStringPtr = NULL;
114 
115  /* Skip leading and trailing whitespace */
116  for( startPos = 0;
117  startPos < strLen && \
118  ( string[ startPos ] == ' ' || string[ startPos ] == '\t' );
119  startPos++ );
120  if( startPos >= strLen )
121  return( -1 );
122  *newStringPtr = string + startPos;
123  for( endPos = strLen;
124  endPos > startPos && \
125  ( string[ endPos - 1 ] == ' ' || string[ endPos - 1 ] == '\t' );
126  endPos-- );
127  ENSURES( endPos - startPos > 0 );
128  return( endPos - startPos );
129  }
130 
131 /****************************************************************************
132 * *
133 * Special-purpose String Functions *
134 * *
135 ****************************************************************************/
136 
137 /* Extract a substring from a string. This converts:
138 
139  string startOffset strLen
140  | | |
141  v v v
142  +-------------------+---------------+-------------------+
143  | Processed data | Whitespace | Remaining data |
144  +-------------------+---------------+-------------------+
145 
146  into:
147 
148  newStr length
149  | |
150  v v
151  +-------------------+
152  | Remaining data |
153  +-------------------+
154 
155  The order of the parameters is a bit unusual, normally we'd use
156  { str, strLen } but this makes things a bit confusing for the caller, for
157  whom it's more logical to group the parameters based on the overall
158  operation beingn performed, which to extract a substring beginning at
159  startOffset is { str, startOffset, strLen } */
160 
162 int strExtract( OUT_OPT_PTR const char **newStringPtr,
163  IN_BUFFER( strLen ) const char *string,
164  IN_LENGTH_SHORT const int startOffset,
165  IN_LENGTH_SHORT const int strLen )
166  {
167  const int newLen = strLen - startOffset;
168 
169  assert( isReadPtr( newStringPtr, sizeof( char * ) ) );
170  assert( isReadPtr( string, strLen ) );
171 
172  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
173  REQUIRES( startOffset >= 0 && startOffset <= strLen && \
174  startOffset < MAX_INTLENGTH_SHORT );
175  /* May be zero if we're extracting from the start of the
176  string; may be equal to strLen if it's the entire
177  remaining string */
178 
179  /* Clear return value */
180  *newStringPtr = NULL;
181 
182  if( newLen < 1 || newLen > strLen || newLen >= MAX_INTLENGTH_SHORT )
183  return( -1 );
184  return( strStripWhitespace( newStringPtr, string + startOffset, newLen ) );
185  }
186 
187 /* Parse a numeric string into an integer value. Safe conversion of a
188  numeric string gets a bit problematic because atoi() can't really
189  indicate an error except by returning 0, which is indistinguishable from
190  a zero numeric value. To handle this we have to perform the conversion
191  ourselves */
192 
194 int strGetNumeric( IN_BUFFER( strLen ) const char *str,
195  IN_LENGTH_SHORT const int strLen,
196  OUT_INT_Z int *numericValue,
197  IN_RANGE( 0, 100 ) const int minValue,
198  IN_RANGE( minValue, MAX_INTLENGTH ) const int maxValue )
199  {
200  int i, value;
201 
202  assert( isReadPtr( str, strLen ) );
203  assert( isWritePtr( numericValue, sizeof( int ) ) );
204 
205  REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
206  REQUIRES( minValue >= 0 && minValue < maxValue && \
207  maxValue <= MAX_INTLENGTH );
208 
209  /* Clear return value */
210  *numericValue = 0;
211 
212  /* Make sure that the value is within the range 'n' ... 'nnnnnnn' */
213  if( strLen < 1 || strLen > 7 )
214  return( CRYPT_ERROR_BADDATA );
215 
216  /* Process the numeric string */
217  for( value = 0, i = 0; i < strLen; i++ )
218  {
219  const int valTmp = value * 10;
220  const int ch = byteToInt( str[ i ] ) - '0';
221 
222  if( ch < 0 || ch > 9 )
223  return( CRYPT_ERROR_BADDATA );
224  if( value >= ( MAX_INTLENGTH / 10 ) || \
225  valTmp >= MAX_INTLENGTH - ch )
226  return( CRYPT_ERROR_BADDATA );
227  value = valTmp + ch;
229  return( CRYPT_ERROR_BADDATA );
230  }
231 
232  /* Make sure that the final value is within the specified range */
233  if( value < minValue || value > maxValue )
234  return( CRYPT_ERROR_BADDATA );
235 
236  *numericValue = value;
237  return( CRYPT_OK );
238  }
239 
240 /* Sanitise a string before passing it back to the user. This is used to
241  clear potential problem characters (for example control characters)
242  from strings passed back from untrusted sources (nec verbum verbo
243  curabis reddere fidus interpres - Horace). The function returns a
244  pointer to the string to allow it to be used in the form
245  printf( "..%s..", sanitiseString( string, strLen ) ). In addition it
246  formats the data to fit a fixed-length buffer, if the string is longer
247  than the indicated buffer size then it appends a '[...]' at the end of
248  the buffer to indicate that further data was truncated. The
249  transformation applied is as follows:
250 
251  buffer strMaxLen
252  | |
253  v v
254  +---------------------------+ . .
255  | | ==> . .
256  +---------------------------+ . .
257  . . . .
258  |---------------| . |---------------|\0| .
259  . ^ . . .
260  |--------------------------------| |-----------------------|[...]\0|
261  | ^
262  +---- strLen ----+
263 
264  so "Error string of arbitrary length..." with a buffer size of 20 would
265  become "Error string [...]" */
266 
268 char *sanitiseString( INOUT_BUFFER( strMaxLen, strLen ) BYTE *string,
269  IN_LENGTH_SHORT const int strMaxLen,
270  IN_LENGTH_SHORT const int strLen )
271  {
272  const int strDataLen = min( strLen, strMaxLen );
273  int i;
274 
275  assert( isWritePtr( string, strMaxLen ) );
276 
277  REQUIRES_EXT( ( strLen > 0 && strLen < MAX_INTLENGTH_SHORT ), \
278  "(Internal error)" );
279  REQUIRES_EXT( ( strMaxLen > 0 && strMaxLen < MAX_INTLENGTH_SHORT ), \
280  "(Internal error)" );
281 
282  /* Remove any potentially unsafe characters from the string, effectively
283  converting it from a 'BYTE *' to a 'char *' */
284  for( i = 0; i < strDataLen; i++ )
285  {
286  const int ch = byteToInt( string[ i ] );
287 
288  if( ch <= 0 || ch > 0x7F || !isPrint( ch ) )
289  string[ i ] = '.';
290  }
291 
292  /* If there was more input than we could fit into the buffer and
293  there's room for a continuation indicator, add this to the output
294  string */
295  if( ( strLen > strMaxLen ) && ( strMaxLen > 8 ) )
296  memcpy( string + strMaxLen - 6, "[...]", 5 ); /* Extra -1 for '\0' */
297 
298  /* Terminate the string to allow it to be used in printf()-style
299  functions */
300  if( strLen < strMaxLen )
301  string[ strLen ] = '\0';
302  else
303  string[ strMaxLen - 1 ] = '\0';
304 
305  /* We've converted the string from BYTE * to char * so it can be
306  returned as a standard text string */
307  return( ( char * ) string );
308  }
309 
310 /****************************************************************************
311 * *
312 * TR 24731 Safe stdlib Extensions *
313 * *
314 ****************************************************************************/
315 
316 #ifndef __STDC_LIB_EXT1__
317 
318 /* Minimal wrappers for the TR 24731 functions to map them to older stdlib
319  equivalents. Because of potential issues when comparing a (signed)
320  literal value -1 to the unsigned size_t we explicitly check for both
321  '( size_t ) -1' as well as a general check for a negative return value */
322 
323 RETVAL_RANGE( -1, 0 ) \
324 int mbstowcs_s( OUT size_t *retval,
325  OUT_BUFFER_FIXED( dstmax ) wchar_t *dst,
326  IN_LENGTH_SHORT size_t dstmax,
327  IN_BUFFER( len ) const char *src,
328  IN_LENGTH_SHORT size_t len )
329  {
330  size_t bytesCopied;
331 
332  assert( isWritePtr( retval, sizeof( size_t ) ) );
333  assert( isWritePtr( dst, dstmax ) );
334  assert( isReadPtr( src, len ) );
335 
336  REQUIRES_EXT( ( dstmax > 0 && dstmax < MAX_INTLENGTH_SHORT ), -1 );
337  REQUIRES_EXT( ( len > 0 && len <= dstmax && \
338  len < MAX_INTLENGTH_SHORT ), -1 );
339 
340  /* Clear return value */
341  *retval = 0;
342 
343  bytesCopied = mbstowcs( dst, src, len );
344  if( ( bytesCopied == ( size_t ) -1 ) || ( bytesCopied <= 0 ) )
345  return( -1 );
346  *retval = bytesCopied;
347  return( 0 );
348  }
349 
350 RETVAL_RANGE( -1, 0 ) \
351 int wcstombs_s( OUT size_t *retval,
352  OUT_BUFFER_FIXED( dstmax ) char *dst,
353  IN_LENGTH_SHORT size_t dstmax,
354  IN_BUFFER( len) const wchar_t *src,
355  IN_LENGTH_SHORT size_t len )
356  {
357  size_t bytesCopied;
358 
359  assert( isWritePtr( retval, sizeof( size_t ) ) );
360  assert( isWritePtr( dst, dstmax ) );
361  assert( isReadPtr( src, len ) );
362 
363  REQUIRES_EXT( ( dstmax > 0 && dstmax < MAX_INTLENGTH_SHORT ), -1 );
364  REQUIRES_EXT( ( len > 0 && len <= dstmax && \
365  len < MAX_INTLENGTH_SHORT ), -1 );
366 
367  /* Clear return value */
368  *retval = 0;
369 
370  bytesCopied = wcstombs( dst, src, len );
371  if( ( bytesCopied == ( size_t ) -1 ) || ( bytesCopied <= 0 ) )
372  return( -1 );
373  *retval = bytesCopied;
374  return( 0 );
375  }
376 #endif /* !__STDC_LIB_EXT1__ */