cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cmp_tcp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib CMP TCP transport Routines *
4 * Copyright Peter Gutmann 2000-2002 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "stream.h"
11 #else
12  #include "crypt.h"
13  #include "io/stream.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_CMP_TRANSPORT
17 
18 /****************************************************************************
19 * *
20 * Utility Functions *
21 * *
22 ****************************************************************************/
23 
24 /* Read and write the CMP-over-TCP header, which kludges on extra bits and
25  pieces which were left out of CMP itself. The TCP protocol version isn't
26  really 10, this is a kludge to work around the fact that the original RFC
27  2510 protocol doesn't work properly so it was necessary to create an
28  artificially huge version number to ensure non-compatibility with earlier
29  implementations (this really says it all for the design of CMP as a
30  whole) */
31 
32 #define CMP_TCP_VERSION 10 /* CMP-over-TCP version */
33 #define CMP_HEADER_SIZE 7 /* Header overall size */
34 #define CMP_MIN_PACKET_SIZE 7 /* Hdr.payload size + error packet */
35 
36 enum { CMPMSG_PKIREQ, CMPMSG_POLLREP, CMPMSG_POLLREQ, CMPMSG_FINREP,
37  CMPMSG_DUMMY, CMPMSG_PKIREP, CMPMSG_ERRORMSGREP };
38 
39 static int writeHeader( BYTE *buffer, const int length,
40  const BOOLEAN lastMessage )
41  {
42  BYTE *bufPtr = buffer;
43  const long lengthVal = length + 3;
44 
45  /* Write the header:
46  LONG: length
47  BYTE: version = 10
48  BYTE: flags = lastMessage
49  BYTE: message type = 0
50  BYTE[]: data */
51  mputLong( bufPtr, lengthVal );
52  *bufPtr++ = CMP_TCP_VERSION;
53  *bufPtr++ = lastMessage;
54  *bufPtr++ = CMPMSG_PKIREQ;
55 
56  return( CMP_HEADER_SIZE );
57  }
58 
59 static int readHeader( STREAM *stream, BYTE *buffer, int *length,
60  const int maxLength )
61  {
62  BYTE *bufPtr = buffer;
63  int headerType, status;
64  long headerLength;
65 
66  /* Clear return value */
67  *length = CRYPT_ERROR;
68 
69  /* Read the fixed-length header fields */
70  status = stream->bufferedTransportReadFunction( stream, bufPtr,
71  CMP_HEADER_SIZE,
73  if( cryptStatusError( status ) )
74  return( status );
75  headerLength = mgetLong( bufPtr );
76  if( headerLength < CMP_MIN_PACKET_SIZE || headerLength > maxLength || \
77  *bufPtr++ != CMP_TCP_VERSION )
78  return( CRYPT_ERROR_BADDATA );
79  if( *bufPtr++ != 0 )
80  {
81  /* This is the last message, close the connection */
82  sioctlSet( stream, STREAM_IOCTL_CONNSTATE, FALSE );
83  }
84  headerType = *bufPtr++;
85  if( headerType < CMPMSG_PKIREQ || headerType > CMPMSG_ERRORMSGREP )
86  return( CRYPT_ERROR_BADDATA );
87  assert( CMP_MIN_PACKET_SIZE > 3 );
88  headerLength -= 3;
89 
90  /* Handle individual header types */
91  if( headerType == CMPMSG_PKIREQ || headerType == CMPMSG_PKIREP )
92  {
93  /* It's a normal reply, return the length of the payload */
94  *length = headerLength;
95  return( CRYPT_OK );
96  }
97  if( headerType == CMPMSG_ERRORMSGREP )
98  {
99  int unknownDataLength;
100 
101  /* Read as much of the error status info as we can:
102  WORD: error code
103  WORD: unknownDataLength
104  BYTE[]: unknownData
105  BYTE[]: error string filling remainder of packet
106 
107  Because of the braindamaged packet format we have to jump through
108  various hoops to correctly handle data lengths in the face of a
109  hostile adversary. First we read the error contents and shrink
110  the payload length value by that amount. If the result is
111  positive, we're still within the read data, and copy what we've
112  got out as the error message. If not, there's a problem
113  (probably due to a bogus unknownDataLength) and we substitute a
114  generic error message.
115 
116  Unfortunately though, we can't even safely do this. Since the
117  protocol kludges an unauthenticated wrapper around the carefully
118  signed or MAC'd main CMP protocol, it's possible for an attacker
119  to manipulate the CMP-over-TCP layer to do things like redirect
120  users to bogus CAs via error messages spoofed from the real CA
121  (and if your client supports send-the-private-key-to-the-CA as
122  some do, you're in real trouble). As a result we don't trust any
123  unauthenticated CMP-over-TCP messages, but simply report a
124  transport protocol problem. Given the hit-and-miss nature of
125  implementations of this protocol, it's probably not going to make
126  things much worse than it would be if we tried to do it properly */
127  bufPtr = buffer;
128  status = stream->bufferedTransportReadFunction( stream, bufPtr,
129  headerLength,
131  if( cryptStatusError( status ) )
132  return( status );
133  stream->errorInfo->errorCode = mgetWord( bufPtr );
134  unknownDataLength = mgetWord( bufPtr );
135  if( unknownDataLength < 0 )
136  return( CRYPT_ERROR_BADDATA );
137 #if 0
138  headerLength -= sizeof( WORD ) + sizeof( WORD ) + unknownDataLength;
139  if( headerLength > 0 )
140  {
141  const int errorMessageLength = \
142  min( headerLength, MAX_ERRMSG_SIZE - 1 );
143 
144  bufPtr += unknownDataLength; /* Skip unknown data block */
145  memcpy( stream->errorInfo->errorMessage, bufPtr,
146  errorMessageLength );
147  stream->errorInfo->errorMessage[ errorMessageLength ] = '\0';
148  }
149  else
150 #endif /* 0 */
151  strlcpy_s( stream->errorInfo->errorString, MAX_ERRMSG_SIZE,
152  "CMP transport-level protocol error encountered" );
153 
154  /* The appropriate status values to return for a problem at this
155  level are pretty unclear, the most appropriate ones appear to be
156  a read error if there's a problem with the server (exactly what
157  the problem is is never specified in the error code) and a generic
158  bad data for anything else */
159  return( ( ( stream->errorInfo->errorCode & 0x0F00 ) == 0x0300 ) ? \
161  }
162 
163  /* It's something weird which we don't handle */
164  return( CRYPT_ERROR_BADDATA );
165  }
166 
167 /****************************************************************************
168 * *
169 * CMP Access Functions *
170 * *
171 ****************************************************************************/
172 
173 /* Read data from a CMP stream */
174 
175 static int readFunction( STREAM *stream, void *buffer, int length )
176  {
177  int localLength, status;
178 
179  /* Read the CMP packet header */
180  status = readHeader( stream, buffer, &localLength, length );
181  if( cryptStatusError( status ) )
182  return( status );
183 
184  /* Read the payload data from the client/server */
185  return( stream->bufferedTransportReadFunction( stream, buffer,
186  localLength,
188  }
189 
190 /* Write data to a CMP stream */
191 
192 static int writeFunction( STREAM *stream, const void *buffer,
193  const int length )
194  {
195  BYTE headerBuffer[ 64 + 8 ];
196  int headerLength, status;
197 
198  /* Write the CMP packet header */
199  headerLength = writeHeader( headerBuffer, length,
200  ( stream->flags & STREAM_NFLAG_LASTMSG ) ? \
201  TRUE : FALSE );
202  status = stream->bufferedTransportWriteFunction( stream, headerBuffer,
203  headerLength,
205  if( cryptStatusError( status ) )
206  return( status );
207 
208  /* Send the payload data to the client/server */
209  return( stream->bufferedTransportWriteFunction( stream, buffer, length,
211  }
212 
213 int setStreamLayerCMP( STREAM *stream )
214  {
215  /* Set the access method pointers */
216  stream->writeFunction = writeFunction;
217  stream->readFunction = readFunction;
218 
219  /* The CMP-over-TCP kludge provides its own data-size and flow-control
220  indicators so we don't want the higher-level code to try and do this
221  for us */
222  stream->flags |= STREAM_NFLAG_ENCAPS;
223 
224  return( CRYPT_OK );
225  }
226 #endif /* USE_CMP_TRANSPORT */