cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dnstring.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate String Routines *
4 * Copyright Peter Gutmann 1996-2009 *
5 * *
6 ****************************************************************************/
7 
8 #include <ctype.h>
9 #if defined( INC_ALL )
10  #include "cert.h"
11  #include "asn1.h"
12  #include "misc_rw.h"
13 #else
14  #include "cert/cert.h"
15  #include "enc_dec/asn1.h"
16  #include "enc_dec/misc_rw.h"
17 #endif /* Compiler-specific includes */
18 
19 /* The character set (or at least ASN.1 string type) for a string. Although
20  IA5String and VisibleString/ISO646String are technically different the
21  only real difference is that IA5String allows the full range of control
22  characters, which isn't notably useful. For this reason we treat both as
23  ISO646String. Sometimes we can be fed Unicode strings that are just
24  bloated versions of another string type so we need to account for these
25  as well.
26 
27  UTF-8 strings are a pain because they're only rarely supported as a
28  native format. For this reason we convert them to a more useful local
29  character set (ASCII, 8859-1, or Unicode as appropriate) when we read
30  them to make them usable. Although their use was required after the
31  cutover date of December 2003, by unspoken unanimous consensus of
32  implementors everywhere implementations stuck with the existing DN
33  encoding to avoid breaking things. Several years after the cutoff date
34  vendors were slowly starting to introduce UTF-8 support to their
35  applications, although on an ad-hoc basis and sometimes only as a user-
36  configurable option so it's still too risky to rely on this being
37  supported */
38 
39 typedef enum {
40  STRINGTYPE_NONE, /* No string type */
41 
42  /* 8-bit character types */
43  STRINGTYPE_PRINTABLE, /* PrintableString */
44  STRINGTYPE_IA5, /* IA5String */
45  STRINGTYPE_T61, /* T61 (8859-1) string */
46 
47  /* 8-bit types masquerading as Unicode */
48  STRINGTYPE_UNICODE_PRINTABLE, /* PrintableString as Unicode */
49  STRINGTYPE_UNICODE_IA5, /* IA5String as Unicode */
50  STRINGTYPE_UNICODE_T61, /* 8859-1 as Unicode */
51 
52  /* Unicode/UTF-8 */
53  STRINGTYPE_UNICODE, /* Unicode string */
54  STRINGTYPE_UTF8, /* UTF-8 string */
55 
56  /* Special-case error string type */
57  STRINGTYPE_ERROR, /* Error occurred during processing */
58 
59  STRINGTYPE_LAST /* Last possible string type */
61 
62 /* Since wchar_t can be anything from 8 bits (Borland C++ under DOS) to 32
63  bits (some RISC Unixen) we define a bmpchar_t for Unicode/BMPString
64  characters which is always 16 bits as required for BMPStrings, to match
65  the naming convention of wchar_t. The conversion to and from a BMPString
66  and wchar_t may require narrowing or widening of characters and possibly
67  endianness conversion as well */
68 
69 typedef unsigned short int bmpchar_t; /* Unicode/BMPString data type */
70 #define UCSIZE 2
71 
72 #ifdef USE_CERTIFICATES
73 
74 /****************************************************************************
75 * *
76 * Character Set Management Functions *
77 * *
78 ****************************************************************************/
79 
80 /* Because of the bizarre (and mostly useless) collection of ASN.1 character
81  types we need to be very careful about what we allow in a string. The
82  following table is used to determine whether a character is valid within
83  a given string type.
84 
85  Although IA5String and VisibleString/ISO646String are technically
86  different the only real difference is that IA5String allows the full
87  range of control characters, which isn't notably useful. For this reason
88  we treat both as ISO646String */
89 
90 #define P 1 /* PrintableString */
91 #define I 2 /* IA5String/VisibleString/ISO646String */
92 #define PI ( P | I ) /* PrintableString and IA5String */
93 
94 static const int FAR_BSS asn1CharFlags[] = {
95  /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */
96  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97  /* 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F */
98  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99  /* ! " # $ % & ' ( ) * + , - . / */
100  PI, I, I, I, I, I, I, PI, PI, PI, I, PI, PI, PI, PI, PI,
101  /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
102  PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, I, I, PI, I, PI,
103  /* @ A B C D E F G H I J K L M N O */
104  I, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,
105  /* P Q R S T U V W X Y Z [ \ ] ^ _ */
106  PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, I, I, I, I, I,
107  /* ` a b c d e f g h i j k l m n o */
108  I, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,
109  /* p q r s t u v w x y z { | } ~ DL */
110  PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, I, I, I, I, 0,
111  0, 0 /* Catch overflows */
112  };
113 
114 #define nativeCharFlags asn1CharFlags
115 
116 /* Extract a widechar or bmpchar from an (arbitrarily-aligned) string. Note
117  that if sizeof( wchar_t ) is larger than 16 bits and we're fed malformed
118  data then the return value can become larger than what's indicated in the
119  CHECK_RETVAL_RANGE() statement, but since this is only evaluated under
120  Windows where wchar_t is 16 bits this is safe to use. In addition since
121  sizeof() isn't (normally) evaluated by the preprocessor we can't easily
122  fix this with a #define or similar method */
123 
124 CHECK_RETVAL_RANGE( 0, 0xFFFF ) STDC_NONNULL_ARG( ( 1 ) ) \
125 static wchar_t getWidechar( IN_BUFFER_C( 2 ) const BYTE *string )
126  {
127  wchar_t ch = 0;
128 #ifdef DATA_LITTLEENDIAN
129  int shiftAmt = 0;
130 #endif /* DATA_LITTLEENDIAN */
131  int i;
132 
133  assert( isReadPtr( string, 2 ) );
134 
135  /* Since we're reading wchar_t-sized values from a char-aligned source,
136  we have to assemble the data a byte at a time to handle systems where
137  non-char values can only be accessed on word-aligned boundaries */
138  for( i = 0; i < WCSIZE; i++ )
139  {
140 #ifdef DATA_LITTLEENDIAN
141  ch |= string[ i ] << shiftAmt;
142  shiftAmt += 8;
143 #else
144  ch = ( ch << 8 ) | string[ i ];
145 #endif /* DATA_LITTLEENDIAN */
146  }
147 
148  return( ch );
149  }
150 
151 /****************************************************************************
152 * *
153 * UTF-8 Functions *
154 * *
155 ****************************************************************************/
156 
157 /* Parse one UTF-8 encoded character from a string, enforcing the UTF-8
158  canonical-encoding rules:
159 
160  00 - 7F = 0xxxxxxx, mask = 0x80
161  80 - 7FF = 110xxxxx 10xxxxxx, mask = 0xE0
162  800 - FFFF = 1110xxxx 10xxxxxx 10xxxxxx, mask = 0xF0
163 
164  Note that some of the checks applied below are redundant but due to the
165  powerful nature of UTF-8 string formatting attacks we apply them anyway
166  to make the different checking actions explicit and to reduce the chances
167  of a coding error that allows something dangerous to slip through */
168 
169 STDC_NONNULL_ARG( ( 1 ) ) \
170 static long getUTF8Char( INOUT STREAM *stream )
171  {
172  long largeCh;
173  int firstChar, secondChar, status;
174 
175  assert( isWritePtr( stream, sizeof( STREAM ) ) );
176 
177  /* Process the first character */
178  status = firstChar = sgetc( stream );
179  if( cryptStatusError( status ) )
180  return( CRYPT_ERROR_BADDATA );
181  if( !( firstChar & 0x80 ) )
182  {
183  /* 1-byte character, straight ASCII */
184  return( firstChar & 0x7F );
185  }
186  if( ( firstChar & 0xC0 ) == 0x80 ) /* 11xxxxxx -> 10xxxxxx */
187  return( CRYPT_ERROR_BADDATA );
188 
189  /* Process the second character */
190  status = secondChar = sgetc( stream );
191  if( cryptStatusError( status ) )
192  return( CRYPT_ERROR_BADDATA );
193  if( ( firstChar & 0xE0 ) == 0xC0 ) /* 111xxxxx -> 110xxxxx */
194  {
195  /* 2-byte character in the range 0x80...0x7FF */
196  if( ( secondChar & 0xC0 ) != 0x80 )
197  return( CRYPT_ERROR_BADDATA );
198  largeCh = ( ( firstChar & 0x1F ) << 6 ) | \
199  ( secondChar & 0x3F );
200  if( largeCh < 0x80 || largeCh > 0x7FF )
201  return( CRYPT_ERROR_BADDATA );
202  return( largeCh & 0x7FF );
203  }
204 
205  /* Process any further characters */
206  if( ( firstChar & 0xF0 ) == 0xE0 ) /* 1111xxxx -> 1110xxxx */
207  {
208  int thirdChar;
209 
210  status = thirdChar = sgetc( stream );
211  if( cryptStatusError( status ) )
212  return( CRYPT_ERROR_BADDATA );
213 
214  /* 3-byte character in the range 0x800...0xFFFF */
215  if( ( secondChar & 0xC0 ) != 0x80 || \
216  ( thirdChar & 0xC0 ) != 0x80 )
217  return( CRYPT_ERROR_BADDATA );
218  largeCh = ( ( firstChar & 0x1F ) << 12 ) | \
219  ( ( secondChar & 0x3F ) << 6 ) | \
220  ( thirdChar & 0x3F );
221  if( largeCh < 0x800 || largeCh > 0xFFFF )
222  return( CRYPT_ERROR_BADDATA );
223  return( largeCh & 0xFFFF );
224  }
225 
226  /* In theory we can also get 4- and 5-byte encodings but this is far
227  more likely to be invalid data than a genuine attempt to represent
228  something in Tsolyani */
229  return( CRYPT_ERROR_BADDATA );
230  }
231 
232 #if 0 /* Currently unused, see note at start */
233 
235 static int putUtf8Char( INOUT STREAM *stream,
236  IN_RANGE( 0, 0xFFFF ) const long largeCh )
237  {
238  assert( isWritePtr( stream, sizeof( STREAM ) ) );
239 
240  REQUIRES_S( largeCh >= 0 && largeCh <= 0xFFFF );
241 
242  if( largeCh < 0x80 )
243  return( sputc( stream, ( BYTE ) largeCh );
244  if( largeCh < 0x0800 )
245  {
246  sputc( stream, ( BYTE )( 0xC0 | ( ( largeCh >> 6 ) & 0x1F ) ) );
247  return( sputc( stream, ( BYTE )( 0x80 | ( largeCh & 0x3F ) ) ) );
248  }
249  sputc( stream, ( BYTE )( 0xE0 | ( ( largeCh >> 12 ) & 0x0F ) ) );
250  sputc( stream, ( BYTE )( 0x80 | ( ( largeCh >> 6 ) & 0x3F ) ) );
251  return( sputc( stream, ( BYTE )( 0x80 | largeCh & 0x3F ) ) );
252  }
253 
254 /* Determine the length of a string once it's encoded as UTF-8 */
255 
256 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
257 static int utf8TargetStringLen( IN_BUFFER( stringLen ) const void *string,
258  IN_LENGTH_SHORT const int stringLen,
259  OUT_LENGTH_SHORT_Z int *targetStringLength,
260  const BOOLEAN isWideChar )
261  {
262  STREAM stream;
263  int status = CRYPT_OK;
264 
265  assert( isReadPtr( string, stringLen ) );
266  assert( isWritePtr( targetStringLength, sizeof( int ) ) );
267 
268  REQUIRES( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT );
269 
270  /* Clear return value */
271  *targetStringLength = 0;
272 
273  sMemNullOpen( &stream );
274  if( isWideChar )
275  {
276  const wchar_t *wcStrPtr = ( wchar_t * ) string;
277  const int wcStrLen = stringLen / WCSIZE;
278  int i;
279 
280  REQUIRES( stringLen % WCSIZE == 0 );
281 
282  for( i = 0; i < wcStrLen && i < FAILSAFE_ITERATIONS_LARGE; i++ )
283  {
284  status = putUtf8Char( &stream, wcStrPtr[ i ] );
285  if( cryptStatusError( status ) )
286  break;
287  }
288  ENSURES( i < FAILSAFE_ITERATIONS_LARGE );
289  if( cryptStatusOK( status ) )
290  *targetStringLength = stell( &stream );
291  }
292  else
293  {
294  for( i = 0; i < strinLen && i < FAILSAFE_ITERATIONS_LARGE; i++ )
295  {
296  status = putUtf8Char( &stream, string[ i ] );
297  if( cryptStatusError( status ) )
298  break;
299  }
300  ENSURES( i < FAILSAFE_ITERATIONS_LARGE );
301  if( cryptStatusOK( status ) )
302  *targetStringLength = stell( &stream );
303  }
304  sMemClose( &stream );
305 
306  return( status );
307  }
308 #endif /* 0 */
309 
310 /* Check that a UTF-8 string has a valid encoding */
311 
313 static int checkUtf8String( IN_BUFFER( stringLen ) const void *string,
314  IN_LENGTH_SHORT const int stringLen )
315  {
316  STREAM stream;
317  int iterationCount;
318 
319  assert( isReadPtr( string, stringLen ) );
320 
321  REQUIRES( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT );
322 
323  /* Scan the string making sure that there are no malformed characters */
324  sMemConnect( &stream, string, stringLen );
325  for( iterationCount = 0;
326  stell( &stream ) < stringLen && \
327  iterationCount < FAILSAFE_ITERATIONS_LARGE;
328  iterationCount++ )
329  {
330  const long longStatus = getUTF8Char( &stream );
331  if( cryptStatusError( longStatus ) )
332  {
333  sMemDisconnect( &stream );
334  return( CRYPT_ERROR_BADDATA );
335  }
336  }
337  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
338  sMemDisconnect( &stream );
339 
340  return( CRYPT_OK );
341  }
342 
343 /* Convert a UTF-8 string to ASCII, 8859-1, or Unicode, and vice versa */
344 
345 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
346 static int copyFromUtf8String( OUT_BUFFER( destMaxLen, *destLen ) void *dest,
347  IN_LENGTH_SHORT const int destMaxLen,
349  OUT_RANGE( 0, 20 ) int *destStringType,
350  IN_BUFFER( sourceLen ) const void *source,
351  IN_LENGTH_SHORT const int sourceLen )
352  {
353  STREAM stream;
355  wchar_t *wcDestPtr = dest;
356  BYTE *destPtr = dest;
357  int noChars = 0, iterationCount;
358 
359  assert( isWritePtr( dest, destMaxLen ) );
360  assert( isWritePtr( destLen, sizeof( int ) ) );
361  assert( isWritePtr( destStringType, sizeof( int ) ) );
362  assert( isReadPtr( source, sourceLen ) );
363 
364  REQUIRES( destMaxLen > 0 && destMaxLen < MAX_INTLENGTH_SHORT );
365  REQUIRES( sourceLen > 0 && sourceLen < MAX_INTLENGTH_SHORT );
366 
367  /* Clear return value */
368  memset( dest, 0, min( 16, destMaxLen ) );
369  *destLen = 0;
370  *destStringType = STRINGTYPE_NONE;
371 
372  /* Scan the string to determine its length and the widest character type
373  in it. We have to process the entire string even if we've already
374  identified it as containing the widest string type (Unicode) in order
375  to check for malformed characters. In addition we can't combine this
376  with the copy loop that follows because until we get to the end we
377  don't know whether we're copying 8-bit or wide characters */
378  sMemConnect( &stream, source, sourceLen );
379  for( iterationCount = 0;
380  stell( &stream ) < sourceLen && \
381  iterationCount < FAILSAFE_ITERATIONS_LARGE;
382  iterationCount++ )
383  {
384  const long largeCh = getUTF8Char( &stream );
385  if( cryptStatusError( largeCh ) )
386  {
387  sMemDisconnect( &stream );
388  return( largeCh );
389  }
390  noChars++;
391 
392  /* If we've already identified the widest character type there's
393  nothing more to do */
394  if( stringType == STRINGTYPE_UNICODE )
395  continue;
396 
397  /* If it's not an 8-bit value it can only be Unicode */
398  if( largeCh > 0xFF )
399  {
400  stringType = STRINGTYPE_UNICODE;
401  continue;
402  }
403 
404  /* If it's not a PrintableString character mark it as T61 if it's
405  within range, otherwise it's Unicode */
406  if( largeCh >= 128 )
407  {
408  stringType = ( asn1CharFlags[ largeCh & 0x7F ] & P ) ? \
410  }
411  }
412  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
413  sMemDisconnect( &stream );
414 
415  /* Make sure that the translated string will fit into the destination
416  buffer */
417  *destLen = noChars * ( ( stringType == STRINGTYPE_UNICODE ) ? \
418  WCSIZE : 1 );
419  if( *destLen < 0 || *destLen > destMaxLen )
420  return( CRYPT_ERROR_OVERFLOW );
421  *destStringType = stringType;
422 
423  /* Perform a second pass copying the string over */
424  sMemConnect( &stream, source, sourceLen );
425  for( iterationCount = 0;
426  stell( &stream ) < sourceLen && \
427  iterationCount < FAILSAFE_ITERATIONS_LARGE;
428  iterationCount++ )
429  {
430  const long largeCh = getUTF8Char( &stream );
431 
432  ENSURES( !cryptStatusError( largeCh ) );
433 
434  /* Copy the result as a Unicode or ASCII/8859-1 character */
435  if( stringType == STRINGTYPE_UNICODE )
436  *wcDestPtr++ = ( wchar_t ) largeCh;
437  else
438  *destPtr++ = ( BYTE ) largeCh;
439  }
440  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
441  sMemDisconnect( &stream );
442 
443  return( CRYPT_OK );
444  }
445 
446 #if 0 /* Currently unused, see note at start */
447 
448 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
449 static int copyToUtf8String( OUT_BUFFER( destMaxLen, *destLen ) void *dest,
450  IN_LENGTH_SHORT const int destMaxLen,
451  OUT_LENGTH_SHORT_Z int *destLen,
452  IN_BUFFER( sourceLen ) const void *source,
453  IN_LENGTH_SHORT const int sourceLen,
454  const BOOLEAN isWideChar )
455  {
456  STREAM stream;
457 
458  assert( isWritePtr( dest, destMaxLen ) );
459  assert( isWritePtr( destLen, sizeof( int ) ) );
460  assert( isReadPtr( source, sourceLen ) );
461 
462  REQUIRES( destMaxLen > 0 && destMaxLen < MAX_INTLENGTH_SHORT );
463  REQUIRES( sourceLen > 0 && sourceLen < MAX_INTLENGTH_SHORT );
464 
465  /* Clear return value */
466  memset( dest, 0, min( 16, destMaxLen ) );
467  *destLen = 0;
468 
469  sMemOpen( &stream, dest, destMaxLen );
470  if( isWideChar )
471  {
472  const wchar_t *wcStrPtr = ( wchar_t * ) string;
473  const int wcStrLen = stringLen / WCSIZE;
474  int i;
475 
476  REQUIRES( stringLen % WCSIZE == 0 );
477 
478  for( i = 0; i < wcStrLen && i < FAILSAFE_ITERATIONS_LARGE; i++ )
479  {
480  if( wcStrPtr[ i ] < 0 || wcStrPtr[ i ] > 0xFFFF )
481  {
482  /* Safety check for WCSIZE > 2 */
483  return( CRYPT_ERROR_BADDATA );
484  }
485  status = putUtf8Char( &stream, wcStrPtr[ i ] );
486  if( cryptStatusError( status ) )
487  break;
488  }
489  ENSURES( i < FAILSAFE_ITERATIONS_LARGE );
490  if( cryptStatusOK( status ) )
491  *destLen = stell( &stream );
492  }
493  else
494  {
495  for( i = 0; i < strinLen && i < FAILSAFE_ITERATIONS_LARGE; i++ )
496  {
497  status = putUtf8Char( &stream, string[ i ] );
498  if( cryptStatusError( status ) )
499  break;
500  }
501  ENSURES( i < FAILSAFE_ITERATIONS_LARGE );
502  if( cryptStatusOK( status ) )
503  *destLen = stell( &stream );
504  }
505  sMemDisconnect( &stream );
506 
507  return( status );
508  }
509 #endif /* 0 */
510 
511 /****************************************************************************
512 * *
513 * String-type Identification Functions *
514 * *
515 ****************************************************************************/
516 
517 /* Try and guess whether a native string is a widechar string */
518 
520 static BOOLEAN isNativeWidecharString( IN_BUFFER( stringLen ) const BYTE *string,
521  IN_LENGTH_SHORT_MIN( 2 ) const int stringLen )
522  {
523  wchar_t wCh;
524  int hiByte = 0, i;
525 
526  assert( isReadPtr( string, stringLen ) );
527 
528  REQUIRES_B( stringLen >= WCSIZE && stringLen < MAX_INTLENGTH_SHORT );
529  REQUIRES_B( !( stringLen % WCSIZE ) );
530 
531  /* Look at the first character in the string */
532  wCh = getWidechar( string );
533 
534  /* If wchar_t is > 16 bits and the bits above 16 are set or all zero,
535  it's either definitely not Unicode or Unicode. Note that some
536  compilers will complain of unreachable code here, unfortunately we
537  can't easily fix this since WCSIZE is usually an expression involving
538  sizeof() which can't be handled via the preprocessor so we have to
539  guard it with a preprocessor check */
540 #ifdef CHECK_WCSIZE
541  if( WCSIZE > 2 )
542  return( ( wCh > 0xFFFF ) ? FALSE : TRUE );
543 #endif /* CHECK_WCSIZE */
544 
545  /* If wchar_t is 8 bits it's never Unicode. We make this conditional on
546  the system being 16-bit to avoid compiler warnings about dead code on
547  the majority of systems, which have > 8-bit wchar_t */
548 #if INT_MAX < 0xFFFFL
549  if( WCSIZE < 2 )
550  return( FALSE );
551 #endif /* WCSIZE */
552 
553  /* wchar_t is 16 bits, make sure that we don't get false positives with
554  short strings. Two-character strings are more likely to be ASCII
555  than a single widechar, and repeated alternate characters (e.g.
556  "tanaka") in an ASCII string appear to be widechars for the general-
557  purpose check below so we check for these in strings of 2-3 wide
558  characters before we perform the general-purpose check */
559  if( stringLen <= ( WCSIZE * 3 ) && wCh > 0xFF )
560  {
561  if( stringLen == WCSIZE )
562  {
563  const int ch1 = string[ 0 ];
564  const int ch2 = string[ 1 ];
565 
566  /* Check for a two-character ASCII string, usually a country
567  name */
568  if( ch1 > 0 && ch1 <= 0x7F && isPrint( ch1 ) && \
569  ch2 > 0 && ch2 <= 0x7F && isPrint( ch2 ) )
570  return( FALSE );
571  }
572  else
573  {
574  const int hi1 = wCh >> 8;
575  const int hi2 = getWidechar( string + WCSIZE ) >> 8;
576  const int hi3 = ( stringLen > WCSIZE * 2 ) ? \
577  getWidechar( string + ( WCSIZE * 2 ) ) >> 8 : hi1;
578 
579  ENSURES_B( stringLen == ( WCSIZE * 2 ) || \
580  stringLen == ( WCSIZE * 3 ) );
581 
582  /* Check for alternate characters being ASCII */
583  if( isAlnum( hi1 ) && isAlnum( hi2 ) && isAlnum( hi3 ) && \
584  hi1 == hi2 && hi2 == hi3 )
585  return( FALSE );
586  }
587  }
588 
589  /* wchar_t is 16 bits, check whether it's in the form { 00 xx }* or
590  { AA|00 xx }*, either ASCII-as-Unicode or Unicode. The code used
591  below is safe because to get to this point the string has to be some
592  multiple of 2 bytes long. Note that if someone passes in a 1-byte
593  string and mistakenly includes the terminator in the length it'll be
594  identified as a 16-bit widechar string but this doesn't really matter
595  since it'll get "converted" into a non-widechar string later */
596  for( i = 0; i < stringLen && i < FAILSAFE_ITERATIONS_LARGE; i += WCSIZE )
597  {
598  wCh = getWidechar( &string[ i ] );
599  if( wCh > 0xFF )
600  {
601  const int wChHi = wCh >> 8;
602 
603  ENSURES_B( wChHi );
604 
605  /* If we haven't already seen a high byte, remember it */
606  if( hiByte == 0 )
607  hiByte = wChHi;
608  else
609  {
610  /* If the current high byte doesn't match the previous one,
611  it's probably 8-bit characters */
612  if( wChHi != hiByte )
613  return( FALSE );
614  }
615  }
616  }
617  ENSURES_B( i < FAILSAFE_ITERATIONS_LARGE );
618 
619  return( TRUE ); /* Probably 16-bit characters */
620  }
621 
622 /* Try and figure out the true string type for an ASN.1-encoded or native
623  string. This detects (or at least tries to detect) not only the basic
624  string type but also basic string types encoded as widechar strings and
625  widechar strings encoded as basic string types.
626 
627  All of these functions work by checking for the most restrictive ASN.1
628  string subset that'll still contain the string, progressively widening
629  from PrintableString -> IA5String -> T61(8859-1)String ->
630  BMP(Unicode)String, reporting an error if even a Unicode string can't
631  contain the value. Note that we continue processing the string even
632  when we've reached the least-constraining value (Unicode) because we
633  still need to check whether all of the characters in the string are
634  actually valid before we exit */
635 
637 static ASN1_STRINGTYPE get8bitStringType( IN_BUFFER( stringLen ) \
638  const BYTE *string,
639  IN_LENGTH_SHORT const int stringLen,
641  {
642  BOOLEAN isIA5 = FALSE, isT61 = FALSE;
643  int i;
644 
645  assert( isReadPtr( string, stringLen ) );
646 
647  REQUIRES_EXT( ( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT ), \
649  REQUIRES_EXT( ( stringTag >= BER_STRING_UTF8 && \
650  stringTag < BER_STRING_BMP ),
652 
653  /* Walk down the string checking each character */
654  for( i = 0; i < stringLen; i++ )
655  {
656  const BYTE ch = string[ i ];
657 
658  /* If the high bit is set, it's not an ASCII subset */
659  if( ch >= 128 )
660  {
661  isT61 = TRUE;
662  if( asn1CharFlags[ ch & 0x7F ] )
663  continue;
664 
665  /* It's not 8859-1 either, check whether it's UTF-8 if this is
666  permitted. We can safely do an early-out in this case
667  because checkUtf8String() checks the entire string */
668  if( stringTag == BER_STRING_UTF8 )
669  {
670  if( cryptStatusOK( checkUtf8String( string, stringLen ) ) )
671  return( STRINGTYPE_UTF8 );
672  }
673 
674  return( STRINGTYPE_ERROR );
675  }
676 
677  /* Check whether it's a PrintableString */
678  if( !( asn1CharFlags[ ch ] & P ) )
679  isIA5 = TRUE;
680 
681  /* Check whether it's something peculiar */
682  if( asn1CharFlags[ ch ] )
683  continue;
684 
685  /* It's not 8859-1 either, check whether it's UTF-8 if this is
686  permitted. We can safely do an early-out in this case because
687  we're checking the entire string */
688  if( stringTag == BER_STRING_UTF8 )
689  {
690  if( cryptStatusOK( checkUtf8String( string, stringLen ) ) )
691  return( STRINGTYPE_UTF8 );
692  }
693 
694  return( STRINGTYPE_ERROR );
695  }
696 
697  return( isT61 ? STRINGTYPE_T61 : \
698  isIA5 ? STRINGTYPE_IA5 : \
700  }
701 
703 static ASN1_STRINGTYPE getAsn1StringType( IN_BUFFER( stringLen ) \
704  const BYTE *string,
705  IN_LENGTH_SHORT const int stringLen,
706  IN_TAG_ENCODED const int stringTag )
707  {
708  STREAM stream;
709  BOOLEAN isIA5 = FALSE, isT61 = FALSE, isUnicode = FALSE;
710  int length, status;
711 
712  assert( isReadPtr( string, stringLen ) );
713 
714  REQUIRES_EXT( ( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT ), \
716  REQUIRES_EXT( ( stringTag >= BER_STRING_UTF8 && \
717  stringTag <= BER_STRING_BMP ),
719 
720  /* If it's not a Unicode string, determine the 8-bit string type */
721  if( stringTag != BER_STRING_BMP )
722  return( get8bitStringType( string, stringLen, stringTag ) );
723 
724  /* If it's not a multiple of bmpchar_t in size then it can't really be
725  Unicode either */
726  if( stringLen % UCSIZE )
727  return( STRINGTYPE_ERROR );
728 
729  /* If the first character isn't a null then it's definitely a Unicode
730  string. These strings are always big-endian, even coming from
731  Microsoft software, so we don't have to check for a null as the
732  second character */
733  if( string[ 0 ] != '\0' )
734  return( STRINGTYPE_UNICODE );
735 
736  /* Check whether it's an 8-bit string encoded as a BMPString. Since
737  we're reading bmpchar_t-sized values from a char-aligned source we
738  have to assemble the data carefully to handle systems where non-char
739  values can only be accessed on word-aligned boundaries */
740  sMemConnect( &stream, string, stringLen );
741  for( length = 0; length < stringLen; length += UCSIZE )
742  {
743  int ch;
744 
745  status = ch = readUint16( &stream );
746  if( cryptStatusError( status ) )
747  {
748  sMemDisconnect( &stream );
749  return( STRINGTYPE_ERROR );
750  }
751 
752  /* If it's not an 8-bit value then it's a pure Unicode string */
753  if( ch > 0xFF )
754  {
755  isUnicode = TRUE;
756  continue;
757  }
758 
759  /* If the high bit is set then it's not an ASCII subset */
760  if( ch >= 0x80 )
761  {
762  isT61 = TRUE;
763  continue;
764  }
765 
766  /* Check whether it's a PrintableString */
767  if( !( asn1CharFlags[ ch ] & P ) )
768  isIA5 = TRUE;
769  }
770  sMemDisconnect( &stream );
771 
772  return( isUnicode ? STRINGTYPE_UNICODE : \
773  isT61 ? STRINGTYPE_UNICODE_T61 : \
774  isIA5 ? STRINGTYPE_UNICODE_IA5 : \
776  }
777 
779 static ASN1_STRINGTYPE getNativeStringType( IN_BUFFER( stringLen ) \
780  const BYTE *string,
781  IN_LENGTH_SHORT const int stringLen )
782  {
783  BOOLEAN isIA5 = FALSE, isT61 = FALSE, isUnicode = FALSE;
784  int i;
785 
786  assert( isReadPtr( string, stringLen ) );
787 
788  REQUIRES_EXT( ( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT ), \
790 
791  /* If it's not a widechar string, handle it as a basic 8-bit string
792  type. We pass in 8859-1 as the most permissible allowed string
793  type, making it UTF-8 is rather risky because we don't know whether
794  the environment really does support this natively or whether we've
795  been passed garbage, and in addition the creation of certificates
796  with UTF8 strings is disabled by default because of interop problems
797  (see the comment at the start) so even if it is a legitimate UTF8
798  string we can't really do much with it once we have to encode the
799  DN */
800  if( stringLen < WCSIZE || ( stringLen % WCSIZE ) != 0 || \
801  !isNativeWidecharString( string, stringLen ) )
802  return( get8bitStringType( string, stringLen, BER_STRING_T61 ) );
803 
804  /* It's a widechar string, although it may actually be something else
805  that's been bloated out into widechars so we check for this as well */
806  for( i = 0; i < stringLen; i += WCSIZE )
807  {
808  const wchar_t wCh = getWidechar( &string[ i ] );
809 
810  /* Make sure that we've got a character from a Unicode (BMP) string.
811  This check can be triggered if WCSIZE > 2 and the caller feeds us
812  a binary garbage string so that the resulting decoded widechar
813  value is larger than 16 bits */
814  if( wCh < 0 || ( wCh & 0xFFFF8000L ) )
815  return( STRINGTYPE_ERROR );
816 
817  /* If the high bit is set it's not an ASCII subset */
818  if( wCh >= 0x80 )
819  {
820  /* If it's larger than 8 bits then it's definitely Unicode */
821  if( wCh >= 0xFF )
822  {
823  isUnicode = TRUE;
824  continue;
825  }
826 
827  /* Check which (if any) 8-bit type it could be */
828  isT61 = TRUE;
829  if( nativeCharFlags[ wCh & 0x7F ] )
830  continue;
831 
832  /* It's not 8859-1 either, or more specifically it's something
833  that ends up looking like a control character, what to do at
834  this point is a bit uncertain but making it a generic Unicode
835  string which'll be handled via somewhat more robust
836  mechanisms than something presumed to be ASCII or close to it
837  is probably safer than storing it as a probably control
838  character */
839  isUnicode = TRUE;
840 
841  continue;
842  }
843 
844  /* Check whether it's a PrintableString */
845  if( !( nativeCharFlags[ wCh ] & P ) )
846  isIA5 = TRUE;
847  }
848 
849  return( isUnicode ? STRINGTYPE_UNICODE : \
850  isT61 ? STRINGTYPE_UNICODE_T61 : \
851  isIA5 ? STRINGTYPE_UNICODE_IA5 : \
853  }
854 
855 /****************************************************************************
856 * *
857 * ASN.1 String Conversion Functions *
858 * *
859 ****************************************************************************/
860 
861 /* Check that a text string contains valid characters for its string type.
862  This is used in non-DN strings where we can't vary the string type based
863  on the characters being used */
864 
866 BOOLEAN checkTextStringData( IN_BUFFER( stringLen ) const char *string,
867  IN_LENGTH_SHORT const int stringLen,
868  const BOOLEAN isPrintableString )
869  {
870  const int charTypeMask = isPrintableString ? P : I;
871  int i;
872 
873  assert( isReadPtr( string, stringLen ) );
874 
875  REQUIRES_B( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT );
876 
877  for( i = 0; i < stringLen && i < FAILSAFE_ITERATIONS_LARGE; i++ )
878  {
879  const int ch = byteToInt( string[ i ] );
880 
881  if( ch <= 0 || ch > 0x7F || !isPrint( ch ) )
882  return( FALSE );
883  if( !( nativeCharFlags[ ch ] & charTypeMask ) )
884  return( FALSE );
885  }
886  ENSURES_B( i < FAILSAFE_ITERATIONS_LARGE );
887 
888  return( TRUE );
889  }
890 
891 /* Convert a character string from the format used in certificates into the
892  native format */
893 
894 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
895 int copyFromAsn1String( OUT_BUFFER( destMaxLen, *destLen ) void *dest,
896  IN_LENGTH_SHORT const int destMaxLen,
897  OUT_LENGTH_SHORT_Z int *destLen,
898  OUT_RANGE( 0, 20 ) int *destStringType,
899  IN_BUFFER( sourceLen ) const void *source,
900  IN_LENGTH_SHORT const int sourceLen,
901  IN_TAG_ENCODED const int stringTag )
902  {
903  STREAM stream;
904  const ASN1_STRINGTYPE stringType = getAsn1StringType( source, sourceLen,
905  stringTag );
906  int iterationCount, status;
907 
908  assert( isWritePtr( dest, destMaxLen ) );
909  assert( isWritePtr( destLen, sizeof( int ) ) );
910  assert( isWritePtr( destStringType, sizeof( int ) ) );
911  assert( isReadPtr( source, sourceLen ) );
912 
913  REQUIRES( destMaxLen > 0 && destMaxLen < MAX_INTLENGTH_SHORT );
914  REQUIRES( sourceLen > 0 && sourceLen < MAX_INTLENGTH_SHORT );
915  REQUIRES( stringTag >= BER_STRING_UTF8 && stringTag <= BER_STRING_BMP );
916 
917  /* Clear return values */
918  memset( dest, 0, min( 16, destMaxLen ) );
919  *destLen = 0;
920  *destStringType = STRINGTYPE_NONE;
921 
922  /* Make sure that the string type can be determined */
923  if( stringType <= STRINGTYPE_NONE || stringType >= STRINGTYPE_ERROR )
924  return( CRYPT_ERROR_BADDATA );
925 
926  /* If it's a BMP or UTF-8 string convert it to the native format */
927  if( stringType == STRINGTYPE_UNICODE )
928  {
929  wchar_t *wcDestPtr = ( wchar_t * ) dest;
930  const int newLen = ( sourceLen / UCSIZE ) * WCSIZE;
931 
932  if( newLen <= 0 || newLen > destMaxLen )
933  return( CRYPT_ERROR_OVERFLOW );
934 
935  /* Since we're reading bmpchar_t-sized values from a char-aligned
936  source we have to assemble the data carefully to handle systems
937  where non-char values can only be accessed on word-aligned
938  boundaries */
939  sMemConnect( &stream, source, sourceLen );
940  for( iterationCount = 0;
941  stell( &stream ) < sourceLen && \
942  iterationCount < FAILSAFE_ITERATIONS_LARGE;
943  iterationCount++ )
944  {
945  int wCh;
946 
947  status = wCh = readUint16( &stream );
948  if( cryptStatusError( status ) )
949  {
950  sMemDisconnect( &stream );
951  return( status );
952  }
953  *wcDestPtr++ = ( wchar_t ) wCh;
954  }
955  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
956  sMemDisconnect( &stream );
957  *destLen = newLen;
958  *destStringType = STRINGTYPE_UNICODE;
959 
960  return( CRYPT_OK );
961  }
962  if( stringTag == BER_STRING_UTF8 )
963  {
964  return( copyFromUtf8String( dest, destMaxLen, destLen,
965  destStringType, source, sourceLen ) );
966  }
967 
968  /* If it's something masquerading as Unicode convert it to the narrower
969  format */
970  if( stringType == STRINGTYPE_UNICODE_PRINTABLE || \
971  stringType == STRINGTYPE_UNICODE_IA5 || \
972  stringType == STRINGTYPE_UNICODE_T61 )
973  {
974  BYTE *destPtr = dest;
975  const int newLen = sourceLen / UCSIZE;
976 
977  if( newLen <= 0 || newLen > destMaxLen )
978  return( CRYPT_ERROR_OVERFLOW );
979 
980  sMemConnect( &stream, source, sourceLen );
981  for( iterationCount = 0;
982  stell( &stream ) < sourceLen && \
983  iterationCount < FAILSAFE_ITERATIONS_LARGE;
984  iterationCount++ )
985  {
986  int wCh;
987 
988  status = wCh = readUint16( &stream );
989  if( !cryptStatusError( status ) && ( wCh > 0xFF ) )
990  {
991  /* Should never happen because of the pre-scan that we've
992  done earlier */
993  status = CRYPT_ERROR_BADDATA;
994  }
995  if( cryptStatusError( status ) )
996  {
997  sMemDisconnect( &stream );
998  return( status );
999  }
1000  *destPtr++ = intToByte( wCh );
1001  }
1002  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1003  sMemDisconnect( &stream );
1004  *destLen = newLen;
1005  *destStringType = ( stringType == STRINGTYPE_UNICODE_PRINTABLE ) ? \
1007  ( stringType == STRINGTYPE_UNICODE_IA5 ) ? \
1008  STRINGTYPE_IA5 : STRINGTYPE_UNICODE_T61;
1009 
1010  return( CRYPT_OK );
1011  }
1012 
1013  /* It's an 8-bit character set, just copy it across */
1014  if( sourceLen <= 0 || sourceLen > destMaxLen )
1015  return( CRYPT_ERROR_OVERFLOW );
1016  memcpy( dest, source, sourceLen );
1017  *destLen = sourceLen;
1018  *destStringType = stringType;
1019 
1020 #if 0 /* 18/7/08 Removed for attack surface reduction, there's really no
1021  need to have this here just to support some long-expired broken
1022  Deutsche Telekom certificates */
1023  /* If it's a T61String try and guess whether it's using floating
1024  diacritics and convert them to the correct latin-1 representation.
1025  This is mostly guesswork since some implementations use floating
1026  diacritics and some don't, the only known user is Deutsche Telekom
1027  who use them for a/o/u-umlauts so we only interpret the character if
1028  the result would be one of these values */
1029  if( stringTag == BER_STRING_T61 )
1030  {
1031  BYTE *destPtr = dest;
1032  int length = sourceLen, i;
1033 
1034  for( i = 0; i < length - 1 && i < FAILSAFE_ITERATIONS_LARGE; i++ )
1035  {
1036  if( destPtr[ i ] == 0xC8 )
1037  {
1038  int ch = byteToInt( destPtr[ i + 1 ] );
1039 
1040  /* If it's an umlautable character convert the following
1041  ASCII value to the equivalent latin-1 form and move the
1042  rest of the string down */
1043  if( ch == 0x61 || ch == 0x41 || /* a, A */
1044  ch == 0x6F || ch == 0x4F || /* o, O */
1045  ch == 0x75 || ch == 0x55 ) /* u, U */
1046  {
1047  typedef struct { int src, dest; } CHARMAP_INFO;
1048  static const CHARMAP_INFO charMap[] = {
1049  { 0x61, 0xE4 }, { 0x41, 0xC4 }, /* a, A */
1050  { 0x6F, 0xF6 }, { 0x4F, 0xD6 }, /* o, O */
1051  { 0x75, 0xFC }, { 0x55, 0xDC }, /* u, U */
1052  { 0x00, '?' }, { 0x00, '?' }
1053  };
1054  int charIndex;
1055 
1056  for( charIndex = 0;
1057  charMap[ charIndex ].src && \
1058  charMap[ charIndex ].src != ch && \
1059  charIndex < FAILSAFE_ARRAYSIZE( charMap, CHARMAP_INFO );
1060  charIndex++ );
1061  ENSURES( charIndex < FAILSAFE_ARRAYSIZE( charMap, CHARMAP_INFO ) );
1062  destPtr[ i ] = charMap[ charIndex ].dest;
1063  if( length - i > 2 )
1064  memmove( destPtr + i + 1, destPtr + i + 2,
1065  length - ( i + 2 ) );
1066  length--;
1067  }
1068  }
1069  }
1070  ENSURES( i < FAILSAFE_ITERATIONS_LARGE );
1071  *destLen = length;
1072  }
1073 #endif /* 0 */
1074 
1075  return( CRYPT_OK );
1076  }
1077 
1078 /* Convert a character string from the native format to the format used in
1079  certificates. The 'stringType' value doesn't have any meaning outside
1080  this module, it's merely used as a cookie to pass back to other functions
1081  here */
1082 
1083 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
1084 int getAsn1StringInfo( IN_BUFFER( stringLen ) const void *string,
1085  IN_LENGTH_SHORT const int stringLen,
1086  OUT_RANGE( 0, 20 ) int *stringType,
1089  {
1090  const ASN1_STRINGTYPE localStringType = \
1091  getNativeStringType( string, stringLen );
1092 
1093  assert( isReadPtr( string, stringLen ) );
1094  assert( isWritePtr( stringType, sizeof( int ) ) );
1095  assert( isWritePtr( asn1StringType, sizeof( int ) ) );
1096  assert( isWritePtr( asn1StringLen, sizeof( int ) ) );
1097 
1098  REQUIRES( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT );
1099 
1100  /* Clear return value */
1101  *asn1StringLen = 0;
1102  *asn1StringType = 0;
1103 
1104  /* Make sure that the string type can be determined */
1105  if( localStringType <= STRINGTYPE_NONE || \
1106  localStringType >= STRINGTYPE_ERROR )
1107  return( CRYPT_ERROR_BADDATA );
1108 
1109  *stringType = localStringType;
1110  switch( localStringType )
1111  {
1112  case STRINGTYPE_UNICODE:
1113  /* It's a native widechar string, the output is Unicode
1114  (BMPString) */
1115  *asn1StringLen = ( stringLen / WCSIZE ) * UCSIZE;
1116  *asn1StringType = BER_STRING_BMP;
1117  return( CRYPT_OK );
1118 
1122  /* It's an ASCII string masquerading as a native widechar
1123  string, output is an 8-bit string type */
1124  *asn1StringLen = stringLen / WCSIZE;
1125  *asn1StringType = \
1126  ( localStringType == STRINGTYPE_UNICODE_PRINTABLE ) ? \
1128  ( localStringType == STRINGTYPE_UNICODE_IA5 ) ? \
1129  BER_STRING_IA5 : BER_STRING_T61;
1130  return( CRYPT_OK );
1131 
1132 #if 0 /* Currently unused, see note at start */
1133  case STRINGTYPE_UTF8:
1134  {
1135  int status;
1136 
1137  /* It's a native widechar string encoded as UTF-8, the output is
1138  a variable-length UTF-8 string */
1139  status = utf8TargetStringLen( string, stringLen, asn1StringLen,
1140  ( localStringType == STRINGTYPE_UNICODE || \
1141  localStringType == STRINGTYPE_UNICODE_PRINTABLE || \
1142  localStringType == STRINGTYPE_UNICODE_IA5 || \
1143  localStringType == STRINGTYPE_UNICODE_T61 ) ? \
1144  TRUE : FALSE );
1145  if( cryptStatusError( status ) )
1146  return( status );
1147  *asn1StringType = BER_STRING_UTF8;
1148  return( CRYPT_OK );
1149  }
1150 #endif /* 0 */
1151  }
1152 
1153  /* If nothing specialised matches then the default string type is an
1154  ASCII string */
1155  *asn1StringLen = stringLen;
1156  *asn1StringType = ( localStringType == STRINGTYPE_PRINTABLE ) ? \
1158  ( localStringType == STRINGTYPE_IA5 ) ? \
1159  BER_STRING_IA5 : BER_STRING_T61;
1160 
1161  return( CRYPT_OK );
1162  }
1163 
1164 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
1165 int copyToAsn1String( OUT_BUFFER( destMaxLen, *destLen ) void *dest,
1166  IN_LENGTH_SHORT const int destMaxLen,
1167  OUT_LENGTH_SHORT_Z int *destLen,
1168  IN_BUFFER( sourceLen ) const void *source,
1169  IN_LENGTH_SHORT const int sourceLen,
1170  IN_RANGE( 1, 20 ) const int stringType )
1171  {
1172  STREAM stream;
1173  const BYTE *srcPtr = source;
1174  const BOOLEAN unicodeTarget = ( stringType == STRINGTYPE_UNICODE ) ? \
1175  TRUE : FALSE;
1176  int i, status;
1177 
1178  assert( isWritePtr( dest, destMaxLen ) );
1179  assert( isWritePtr( destLen, sizeof( int ) ) );
1180  assert( isReadPtr( source, sourceLen ) );
1181 
1182  REQUIRES( destMaxLen > 0 && destMaxLen < MAX_INTLENGTH_SHORT );
1183  REQUIRES( sourceLen > 0 && sourceLen < MAX_INTLENGTH_SHORT );
1184  REQUIRES( stringType > STRINGTYPE_NONE && \
1185  stringType < STRINGTYPE_LAST && \
1186  stringType != STRINGTYPE_ERROR );
1187 
1188  /* Clear return value */
1189  memset( dest, 0, min( 16, destMaxLen ) );
1190  *destLen = 0;
1191 
1192  /* If it's a non-widechar string then we can just copy it across
1193  directly */
1194  if( stringType != STRINGTYPE_UNICODE && \
1195  stringType != STRINGTYPE_UNICODE_PRINTABLE && \
1196  stringType != STRINGTYPE_UNICODE_IA5 && \
1197  stringType != STRINGTYPE_UNICODE_T61 )
1198  {
1199  if( sourceLen > destMaxLen )
1200  return( CRYPT_ERROR_OVERFLOW );
1201  memcpy( dest, source, sourceLen );
1202  *destLen = sourceLen;
1203 
1204  return( CRYPT_OK );
1205  }
1206 
1207  /* It's a native widechar string, copy it across converting from wchar_t
1208  to bmpchar_t/char as required */
1209  sMemOpen( &stream, dest, destMaxLen );
1210  for( status = CRYPT_OK, i = 0;
1211  i < sourceLen && i < FAILSAFE_ITERATIONS_LARGE;
1212  i += WCSIZE )
1213  {
1214  const wchar_t wCh = getWidechar( &srcPtr[ i ] );
1215  if( unicodeTarget )
1216  status = writeUint16( &stream, wCh );
1217  else
1218  status = sputc( &stream, wCh );
1219  }
1220  ENSURES( i < FAILSAFE_ITERATIONS_LARGE );
1221  if( cryptStatusOK( status ) )
1222  *destLen = stell( &stream );
1223  sMemDisconnect( &stream );
1224 
1225  return( status );
1226  }
1227 #endif /* USE_CERTIFICATES */