cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
base64.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Base64 Routines *
4 * Copyright Peter Gutmann 1992-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "stream.h"
11  #include "asn1.h"
12 #else
13  #include "crypt.h"
14  #include "io/stream.h"
15  #include "enc_dec/asn1.h"
16 #endif /* Compiler-specific includes */
17 
18 /* Base64 encode/decode tables from RFC 1113 */
19 
20 #define BPAD '=' /* Padding for odd-sized output */
21 #define BERR 0xFF /* Illegal character marker */
22 #define BEOF 0x7F /* EOF marker (padding character or EOL) */
23 
24 static const char FAR_BSS binToAscii[ 64 ] = {
25  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
26  'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
27  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
28  'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
29  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
30  'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
31  'w', 'x', 'y', 'z', '0', '1', '2', '3',
32  '4', '5', '6', '7', '8', '9', '+', '/'
33  };
34 
35 static const BYTE FAR_BSS asciiToBin[ 256 ] = {
36  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* 00 */
38  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* 10 */
40  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* 20 */
41  BERR, BERR, BERR, 0x3E, BERR, BERR, BERR, 0x3F,
42  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, /* 30 */
43  0x3C, 0x3D, BERR, BERR, BERR, BEOF, BERR, BERR,
44  BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 40 */
45  0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
46  0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 50 */
47  0x17, 0x18, 0x19, BERR, BERR, BERR, BERR, BERR,
48  BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, /* 60 */
49  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
50  0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, /* 70 */
51  0x31, 0x32, 0x33, BERR, BERR, BERR, BERR, BERR,
52  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* 80 */
54  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* 90 */
56  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* A0 */
58  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* B0 */
60  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* C0 */
62  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* D0 */
64  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* E0 */
66  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /* F0 */
67  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR
68  };
69 
70 /* The size of lines for base64-encoded data. This is only used for
71  encoding, for decoding we adjust to whatever size the sender has used,
72  however we require at least some minimum line size when we check for the
73  validity of base64-encoded data */
74 
75 #define BASE64_LINESIZE 64
76 #define BASE64_MIN_LINESIZE 56
77 
78 /* Basic single-character en/decode functions. We mask the value to 6 or 8
79  bits both as a range check and to avoid generating negative array offsets
80  if the sign bit is set, since the strings are passed as 'char *'s */
81 
82 #define encode( data ) binToAscii[ ( data ) & 0x3F ]
83 #define decode( data ) asciiToBin[ ( data ) & 0xFF ]
84 
85 /* The headers and trailers used for base64-encoded certificate objects */
86 
87 typedef struct {
89  BUFFER_FIXED( headerLen ) \
90  const char FAR_BSS *header;
91  const int headerLen;
92  BUFFER_FIXED( trailerLen ) \
93  const char FAR_BSS *trailer;
94  const int trailerLen;
95  } HEADER_INFO;
96 static const HEADER_INFO FAR_BSS headerInfo[] = {
98  "-----BEGIN CERTIFICATE-----" EOL, 27 + EOL_LEN,
99  "-----END CERTIFICATE-----" EOL, 25 + EOL_LEN },
101  "-----BEGIN ATTRIBUTE CERTIFICATE-----" EOL, 37 + EOL_LEN,
102  "-----END ATTRIBUTE CERTIFICATE-----" EOL, 35 + EOL_LEN },
104  "-----BEGIN CERTIFICATE CHAIN-----" EOL, 33 + EOL_LEN,
105  "-----END CERTIFICATE CHAIN-----" EOL, 31 + EOL_LEN },
107  "-----BEGIN NEW CERTIFICATE REQUEST-----" EOL, 39 + EOL_LEN,
108  "-----END NEW CERTIFICATE REQUEST-----" EOL, 37 + EOL_LEN },
110  "-----BEGIN NEW CERTIFICATE REQUEST-----" EOL, 39 + EOL_LEN,
111  "-----END NEW CERTIFICATE REQUEST-----" EOL, 37 + EOL_LEN },
113  "-----BEGIN CERTIFICATE REVOCATION LIST-----" EOL, 43 + EOL_LEN,
114  "-----END CERTIFICATE REVOCATION LIST-----" EOL, 41 + EOL_LEN },
115  { CRYPT_CERTTYPE_NONE, /* Universal catch-all */
116  "-----BEGIN CERTIFICATE OBJECT-----" EOL, 34 + EOL_LEN,
117  "-----END CERTIFICATE OBJECT-----" EOL, 32 + EOL_LEN },
118  { CRYPT_CERTTYPE_NONE, /* Universal catch-all */
119  "-----BEGIN CERTIFICATE OBJECT-----" EOL, 34 + EOL_LEN,
120  "-----END CERTIFICATE OBJECT-----" EOL, 32 + EOL_LEN }
121  };
122 
123 /****************************************************************************
124 * *
125 * Decode Format-checking Functions *
126 * *
127 ****************************************************************************/
128 
129 /* Check for raw base64 data. There isn't a 100% reliable check that we can
130  apply for this but if the first BASE64_MIN_LINESIZE characters are all
131  valid base64 data and the first characters match the encoded form of data
132  handled by cryptlib then it's reasonably certain that it's base64 data */
133 
135 static int fixedBase64decode( STREAM *stream,
136  IN_BUFFER( srcLen ) const char *src,
137  IN_LENGTH_MIN( 10 ) const int srcLen );
138 
140 static BOOLEAN checkBase64( INOUT STREAM *stream )
141  {
142  STREAM nullStream;
144  int status;
145 
146  assert( isWritePtr( stream, sizeof( STREAM ) ) );
147 
148  /* Make sure that there's enough data present to perform a reliable
149  check */
150  status = sread( stream, buffer, BASE64_MIN_LINESIZE );
151  if( cryptStatusError( status ) )
152  return( FALSE );
153 
154  /* Make sure that the content is some form of encoded key or certificate
155  data. For certificate data that begins with 30 8x the corresponding
156  base64 values are MI...; for an SSH public key that begins 00 00 it's
157  AA...; for a PGP public key that begins 99 0x it's mQ...
158 
159  Unfortunately in the case of MIME-encoded data with a MIME header,
160  the header is likely to begin with "MIME-Version", which happens to
161  match the base64-encoded form of 30 8x = "MI", so this quick-reject
162  filter won't catch this one particular case */
163  if( memcmp( buffer, "MI", 2 ) && \
164  memcmp( buffer, "AA", 2 ) && \
165  memcmp( buffer, "mQ", 2 ) )
166  return( FALSE );
167 
168  /* Check that we have at least one minimal-length line of base64-encoded
169  data */
170  sMemNullOpen( &nullStream );
171  status = fixedBase64decode( &nullStream, buffer, BASE64_MIN_LINESIZE );
172  sMemDisconnect( &nullStream );
173  if( cryptStatusError( status ) )
174  return( FALSE );
175 
176  return( TRUE );
177  }
178 
179 /* Check for PEM-encapsulated data. All that we need to look for is the
180  '-----..' header, which is fairly simple although we also need to handle
181  the SSH '---- ...' variant (4 dashes and a space) */
182 
183 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
184 static int checkPEMHeader( INOUT STREAM *stream,
186  {
187  BOOLEAN isSSH = FALSE, isPGP = FALSE;
188  char buffer[ 1024 + 8 ], *bufPtr = buffer;
189  int length, position = DUMMY_INIT, lineCount, status;
190 
191  assert( isWritePtr( stream, sizeof( STREAM ) ) );
192  assert( isWritePtr( headerLength, sizeof( int ) ) );
193 
194  /* Clear return value */
195  *headerLength = 0;
196 
197  /* Check for the initial 5 dashes and 'BEGIN ' (unless we're SSH, in
198  which case we use 4 dashes, a space, and 'BEGIN ') */
199  status = readTextLine( ( READCHARFUNCTION ) sgetc, stream,
200  buffer, 1024, &length, NULL );
201  if( cryptStatusError( status ) )
202  return( status );
203  if( length < 5 + 6 + 7 + 5 )
204  {
205  /* We need room for at least '-----' (5) + 'BEGIN ' (6) +
206  'ABC XYZ' (7) + '-----' (5) */
207  return( CRYPT_ERROR_BADDATA );
208  }
209  if( memcmp( bufPtr, "-----BEGIN ", 11 ) && /* PEM/PGP form */
210  memcmp( bufPtr, "---- BEGIN ", 11 ) ) /* SSH form */
211  return( CRYPT_ERROR_BADDATA );
212  bufPtr += 11;
213  length -= 11;
214 
215  /* Skip the object name */
216  if( !strCompare( bufPtr, "SSH2 ", 5 ) )
217  isSSH = TRUE;
218  else
219  {
220  if( !strCompare( bufPtr, "PGP ", 4 ) )
221  isPGP = TRUE;
222  }
223  while( length >= 4 )
224  {
225  if( *bufPtr == '-' )
226  break;
227  bufPtr++;
228  length--;
229  }
230  if( length != 5 && length != 4 )
231  return( CRYPT_ERROR_BADDATA );
232 
233  /* Check the the trailing 5 (4 for SSH) dashes */
234  if( strCompare( bufPtr, "-----", length ) )
235  return( CRYPT_ERROR_BADDATA );
236 
237  /* If it's not SSH or PGP data, we're done */
238  if( !isSSH && !isPGP )
239  {
240  *headerLength = stell( stream );
241 
242  return( CRYPT_OK );
243  }
244 
245  /* At this point SSH and PGP can continue with an arbitrary number of
246  type : value pairs that we have to strip before we get to the
247  payload. SSH runs the header straight into the body so the only way
248  to tell whether we've hit the body is to check for the absence of the
249  ':' separator, while PGP uses a conventional header format with a
250  blank line as the delimiter so all that we have to do is look for a
251  zero-length line */
252  for( lineCount = 0; lineCount < FAILSAFE_ITERATIONS_MED; lineCount++ )
253  {
254  position = stell( stream );
255  status = readTextLine( ( READCHARFUNCTION ) sgetc, stream,
256  buffer, 1024, &length, NULL );
257  if( cryptStatusError( status ) )
258  return( status );
259  if( isSSH && strFindCh( buffer, length, ':' ) < 0 )
260  break;
261  if( isPGP && length <= 0 )
262  break;
263  }
264  if( lineCount >= FAILSAFE_ITERATIONS_MED )
265  return( CRYPT_ERROR_BADDATA );
266  if( isSSH )
267  {
268  /* Return to the point before the line without the ':' */
269  sseek( stream, position );
270  }
271  *headerLength = stell( stream );
272 
273  return( CRYPT_OK );
274  }
275 
276 /* Look for the EOL marker at the end of a line of text. There's one
277  problematic special case here in which, if the encoding has produced
278  bricktext, the end of the data will coincide with the EOL. For
279  CRYPT_CERTFORMAT_TEXT_CERTIFICATE this will give us '-----END...' on
280  the next line which is easy to check for, but for
281  CRYPT_ICERTFORMAT_SMIME_CERTIFICATE what we end up with depends on the
282  calling code. It could either truncate immediately at the end of the
283  data (which it isn't supposed to) so we get '\0', it could truncate after
284  the EOL (so we get EOL + '\0'), it could continue with a futher content
285  type after a blank line (so we get EOL + EOL), or it could truncate
286  without the '\0' so we get garbage, which is the caller's problem.
287  Because of this we look for all of these situations and, if any are
288  found, return a 0-count EOL indicator */
289 
291 static int checkEOL( IN_BUFFER( srcLen ) const char *src,
292  IN_LENGTH const int srcLen,
293  OUT_LENGTH_Z int *eolSize,
294  IN_ENUM( CRYPT_CERTFORMAT ) \
295  const CRYPT_CERTFORMAT_TYPE format )
296  {
297  int srcIndex = 0;
298 
299  assert( isReadPtr( src, srcLen ) );
300  assert( isWritePtr( eolSize, sizeof( int ) ) );
301 
302  REQUIRES( srcLen > 0 && srcLen < MAX_INTLENGTH );
303  REQUIRES( format > CRYPT_CERTFORMAT_NONE && \
304  format < CRYPT_CERTFORMAT_LAST );
305 
306  /* Clear return value */
307  *eolSize = 0;
308 
309  /* Check for a '\0' at the end of the data */
310  if( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE && src[ 0 ] == '\0' )
311  return( OK_SPECIAL ); /* We're at EOF, not just EOL */
312 
313  /* Check for EOL */
314  if( *src == '\n' )
315  srcIndex++;
316  else
317  {
318  if( *src == '\r' )
319  {
320  srcIndex++;
321 
322  /* Some broken implementations emit two CRs before the LF.
323  Stripping these extra CRs clashes with other broken
324  implementations that emit only CRs, which means that we'll
325  be stripping the EOT blank line in MIME encapsulation,
326  however the two-CR bug (usually from older versions of
327  Netscape) appears to be more prevalent than the CR-only
328  bug (old Mac software) */
329  if( ( srcIndex < srcLen ) && src[ srcIndex ] == '\r' )
330  srcIndex++;
331  if( ( srcIndex < srcLen ) && src[ srcIndex ] == '\n' )
332  srcIndex++;
333  }
334  }
335  if( srcIndex >= srcLen )
336  return( OK_SPECIAL ); /* We're at EOF, not just EOL */
337 
338  /* Check for '\0' or EOL (S/MIME) or '----END...' (PEM) after EOL */
339  if( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE )
340  {
341  if( src[ srcIndex ] == '\0' || src[ srcIndex ] == '\n' || \
342  src[ srcIndex ] == '\r' )
343  return( OK_SPECIAL ); /* We're at EOF, not just EOL */
344  }
345  if( format == CRYPT_CERTFORMAT_TEXT_CERTIFICATE )
346  {
347  if( srcIndex + 9 <= srcLen && \
348  !strCompare( src + srcIndex, "-----END ", 9 ) )
349  return( OK_SPECIAL ); /* We're at EOF, not just EOL */
350  }
351 
352  /* If we were expecting an EOL but didn't find one there's a problem
353  with the data */
354  if( srcIndex <= 0 )
355  return( CRYPT_ERROR_BADDATA );
356 
357  ENSURES( srcIndex > 0 && srcIndex < srcLen );
358  *eolSize = srcIndex;
359 
360  return( CRYPT_OK );
361  }
362 
363 /* Check whether a data item has a header that identifies it as some form of
364  encoded object and return the start position of the encoded data. For
365  S/MIME certificate data this can in theory get quite complex because
366  there are many possible variations in the headers. Some early S/MIME
367  agents used a content type of "application/x-pkcs7-mime",
368  "application/x-pkcs7-signature", and "application/x-pkcs10", while newer
369  ones use the same without the "x-" at the start. In addition Netscape
370  have their own MIME data types for certificates, "application/x-x509-"
371  "{user-cert|ca-cert|email-cert}, and this tradition is perpetuated by the
372  mass of further types in the neverending stream of RFCs that PKIX churns
373  out. There are a whole pile of other possible headers as well, none of
374  them terribly relevant for our purposes, so all that we check for is the
375  base64 indicator */
376 
378 int base64checkHeader( IN_BUFFER( dataLength ) const char *data,
379  IN_LENGTH const int dataLength,
380  OUT_ENUM_OPT( CRYPT_CERTFORMAT ) \
381  CRYPT_CERTFORMAT_TYPE *format,
382  OUT_LENGTH_Z int *startPos )
383  {
384  STREAM stream;
385  BOOLEAN seenTransferEncoding = FALSE, isBinaryEncoding = FALSE;
386  BOOLEAN seenDash = FALSE, isBase64;
387  int position = DUMMY_INIT, lineCount, length, status;
388 
389  assert( isReadPtr( data, dataLength ) );
390  assert( isWritePtr( format, sizeof( CRYPT_CERTFORMAT_TYPE ) ) );
391  assert( isWritePtr( startPos, sizeof( int ) ) );
392 
393  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
394 
395  /* Clear return values */
396  *format = CRYPT_CERTFORMAT_NONE;
397  *startPos = 0;
398 
399  /* If the item is too small to contain any useful data we don't even try
400  and examine it. We don't treat this as a data or underflow error
401  since it may be a short but valid data object like an empty CRL */
402  if( dataLength < 64 )
403  return( CRYPT_OK );
404 
405  sMemConnect( &stream, data, dataLength );
406 
407  /* Perform a quick check to weed out unencoded certificate data, which
408  is usually the case. Certificates and related objects are always an
409  ASN.1 SEQUENCE so if we find data that begins with this value then we
410  perform the check for a certificate object. For very large objects
411  (which can only be CRLs) we can get an overflow error trying to read
412  a short length so if the length is suspiciously long we allow a long
413  length. We don't do this unconditionally in order to reduce
414  potential false positives */
415  if( sPeek( &stream ) == BER_SEQUENCE )
416  {
417  if( dataLength < 32000L )
418  status = readSequenceI( &stream, NULL );
419  else
420  status = readLongSequence( &stream, NULL );
421  if( cryptStatusOK( status ) )
422  {
423  sMemDisconnect( &stream );
424 
425  return( CRYPT_OK );
426  }
427  sClearError( &stream );
428  sseek( &stream, 0 );
429  }
430 
431  /* Sometimes the object can be preceded by a few blank lines, which we
432  ignore */
433  for( length = 0, lineCount = 0;
434  length <= 0 && lineCount < FAILSAFE_ITERATIONS_MED;
435  lineCount++ )
436  {
437  char buffer[ 1024 + 8 ];
438 
439  position = stell( &stream );
440  status = readTextLine( ( READCHARFUNCTION ) sgetc, &stream,
441  buffer, 1024, &length, NULL );
442  if( cryptStatusError( status ) )
443  {
444  sMemDisconnect( &stream );
445  return( status );
446  }
447  if( buffer[ 0 ] == '-' )
448  seenDash = TRUE;
449  }
450  if( lineCount >= FAILSAFE_ITERATIONS_MED )
451  {
452  sMemDisconnect( &stream );
453  return( CRYPT_ERROR_BADDATA );
454  }
455  sseek( &stream, position );
456 
457  /* If the data starts with a dash check for PEM header encapsulation
458  followed by a base64-encoded body */
459  if( seenDash )
460  {
461  status = checkPEMHeader( &stream, &position );
462  if( cryptStatusError( status ) )
463  {
464  sMemDisconnect( &stream );
465  return( status );
466  }
467  if( !checkBase64( &stream ) )
468  {
469  sMemDisconnect( &stream );
470  return( CRYPT_ERROR_BADDATA );
471  }
472  sMemDisconnect( &stream );
474  *startPos = position;
475 
476  return( CRYPT_OK );
477  }
478 
479  /* Check for non-encapsulated base64 data */
480  if( checkBase64( &stream ) )
481  {
482  sMemDisconnect( &stream );
484  *startPos = position;
485 
486  return( CRYPT_OK );
487  }
488  sseek( &stream, position );
489 
490  /* It doesn't look like base64 encoded data, check for an S/MIME header */
491  for( length = 1, lineCount = 0;
492  length > 0 && lineCount < FAILSAFE_ITERATIONS_MED;
493  lineCount++ )
494  {
495  char buffer[ 1024 + 8 ];
496 
497  status = readTextLine( ( READCHARFUNCTION ) sgetc, &stream,
498  buffer, 1024, &length, NULL );
499  if( cryptStatusError( status ) )
500  {
501  sMemDisconnect( &stream );
502  return( status );
503  }
504  if( !seenTransferEncoding && length >= 33 && \
505  !strCompare( buffer, "Content-Transfer-Encoding:", 26 ) )
506  {
507  int index = strSkipWhitespace( buffer + 26, length - 26 );
508 
509  /* Check for a valid content encoding type */
510  if( index < 0 || index > 1024 - 26 )
511  continue;
512  index += 26; /* Skip "Content-Transfer-Encoding:" */
513  if( length - index < 6 )
514  {
515  /* It's too short to be a valid encoding type, skip it */
516  continue;
517  }
518  if( !strCompare( buffer + index, "base64", 6 ) )
519  seenTransferEncoding = TRUE;
520  else
521  {
522  if( !strCompare( buffer + index, "binary", 6 ) )
523  seenTransferEncoding = isBinaryEncoding = TRUE;
524  }
525  }
526  }
527  if( lineCount >= FAILSAFE_ITERATIONS_MED || !seenTransferEncoding )
528  {
529  sMemDisconnect( &stream );
530  return( CRYPT_ERROR_BADDATA );
531  }
532  position = stell( &stream );
533 
534  /* Make sure that the content is some form of encoded certificate using
535  the same check as the one that we used earlier */
536  if( isBinaryEncoding )
537  {
538  if( dataLength < 32000L )
539  status = readSequenceI( &stream, NULL );
540  else
541  status = readLongSequence( &stream, NULL );
542  sMemDisconnect( &stream );
543  if( cryptStatusError( status ) )
544  return( CRYPT_ERROR_BADDATA );
545  *startPos = position;
547 
548  return( CRYPT_OK );
549  }
550  isBase64 = checkBase64( &stream );
551  sMemDisconnect( &stream );
552  if( !isBase64 )
553  return( CRYPT_ERROR_BADDATA );
554  *startPos = position;
555  *format = CRYPT_ICERTFORMAT_SMIME_CERTIFICATE;
556 
557  return( CRYPT_OK );
558  }
559 
560 /****************************************************************************
561 * *
562 * Base64 Decoding Functions *
563 * *
564 ****************************************************************************/
565 
566 /* Decode a chunk of four base64 characters into three binary characters */
567 
569 static int decodeBase64chunk( INOUT STREAM *stream,
570  IN_BUFFER( srcLeft ) const char *src,
571  IN_LENGTH const int srcLeft,
572  const BOOLEAN fixedLenData )
573  {
574  int c0, c1, c2 = 0, c3 = 0, cx;
575  int srcIndex = 0, outByteCount, status;
576 
577  assert( isWritePtr( stream, sizeof( STREAM ) ) );
578  assert( isReadPtr( src, srcLeft ) );
579 
580  REQUIRES( srcLeft > 0 && srcLeft < MAX_INTLENGTH );
581 
582  /* Make sure that there's sufficient input left to decode. We need at
583  least two more characters to produce one byte of output */
584  if( srcLeft < 2 )
585  return( CRYPT_ERROR_UNDERFLOW );
586 
587  /* Decode a block of data from the input buffer */
588  c0 = byteToInt( decode( src[ srcIndex++ ] ) );
589  c1 = byteToInt( decode( src[ srcIndex++ ] ) );
590  if( srcLeft > 2 )
591  {
592  c2 = byteToInt( decode( src[ srcIndex++ ] ) );
593  if( srcLeft > 3 )
594  c3 = byteToInt( decode( src[ srcIndex++ ] ) );
595  }
596  cx = c0 | c1 | c2 | c3;
597  if( cx == BERR || cx == BEOF )
598  {
599  /* If we're decoding fixed-length data and the decoding produces
600  an invalid character or an EOF, there's a problem with the
601  input */
602  if( fixedLenData )
603  return( CRYPT_ERROR_BADDATA );
604 
605  /* We're decoding indefinite-length data for which EOFs are valid
606  characters. We have to be a bit careful with the order of
607  checking since hitting an EOF at an earlier character may cause
608  later input data to be decoded as BERR */
609  if( c0 == BEOF )
610  {
611  /* No more input, we're done */
612  return( OK_SPECIAL );
613  }
614  if( c0 == BERR || c1 == BEOF || c1 == BERR )
615  {
616  /* We can't produce output with only one character of input
617  data, there's a problem with the input */
618  return( CRYPT_ERROR_BADDATA );
619  }
620  if( c2 == BEOF )
621  {
622  /* Two characters of input, then EOF, resulting in one character
623  of output */
624  outByteCount = 1;
625  }
626  else
627  {
628  if( c2 == BERR || c3 == BERR )
629  return( CRYPT_ERROR_BADDATA );
630  ENSURES( c3 == BEOF );
631  outByteCount = 2;
632  }
633  }
634  else
635  {
636  /* All decoded characters are valid */
637  outByteCount = ( srcLeft > 4 ) ? 3 : srcLeft - 1;
638  }
639  ENSURES( outByteCount > 0 && outByteCount < 4 );
640 
641  /* Write the decoded data to the output buffer */
642  status = sputc( stream, ( ( c0 << 2 ) | ( c1 >> 4 ) ) & 0xFF );
643  if( outByteCount > 1 )
644  {
645  status = sputc( stream, ( ( c1 << 4 ) | ( c2 >> 2 ) ) & 0xFF );
646  if( outByteCount > 2 )
647  status = sputc( stream, ( ( c2 << 6 ) | c3 ) & 0xFF );
648  }
649  if( cryptStatusError( status ) )
650  return( status );
651 
652  /* If we've reached the end of the input, let the caller know */
653  return( ( outByteCount < 3 ) ? OK_SPECIAL : CRYPT_OK );
654  }
655 
656 /* Decode a block of binary data from the base64 format, returning the total
657  number of decoded bytes */
658 
659 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
660 static int fixedBase64decode( STREAM *stream,
661  IN_BUFFER( srcLen ) const char *src,
662  IN_LENGTH_MIN( 10 ) const int srcLen )
663  {
664  int srcIndex;
665 
666  assert( isWritePtr( stream, sizeof( STREAM ) ) );
667  assert( isReadPtr( src, srcLen ) );
668 
669  REQUIRES( srcLen >= 10 && srcLen < MAX_INTLENGTH );
670 
671  /* Decode the base64 string as a fixed-length continuous string without
672  padding or newlines. Since we're processing arbitrary-sized input we
673  can't use the usual FAILSAFE_ITERATIONS_MAX to bound the loop because
674  the input could be larger than this so we use MAX_INTLENGTH instead */
675  for( srcIndex = 0; srcIndex < srcLen && \
676  srcIndex < MAX_INTLENGTH; srcIndex += 4 )
677  {
678  int status;
679 
680  status = decodeBase64chunk( stream, src + srcIndex,
681  srcLen - srcIndex, TRUE );
682  if( cryptStatusError( status ) )
683  {
684  /* If we've reached the end of the input, we're done */
685  if( status == OK_SPECIAL )
686  break;
687 
688  return( status );
689  }
690  }
691  ENSURES( srcIndex < MAX_INTLENGTH );
692 
693  return( CRYPT_OK );
694  }
695 
696 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
697 int base64decode( OUT_BUFFER( destMaxLen, *destLen ) void *dest,
698  IN_LENGTH_MIN( 10 ) const int destMaxLen,
699  OUT_LENGTH_Z int *destLen,
700  IN_BUFFER( srcLen ) const char *src,
701  IN_LENGTH_MIN( 10 ) const int srcLen,
702  IN_ENUM_OPT( CRYPT_CERTFORMAT ) \
703  const CRYPT_CERTFORMAT_TYPE format )
704  {
705  STREAM stream;
706  int srcIndex, lineByteCount, lineSize = 0, status = DUMMY_INIT;
707 
708  assert( destMaxLen > 10 && isWritePtr( dest, destMaxLen ) );
709  assert( isWritePtr( destLen, sizeof( int ) ) );
710  assert( srcLen > 10 && isReadPtr( src, srcLen ) );
711 
712  REQUIRES( destMaxLen > 10 && destMaxLen < MAX_INTLENGTH );
713  REQUIRES( srcLen > 10 && srcLen < MAX_INTLENGTH );
714  REQUIRES( format >= CRYPT_CERTFORMAT_NONE && \
715  format < CRYPT_CERTFORMAT_LAST );
716 
717  /* Clear return values */
718  memset( dest, 0, min( 16, destMaxLen ) );
719  *destLen = 0;
720 
721  sMemOpen( &stream, dest, destMaxLen );
722 
723  /* If it's not a certificate, it's a straight base64 string and we can
724  use the simplified decoding routines */
725  if( format == CRYPT_CERTFORMAT_NONE )
726  {
727  status = fixedBase64decode( &stream, src, srcLen );
728  if( cryptStatusOK( status ) )
729  *destLen = stell( &stream );
730  sMemDisconnect( &stream );
731  return( status );
732  }
733 
734  /* Decode the encoded object. Since we're processing arbitrary-sized
735  input we can't use the usual FAILSAFE_ITERATIONS_MAX to bound the
736  loop because the input could be larger than this so we use
737  MAX_INTLENGTH instead */
738  for( srcIndex = 0, lineByteCount = 0;
739  srcIndex < srcLen && srcIndex < MAX_INTLENGTH;
740  srcIndex += 4, lineByteCount += 4 )
741  {
742  /* Depending on implementations, the length of the base64-encoded
743  line can vary from BASE64_MIN_LINESIZE to 72 characters. We
744  adjust for this by checking for the first EOL and setting the
745  line length to the size of the first line of base64 text */
746  if( lineSize <= 0 && \
747  ( src[ srcIndex ] == '\r' || src[ srcIndex ] == '\n' ) )
748  {
749  if( lineByteCount < BASE64_MIN_LINESIZE || lineByteCount > 128 )
750  {
751  /* Suspiciously short or long text line */
752  sMemDisconnect( &stream );
753  return( CRYPT_ERROR_BADDATA );
754  }
755  lineSize = lineByteCount;
756  }
757 
758  /* If we've reached the end of a line of text, look for the EOL
759  marker */
760  if( lineSize > 0 && lineByteCount >= lineSize )
761  {
762  int eolDataSize;
763 
764  status = checkEOL( src + srcIndex, srcLen - srcIndex,
765  &eolDataSize, format );
766  if( cryptStatusError( status ) )
767  {
768  /* If we get an OK_SPECIAL status it means that we've
769  reached the EOF rather than just an EOL */
770  if( status == OK_SPECIAL )
771  {
772  status = CRYPT_OK;
773  break;
774  }
775 
776  sMemDisconnect( &stream );
777  return( status );
778  }
779  srcIndex += eolDataSize;
780  lineByteCount = 0;
781  }
782 
783  /* Decode a chunk of data from the input buffer */
784  status = decodeBase64chunk( &stream, src + srcIndex,
785  srcLen - srcIndex, FALSE );
786  if( cryptStatusError( status ) )
787  {
788  /* If we've reached the end of the input, we're done. Note that
789  we can't just wait for srcIndex to pass srcLen as for the
790  fixed-length decode because there could be extra trailer data
791  following the base64 data.
792 
793  In theory we could call checkEOL() here to make sure that the
794  trailer is well-formed but if the data is truncated right on
795  the base64 end marker then this would produce an error so we
796  just stop decoding as soon as we find the end marker */
797  if( status == OK_SPECIAL )
798  {
799  status = CRYPT_OK;
800  break;
801  }
802 
803  sMemDisconnect( &stream );
804  return( status );
805  }
806  }
807  ENSURES( srcIndex < MAX_INTLENGTH );
808  if( cryptStatusOK( status ) )
809  *destLen = stell( &stream );
810  sMemDisconnect( &stream );
811 
812  return( CRYPT_OK );
813  }
814 
815 /* Calculate the size of a quantity of data once it's en/decoded */
816 
817 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
818 int base64decodeLen( IN_BUFFER( dataLength ) const char *data,
819  IN_LENGTH_MIN( 10 ) const int dataLength,
821  {
822  STREAM stream;
823  int ch, length = DUMMY_INIT, iterationCount;
824 
825  assert( isReadPtr( data, dataLength ) );
826  assert( isWritePtr( decodedLength, sizeof( int ) ) );
827 
828  REQUIRES( dataLength >= 10 && dataLength < MAX_INTLENGTH );
829 
830  /* Clear return value */
831  *decodedLength = 0;
832 
833  /* Skip ahead until we find the end of the decodable data. This ignores
834  errors on the input stream since at this point all that we're
835  interested in is how much we can decode from it and not whether it's
836  valid or not. Handling this gets a bit complicated since once the
837  stream enters an error state stell() doesn't try and return a stream
838  position any more because the stream is in the error state, so we have
839  to check the position before every read.
840 
841  Since we're processing arbitrary-sized input we can't use the usual
842  FAILSAFE_ITERATIONS_MAX to bound the loop because the input could be
843  larger than this so we use MAX_INTLENGTH instead */
844  sMemConnect( &stream, data, dataLength );
845  for( iterationCount = 0; iterationCount < MAX_INTLENGTH; iterationCount++ )
846  {
847  length = stell( &stream );
848  ch = sgetc( &stream );
849  if( cryptStatusError( ch ) || ch == BPAD )
850  break;
851  if( ch == '\r' || ch == '\n' )
852  {
853  /* Don't try and decode out-of-band data */
854  continue;
855  }
856  ch = byteToInt( decode( ch ) );
857  if( ch == BERR || ch == BEOF )
858  break;
859  }
860  ENSURES( iterationCount < MAX_INTLENGTH );
861  sMemDisconnect( &stream );
862 
863  /* Return a rough estimate of how much room the decoded data will occupy.
864  This ignores the EOL size so it always overestimates, but a strict
865  value isn't necessary since it's only used for memory buffer
866  allocation */
867  *decodedLength = ( length * 3 ) / 4;
868 
869  return( CRYPT_OK );
870  }
871 
872 /****************************************************************************
873 * *
874 * Base64 Encoding Functions *
875 * *
876 ****************************************************************************/
877 
878 /* Calculate the size of a quantity of data once it's encoded */
879 
881 int base64encodeLen( IN_LENGTH_MIN( 10 ) const int dataLength,
883  IN_ENUM_OPT( CRYPT_CERTTYPE ) \
885  {
886  int length = roundUp( ( dataLength * 4 ) / 3, 4 ), headerInfoIndex;
887 
888  assert( isWritePtr( encodedLength, sizeof( int ) ) );
889 
890  REQUIRES( dataLength >= 10 && dataLength < MAX_INTLENGTH );
891  REQUIRES( certType >= CRYPT_CERTTYPE_NONE && \
892  certType < CRYPT_CERTTYPE_LAST );
893 
894  ENSURES( length >= 10 && length < MAX_INTLENGTH );
895 
896  /* Clear return value */
897  *encodedLength = 0;
898 
899  /* Find the header/trailer info for this format */
900  for( headerInfoIndex = 0;
901  headerInfo[ headerInfoIndex ].type != certType && \
902  headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE && \
903  headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO );
904  headerInfoIndex++ );
905  ENSURES( headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO ) );
906  ENSURES( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );
907 
908  /* Calculate the extra length due to EOLs and delimiters */
909  length += ( ( roundUp( length, BASE64_LINESIZE ) / BASE64_LINESIZE ) * EOL_LEN );
910  length = headerInfo[ headerInfoIndex ].headerLen + length + \
911  headerInfo[ headerInfoIndex ].trailerLen;
912 
913  ENSURES( length > 10 && length < MAX_INTLENGTH );
914 
915  *encodedLength = length;
916 
917  return( CRYPT_OK );
918  }
919 
920 /* Encode a block of binary data into the base64 format */
921 
922 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
923 int base64encode( OUT_BUFFER( destMaxLen, *destLen ) char *dest,
924  IN_LENGTH_MIN( 10 ) const int destMaxLen,
925  OUT_LENGTH_Z int *destLen,
926  IN_BUFFER( srcLen ) const void *src,
927  IN_LENGTH_MIN( 10 ) const int srcLen,
928  IN_ENUM_OPT( CRYPT_CERTTYPE ) \
930  {
931  STREAM stream;
932  const BYTE *srcPtr = src;
933  int srcIndex, lineByteCount, remainder = srcLen % 3;
934  int headerInfoIndex = DUMMY_INIT, status = DUMMY_INIT;
935 
936  assert( destMaxLen > 10 && isWritePtr( dest, destMaxLen ) );
937  assert( isWritePtr( destLen, sizeof( int ) ) );
938  assert( srcLen >= 10 && isReadPtr( src, srcLen ) );
939 
940  REQUIRES( destMaxLen >= 10 && destMaxLen > srcLen && \
941  destMaxLen < MAX_INTLENGTH );
942  REQUIRES( srcLen >= 10 && srcLen < MAX_INTLENGTH );
943  REQUIRES( certType >= CRYPT_CERTTYPE_NONE && \
944  certType < CRYPT_CERTTYPE_LAST );
945 
946  /* Clear return values */
947  memset( dest, 0, min( 16, destMaxLen ) );
948  *destLen = 0;
949 
950  sMemOpen( &stream, dest, destMaxLen );
951 
952  /* If it's an encoded certificate object rather than raw base64 data,
953  add the header */
954  if( certType != CRYPT_CERTTYPE_NONE )
955  {
956  for( headerInfoIndex = 0;
957  headerInfo[ headerInfoIndex ].type != certType && \
958  headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE && \
959  headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO );
960  headerInfoIndex++ );
961  ENSURES( headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO ) );
962  ENSURES( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );
963  status = swrite( &stream, headerInfo[ headerInfoIndex ].header,
964  headerInfo[ headerInfoIndex ].headerLen );
965  if( cryptStatusError( status ) )
966  {
967  sMemDisconnect( &stream );
968  return( status );
969  }
970  }
971 
972  /* Encode the data */
973  for( srcIndex = 0, lineByteCount = 0;
974  srcIndex < srcLen;
975  lineByteCount += 4 )
976  {
977  const int srcLeft = srcLen - srcIndex;
978 
979  /* If we've reached the end of a line of binary data and it's a
980  certificate object rather than a raw binary blob, add the EOL
981  marker */
982  if( certType != CRYPT_CERTTYPE_NONE && \
983  lineByteCount >= BASE64_LINESIZE )
984  {
985  status = swrite( &stream, EOL, EOL_LEN );
986  if( cryptStatusError( status ) )
987  {
988  sMemDisconnect( &stream );
989  return( status );
990  }
991  lineByteCount = 0;
992  }
993 
994  /* Encode a block of data from the input buffer */
995  sputc( &stream, encode( ( srcPtr[ srcIndex ] >> 2 ) & 0x3F ) );
996  if( srcLeft < 2 )
997  {
998  REQUIRES( remainder == 1 );
999  status = sputc( &stream, encode( ( srcPtr[ srcIndex ] << 4 ) & 0x30 ) );
1000  break;
1001  }
1002  sputc( &stream, encode( ( ( srcPtr[ srcIndex ] << 4 ) & 0x30 ) | \
1003  ( ( srcPtr[ srcIndex + 1 ] >> 4 ) & 0x0F ) ) );
1004  srcIndex++;
1005  if( srcLeft < 3 )
1006  {
1007  REQUIRES( remainder == 2 );
1008  status = sputc( &stream, encode( ( srcPtr[ srcIndex ] << 2 ) & 0x3C ) );
1009  break;
1010  }
1011  sputc( &stream, encode( ( ( srcPtr[ srcIndex ] << 2 ) & 0x3C ) | \
1012  ( ( srcPtr[ srcIndex + 1 ] >> 6 ) & 0x03 ) ) );
1013  srcIndex++;
1014  status = sputc( &stream, encode( srcPtr[ srcIndex++ ] & 0x3F ) );
1015  if( cryptStatusError( status ) )
1016  break;
1017  }
1018  if( cryptStatusError( status ) )
1019  {
1020  sMemDisconnect( &stream );
1021  return( status );
1022  }
1023 
1024  /* If it's a certificate object, add any required padding and the
1025  trailer */
1026  if( certType != CRYPT_CERTTYPE_NONE )
1027  {
1028  /* Add any necessary padding. For 0 bytes of remainder there's no
1029  padding (the data fits exactly), for 1 byte of remainder there's
1030  2 bytes of padding ("X=="), and for 2 bytes of remainder there's
1031  1 byte of padding ("XX=") */
1032  if( remainder > 0 )
1033  {
1034  status = sputc( &stream, BPAD );
1035  if( remainder == 1 )
1036  status = sputc( &stream, BPAD );
1037  if( cryptStatusError( status ) )
1038  {
1039  sMemDisconnect( &stream );
1040  return( status );
1041  }
1042  }
1043 
1044  /* Add the trailer */
1045  swrite( &stream, EOL, EOL_LEN );
1046  status = swrite( &stream, headerInfo[ headerInfoIndex ].trailer,
1047  headerInfo[ headerInfoIndex ].trailerLen );
1048  if( cryptStatusError( status ) )
1049  {
1050  sMemDisconnect( &stream );
1051  return( status );
1052  }
1053  }
1054  *destLen = stell( &stream );
1055  sMemDisconnect( &stream );
1056 
1057  return( CRYPT_OK );
1058  }