1 /****************************************************************************
2 *																			*
3 *						cryptlib Session Attribute Routines					*
4 *						Copyright Peter Gutmann 1998-2011					*
5 *																			*
6 ****************************************************************************/
7 
8 #include <stdio.h>
9 #include "crypt.h"
10 #ifdef INC_ALL
11   #include "session.h"
12 #else
13   #include "session/session.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_SESSIONS
17 
18 /****************************************************************************
19 *																			*
20 *								Utility Functions							*
21 *																			*
22 ****************************************************************************/
23 
24 /* Exit after setting extended error information */
25 
26 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exitError(INOUT SESSION_INFO * sessionInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,IN_ENUM (CRYPT_ERRTYPE)const CRYPT_ERRTYPE_TYPE errorType,IN_ERROR const int status)27 static int exitError( INOUT SESSION_INFO *sessionInfoPtr,
28 					  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
29 					  IN_ENUM( CRYPT_ERRTYPE ) const CRYPT_ERRTYPE_TYPE errorType,
30 					  IN_ERROR const int status )
31 	{
32 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
33 
34 	REQUIRES( isAttribute( errorLocus ) || \
35 			  isInternalAttribute( errorLocus ) );
36 	REQUIRES( errorType > CRYPT_ERRTYPE_NONE && \
37 			  errorType < CRYPT_ERRTYPE_LAST );
38 	REQUIRES( cryptStatusError( status ) );
39 
40 	setErrorInfo( sessionInfoPtr, errorLocus, errorType );
41 	return( status );
42 	}
43 
44 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exitErrorInited(INOUT SESSION_INFO * sessionInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus)45 static int exitErrorInited( INOUT SESSION_INFO *sessionInfoPtr,
46 							IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
47 	{
48 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
49 
50 	REQUIRES( isAttribute( errorLocus ) || \
51 			  isInternalAttribute( errorLocus ) );
52 
53 	return( exitError( sessionInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
54 					   CRYPT_ERROR_INITED ) );
55 	}
56 
57 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exitErrorNotInited(INOUT SESSION_INFO * sessionInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus)58 static int exitErrorNotInited( INOUT SESSION_INFO *sessionInfoPtr,
59 							   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
60 	{
61 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
62 
63 	REQUIRES( isAttribute( errorLocus ) || \
64 			  isInternalAttribute( errorLocus ) );
65 
66 	return( exitError( sessionInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
67 					   CRYPT_ERROR_NOTINITED ) );
68 	}
69 
70 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exitErrorNotFound(INOUT SESSION_INFO * sessionInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus)71 static int exitErrorNotFound( INOUT SESSION_INFO *sessionInfoPtr,
72 							  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
73 	{
74 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
75 
76 	REQUIRES( isAttribute( errorLocus ) || \
77 			  isInternalAttribute( errorLocus ) );
78 
79 	return( exitError( sessionInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
80 					   CRYPT_ERROR_NOTFOUND ) );
81 	}
82 
83 /* Add the contents of an encoded URL to a session.  This requires parsing
84    the individual session attribute components out of the URL and then
85    adding each one in turn */
86 
87 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
addUrl(INOUT SESSION_INFO * sessionInfoPtr,IN_BUFFER (urlLength)const void * url,IN_LENGTH_DNS const int urlLength)88 static int addUrl( INOUT SESSION_INFO *sessionInfoPtr,
89 				   IN_BUFFER( urlLength ) const void *url,
90 				   IN_LENGTH_DNS const int urlLength )
91 	{
92 	const PROTOCOL_INFO *protocolInfoPtr = sessionInfoPtr->protocolInfo;
93 	URL_INFO urlInfo;
94 	int status;
95 
96 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
97 	assert( isReadPtr( url, urlLength ) );
98 
99 	REQUIRES( urlLength > 0 && urlLength < MAX_URL_SIZE );
100 
101 	/* If there's already a transport session or network socket specified
102 	   then we can't set a server name as well */
103 	if( sessionInfoPtr->transportSession != CRYPT_ERROR )
104 		return( exitErrorInited( sessionInfoPtr, CRYPT_SESSINFO_SESSION ) );
105 	if( sessionInfoPtr->networkSocket != CRYPT_ERROR )
106 		return( exitErrorInited( sessionInfoPtr,
107 								 CRYPT_SESSINFO_NETWORKSOCKET ) );
108 
109 	/* Parse the server name.  The PKI protocols all use HTTP as their
110 	   substrate so if it's not SSH or SSL/TLS we require HTTP */
111 	status = sNetParseURL( &urlInfo, url, urlLength,
112 						   ( sessionInfoPtr->type == CRYPT_SESSION_SSH ) ? \
113 								URL_TYPE_SSH : \
114 						   ( sessionInfoPtr->type == CRYPT_SESSION_SSL ) ? \
115 								URL_TYPE_HTTPS : URL_TYPE_HTTP );
116 	if( cryptStatusError( status ) )
117 		return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
118 						   CRYPT_ERRTYPE_ATTR_VALUE, CRYPT_ARGERROR_STR1 ) );
119 
120 	/* We can only use autodetection with PKI services */
121 	if( urlInfo.hostLen == 12 && \
122 		!strCompare( urlInfo.host, "[Autodetect]", urlInfo.hostLen ) && \
123 		!protocolInfoPtr->isReqResp )
124 		return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
125 						   CRYPT_ERRTYPE_ATTR_VALUE, CRYPT_ARGERROR_STR1 ) );
126 
127 	/* Remember the server name */
128 	if( urlInfo.hostLen + urlInfo.locationLen >= MAX_URL_SIZE )
129 		{
130 		/* This should never happen since the overall URL size has to be
131 		   less than MAX_URL_SIZE */
132 		assert( INTERNAL_ERROR );
133 		return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
134 						   CRYPT_ERRTYPE_ATTR_VALUE, CRYPT_ARGERROR_STR1 ) );
135 		}
136 	if( ( sessionInfoPtr->protocolInfo->flags & SESSION_ISHTTPTRANSPORT ) && \
137 		urlInfo.locationLen > 0 )
138 		{
139 		char urlBuffer[ MAX_URL_SIZE + 8 ];
140 
141 		/* We only remember the location if the session uses HTTP transport.
142 		   This is to deal with situations where the caller specifies a URL
143 		   like https://www.server.com/index.html for an SSL session, which
144 		   should be treated as valid even though it's not really a pure
145 		   FQDN */
146 		ENSURES( rangeCheck( urlInfo.hostLen, urlInfo.locationLen,
147 							 MAX_URL_SIZE ) );
148 		memcpy( urlBuffer, urlInfo.host, urlInfo.hostLen );
149 		memcpy( urlBuffer + urlInfo.hostLen, urlInfo.location,
150 				urlInfo.locationLen );
151 		status = addSessionInfoS( &sessionInfoPtr->attributeList,
152 								  CRYPT_SESSINFO_SERVER_NAME, urlBuffer,
153 								  urlInfo.hostLen + urlInfo.locationLen );
154 		}
155 	else
156 		{
157 		status = addSessionInfoS( &sessionInfoPtr->attributeList,
158 								  CRYPT_SESSINFO_SERVER_NAME,
159 								  urlInfo.host, urlInfo.hostLen );
160 		}
161 	if( cryptStatusError( status ) )
162 		return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
163 						   CRYPT_ERRTYPE_ATTR_VALUE, CRYPT_ARGERROR_STR1 ) );
164 
165 	/* If there's a port or user name specified in the URL, remember them.
166 	   We have to add the user name after we add any other attributes
167 	   because it's paired with a password, so adding the user name and then
168 	   following it with something that isn't a password will cause an error
169 	   return */
170 	if( urlInfo.port > 0 )
171 		{
172 		( void ) krnlSendMessage( sessionInfoPtr->objectHandle,
173 								  IMESSAGE_DELETEATTRIBUTE, NULL,
174 								  CRYPT_SESSINFO_SERVER_PORT );
175 		status = krnlSendMessage( sessionInfoPtr->objectHandle,
176 								  IMESSAGE_SETATTRIBUTE, &urlInfo.port,
177 								  CRYPT_SESSINFO_SERVER_PORT );
178 		}
179 	if( cryptStatusOK( status ) && urlInfo.userInfoLen > 0 )
180 		{
181 		MESSAGE_DATA userInfoMsgData;
182 
183 		( void ) krnlSendMessage( sessionInfoPtr->objectHandle,
184 								  IMESSAGE_DELETEATTRIBUTE, NULL,
185 								  CRYPT_SESSINFO_USERNAME );
186 		setMessageData( &userInfoMsgData, ( MESSAGE_CAST ) urlInfo.userInfo,
187 						urlInfo.userInfoLen );
188 		status = krnlSendMessage( sessionInfoPtr->objectHandle,
189 								  IMESSAGE_SETATTRIBUTE_S, &userInfoMsgData,
190 								  CRYPT_SESSINFO_USERNAME );
191 		}
192 	if( cryptStatusError( status ) )
193 		return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
194 						   CRYPT_ERRTYPE_ATTR_VALUE, CRYPT_ARGERROR_STR1 ) );
195 
196 	/* Remember the transport type */
197 	if( sessionInfoPtr->protocolInfo->flags & SESSION_ISHTTPTRANSPORT )
198 		sessionInfoPtr->flags |= SESSION_ISHTTPTRANSPORT;
199 
200 	return( CRYPT_OK );
201 	}
202 
203 /****************************************************************************
204 *																			*
205 *								Get Attributes								*
206 *																			*
207 ****************************************************************************/
208 
209 /* Get a numeric/boolean attribute */
210 
211 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getSessionAttribute(INOUT SESSION_INFO * sessionInfoPtr,OUT_INT_Z int * valuePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute)212 int getSessionAttribute( INOUT SESSION_INFO *sessionInfoPtr,
213 						 OUT_INT_Z int *valuePtr,
214 						 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
215 	{
216 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
217 	assert( isWritePtr( valuePtr, sizeof( int ) ) );
218 
219 	REQUIRES( isAttribute( attribute ) || \
220 			  isInternalAttribute( attribute ) );
221 
222 	/* Clear return value */
223 	*valuePtr = 0;
224 
225 	/* Handle the various information types */
226 	switch( attribute )
227 		{
228 		case CRYPT_ATTRIBUTE_CURRENT:
229 		case CRYPT_ATTRIBUTE_CURRENT_GROUP:
230 			{
231 			CRYPT_ATTRIBUTE_TYPE attributeID;
232 			int status;
233 
234 			status = getSessionAttributeCursor( sessionInfoPtr->attributeList,
235 									sessionInfoPtr->attributeListCurrent,
236 									attribute, &attributeID );
237 			if( status == OK_SPECIAL )
238 				{
239 				/* The attribute list wasn't initialised yet, initialise it
240 				   now */
241 				sessionInfoPtr->attributeListCurrent = \
242 										sessionInfoPtr->attributeList;
243 				}
244 			else
245 				{
246 				if( cryptStatusError( status ) )
247 					return( exitError( sessionInfoPtr, attribute,
248 									   CRYPT_ERRTYPE_ATTR_ABSENT, status ) );
249 				}
250 			*valuePtr = attributeID;
251 
252 			return( CRYPT_OK );
253 			}
254 
255 		case CRYPT_OPTION_NET_CONNECTTIMEOUT:
256 			if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
257 				return( exitErrorNotInited( sessionInfoPtr,
258 											CRYPT_OPTION_NET_CONNECTTIMEOUT ) );
259 			*valuePtr = sessionInfoPtr->connectTimeout;
260 			return( CRYPT_OK );
261 
262 		case CRYPT_OPTION_NET_READTIMEOUT:
263 			if( sessionInfoPtr->readTimeout == CRYPT_ERROR )
264 				return( exitErrorNotInited( sessionInfoPtr,
265 											CRYPT_OPTION_NET_READTIMEOUT ) );
266 			*valuePtr = sessionInfoPtr->readTimeout;
267 			return( CRYPT_OK );
268 
269 		case CRYPT_OPTION_NET_WRITETIMEOUT:
270 			if( sessionInfoPtr->writeTimeout == CRYPT_ERROR )
271 				return( exitErrorNotInited( sessionInfoPtr,
272 											CRYPT_OPTION_NET_WRITETIMEOUT ) );
273 			*valuePtr = sessionInfoPtr->writeTimeout;
274 			return( CRYPT_OK );
275 
276 		case CRYPT_ATTRIBUTE_ERRORTYPE:
277 			*valuePtr = sessionInfoPtr->errorType;
278 			return( CRYPT_OK );
279 
280 		case CRYPT_ATTRIBUTE_ERRORLOCUS:
281 			*valuePtr = sessionInfoPtr->errorLocus;
282 			return( CRYPT_OK );
283 
284 		case CRYPT_ATTRIBUTE_BUFFERSIZE:
285 			*valuePtr = sessionInfoPtr->receiveBufSize;
286 			return( CRYPT_OK );
287 
288 		case CRYPT_SESSINFO_ACTIVE:
289 			/* Only secure transport sessions can be persistently active,
290 			   request/response sessions are only active while the
291 			   transaction is in progress.  Note that this differs from the
292 			   connection-active state below, which records the fact that
293 			   there's a network-level connection established but not whether
294 			   there's any messages or a secure session active across it.
295 			   See the comment in setSessionAttribute() for more on this */
296 			*valuePtr = sessionInfoPtr->iCryptInContext != CRYPT_ERROR && \
297 						( sessionInfoPtr->flags & SESSION_ISOPEN ) ? \
298 						TRUE : FALSE;
299 			return( CRYPT_OK );
300 
301 		case CRYPT_SESSINFO_CONNECTIONACTIVE:
302 			*valuePtr = ( sessionInfoPtr->flags & SESSION_ISOPEN ) ? \
303 						TRUE : FALSE;
304 			return( CRYPT_OK );
305 
306 		case CRYPT_SESSINFO_SERVER_PORT:
307 		case CRYPT_SESSINFO_CLIENT_PORT:
308 			{
309 			const ATTRIBUTE_LIST *attributeListPtr = \
310 							findSessionInfo( sessionInfoPtr->attributeList,
311 											 attribute );
312 			if( attributeListPtr == NULL )
313 				return( exitErrorNotInited( sessionInfoPtr, attribute ) );
314 			*valuePtr = attributeListPtr->intValue;
315 			return( CRYPT_OK );
316 			}
317 
318 		case CRYPT_SESSINFO_VERSION:
319 			*valuePtr = sessionInfoPtr->version;
320 			return( CRYPT_OK );
321 
322 		case CRYPT_SESSINFO_AUTHRESPONSE:
323 			if( sessionInfoPtr->authResponse == AUTHRESPONSE_NONE )
324 				return( exitErrorNotFound( sessionInfoPtr,
325 										   CRYPT_SESSINFO_AUTHRESPONSE ) );
326 			*valuePtr = \
327 				( sessionInfoPtr->authResponse == AUTHRESPONSE_SUCCESS ) ? \
328 				TRUE : FALSE;
329 			return( CRYPT_OK );
330 		}
331 
332 	retIntError();
333 	}
334 
335 /* Get a string attribute */
336 
337 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getSessionAttributeS(INOUT SESSION_INFO * sessionInfoPtr,INOUT MESSAGE_DATA * msgData,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute)338 int getSessionAttributeS( INOUT SESSION_INFO *sessionInfoPtr,
339 						  INOUT MESSAGE_DATA *msgData,
340 						  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
341 	{
342 	const ATTRIBUTE_LIST *attributeListPtr;
343 
344 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
345 	assert( isWritePtr( msgData, sizeof( MESSAGE_DATA ) ) );
346 
347 	/* Handle the various information types */
348 	switch( attribute )
349 		{
350 		case CRYPT_OPTION_NET_SOCKS_SERVER:
351 		case CRYPT_OPTION_NET_SOCKS_USERNAME:
352 		case CRYPT_OPTION_NET_HTTP_PROXY:
353 			/* These aren't implemented on a per-session level yet since
354 			   they're almost never user */
355 			return( exitErrorNotFound( sessionInfoPtr, attribute ) );
356 
357 		case CRYPT_ATTRIBUTE_ERRORMESSAGE:
358 			{
359 #ifdef USE_ERRMSGS
360 			ERROR_INFO *errorInfo = &sessionInfoPtr->errorInfo;
361 
362 			if( errorInfo->errorStringLength > 0 )
363 				{
364 				return( attributeCopy( msgData, errorInfo->errorString,
365 									   errorInfo->errorStringLength ) );
366 				}
367 #endif /* USE_ERRMSGS */
368 
369 			/* We don't set extended error information for this atribute
370 			   because it's usually read in response to an existing error,
371 			   which would overwrite the existing error information */
372 			return( CRYPT_ERROR_NOTFOUND );
373 			}
374 
375 		case CRYPT_SESSINFO_USERNAME:
376 		case CRYPT_SESSINFO_PASSWORD:
377 		case CRYPT_SESSINFO_SERVER_FINGERPRINT_SHA1:
378 		case CRYPT_SESSINFO_SERVER_NAME:
379 		case CRYPT_SESSINFO_CLIENT_NAME:
380 			attributeListPtr = findSessionInfo( sessionInfoPtr->attributeList,
381 												attribute );
382 			if( attributeListPtr == NULL )
383 				return( exitErrorNotInited( sessionInfoPtr, attribute ) );
384 			return( attributeCopy( msgData, attributeListPtr->value,
385 								   attributeListPtr->valueLength ) );
386 		}
387 
388 	retIntError();
389 	}
390 
391 /****************************************************************************
392 *																			*
393 *								Set Attributes								*
394 *																			*
395 ****************************************************************************/
396 
397 /* Set a numeric/boolean attribute */
398 
399 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setSessionAttribute(INOUT SESSION_INFO * sessionInfoPtr,IN const int value,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute)400 int setSessionAttribute( INOUT SESSION_INFO *sessionInfoPtr,
401 						 IN const int value,
402 						 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
403 	{
404 	int status;
405 
406 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
407 
408 	REQUIRES( ( attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
409 				attribute == CRYPT_ATTRIBUTE_CURRENT ) ||
410 				/* CURRENT = cursor positioning code */
411 			  ( attribute == CRYPT_SESSINFO_NETWORKSOCKET ) ||
412 				/* Socket = non-typed value */
413 			  ( value >= 0 && value < MAX_INTLENGTH ) );
414 	REQUIRES( isAttribute( attribute ) || \
415 			  isInternalAttribute( attribute ) );
416 
417 	/* Handle the various information types */
418 	switch( attribute )
419 		{
420 		case CRYPT_ATTRIBUTE_CURRENT:
421 		case CRYPT_ATTRIBUTE_CURRENT_GROUP:
422 			{
423 			ATTRIBUTE_LIST *attributeListPtr = \
424 									sessionInfoPtr->attributeListCurrent;
425 
426 			REQUIRES( value >= CRYPT_CURSOR_LAST && \
427 					  value <= CRYPT_CURSOR_FIRST );	/* Values are -ve */
428 			status = setSessionAttributeCursor( sessionInfoPtr->attributeList,
429 										&attributeListPtr, attribute, value );
430 			if( cryptStatusError( status ) )
431 				return( exitError( sessionInfoPtr, attribute,
432 								   CRYPT_ERRTYPE_ATTR_ABSENT, status ) );
433 			sessionInfoPtr->attributeListCurrent = attributeListPtr;
434 			return( CRYPT_OK );
435 			}
436 
437 		case CRYPT_OPTION_NET_CONNECTTIMEOUT:
438 			sessionInfoPtr->connectTimeout = value;
439 			return( CRYPT_OK );
440 
441 		case CRYPT_OPTION_NET_READTIMEOUT:
442 			sessionInfoPtr->readTimeout = value;
443 			return( CRYPT_OK );
444 
445 		case CRYPT_OPTION_NET_WRITETIMEOUT:
446 			sessionInfoPtr->writeTimeout = value;
447 			return( CRYPT_OK );
448 
449 		case CRYPT_ATTRIBUTE_BUFFERSIZE:
450 			REQUIRES( !( sessionInfoPtr->flags & SESSION_ISOPEN ) );
451 
452 			sessionInfoPtr->receiveBufSize = value;
453 			return( CRYPT_OK );
454 
455 		case CRYPT_SESSINFO_ACTIVE:
456 			{
457 			CRYPT_ATTRIBUTE_TYPE missingInfo;
458 
459 			/* Session state and persistent sessions are handled as follows:
460 			   The CRYPT_SESSINFO_ACTIVE attribute records the active state
461 			   of the session as a whole, and the CRYPT_SESSINFO_-
462 			   CONNECTIONACTIVE attribute records the state of the
463 			   underlying comms session.  Setting CRYPT_SESSINFO_ACTIVE for
464 			   the first time activates the comms session and leaves it
465 			   active if the underlying mechanism (e.g. HTTP 1.1 persistent
466 			   connections) supports it.  The CRYPT_SESSINFO_ACTIVE
467 			   attribute is reset once the transaction completes, and
468 			   further transactions can be initiated as long as
469 			   CRYPT_SESSINFO_CONNECTIONACTIVE is set:
470 
471 										Obj.state	_active		_connactive
472 										---------	-------		-----------
473 				create						0			0			0
474 				setattr						0			0			0
475 					(clear out_param)
476 				activate					1		0 -> 1 -> 0		1
477 					(clear in_param)
478 				setattr						1			0			1
479 					(clear out_param)
480 				activate					1		0 -> 1 -> 0		1
481 					(clear in_param)
482 					(peer closes conn)		1			0			0
483 				setattr							CRYPT_ERROR_COMPLETE */
484 			if( value == FALSE )
485 				return( CRYPT_OK );	/* No-op */
486 
487 			/* If the session is in the partially-open state while we wait
488 			   for the caller to allow or disallow the session authentication
489 			   they have to provide a clear yes or no indication by setting
490 			   CRYPT_SESSINFO_AUTHRESPONSE to TRUE or FALSE before they can
491 			   try to continue the session activation */
492 			if( ( sessionInfoPtr->flags & SESSION_PARTIALOPEN ) && \
493 				sessionInfoPtr->authResponse == AUTHRESPONSE_NONE )
494 				return( exitErrorNotInited( sessionInfoPtr,
495 										    CRYPT_SESSINFO_AUTHRESPONSE ) );
496 
497 			/* Make sure that all of the information that we need to proceed
498 			   is present */
499 			missingInfo = checkMissingInfo( sessionInfoPtr->attributeList,
500 								isServer( sessionInfoPtr ) ? TRUE : FALSE );
501 			if( missingInfo != CRYPT_ATTRIBUTE_NONE )
502 				return( exitErrorNotInited( sessionInfoPtr, missingInfo ) );
503 
504 			status = activateSession( sessionInfoPtr );
505 			if( cryptArgError( status ) )
506 				{
507 				/* Catch leaked low-level status values.  The session
508 				   management code does a large amount of work involving
509 				   other cryptlib objects so it's possible that an
510 				   unexpected failure at some point will leak through an
511 				   inappropriate status value */
512 				DEBUG_DIAG(( "Session activate returned argError status" ));
513 				assert( DEBUG_WARN );
514 				status = CRYPT_ERROR_FAILED;
515 				}
516 			return( status );
517 			}
518 
519 		case CRYPT_SESSINFO_SERVER_PORT:
520 			/* If there's already a transport session or network socket
521 			   specified then we can't set a port as well */
522 			if( sessionInfoPtr->transportSession != CRYPT_ERROR )
523 				return( exitErrorInited( sessionInfoPtr,
524 										 CRYPT_SESSINFO_SESSION ) );
525 			if( sessionInfoPtr->networkSocket != CRYPT_ERROR )
526 				return( exitErrorInited( sessionInfoPtr,
527 										 CRYPT_SESSINFO_NETWORKSOCKET ) );
528 
529 			return( addSessionInfo( &sessionInfoPtr->attributeList,
530 									CRYPT_SESSINFO_SERVER_PORT, value ) );
531 
532 		case CRYPT_SESSINFO_VERSION:
533 			if( value < sessionInfoPtr->protocolInfo->minVersion || \
534 				value > sessionInfoPtr->protocolInfo->maxVersion )
535 				return( CRYPT_ARGERROR_VALUE );
536 			sessionInfoPtr->version = value;
537 			return( CRYPT_OK );
538 
539 		case CRYPT_SESSINFO_PRIVATEKEY:
540 			{
541 			const int requiredAttributeFlags = isServer( sessionInfoPtr ) ? \
542 								sessionInfoPtr->serverReqAttrFlags : \
543 								sessionInfoPtr->clientReqAttrFlags;
544 
545 			/* Make sure that it's a private key */
546 			status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
547 									  MESSAGE_CHECK_PKC_PRIVATE );
548 			if( cryptStatusError( status ) )
549 				{
550 				if( sessionInfoPtr->type != CRYPT_SESSION_SSL )
551 					return( CRYPT_ARGERROR_NUM1 );
552 
553 				/* SSL can also do key agreement-based key exchange so we
554 				   fall back to this if key transport-based exchange isn't
555 				   possible */
556 				status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
557 										  MESSAGE_CHECK_PKC_KA_EXPORT );
558 				if( cryptStatusError( status ) )
559 					return( CRYPT_ARGERROR_NUM1 );
560 				}
561 
562 			/* If we need a private key with certain capabilities, make sure
563 			   that it has these capabilities.  This is a more specific check
564 			   than that allowed by the kernel ACLs */
565 			if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYSIGN )
566 				{
567 				status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
568 										  MESSAGE_CHECK_PKC_SIGN );
569 				if( cryptStatusError( status ) )
570 					{
571 					setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
572 								  CRYPT_ERRTYPE_ATTR_VALUE );
573 					return( CRYPT_ARGERROR_NUM1 );
574 					}
575 				}
576 			if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYCRYPT )
577 				{
578 				status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
579 										  MESSAGE_CHECK_PKC_DECRYPT );
580 				if( cryptStatusError( status ) )
581 					{
582 					setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
583 								  CRYPT_ERRTYPE_ATTR_VALUE );
584 					return( CRYPT_ARGERROR_NUM1 );
585 					}
586 				}
587 
588 			/* If we need a private key with a certificate, make sure that
589 			   the appropriate type of initialised certificate object is
590 			   present.  This is a more specific check than that allowed by
591 			   the kernel ACLs */
592 			if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYCERT )
593 				{
594 				int attrValue;
595 
596 				status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
597 									&attrValue, CRYPT_CERTINFO_IMMUTABLE );
598 				if( cryptStatusError( status ) || !attrValue )
599 					return( CRYPT_ARGERROR_NUM1 );
600 				status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
601 									&attrValue, CRYPT_CERTINFO_CERTTYPE );
602 				if( cryptStatusError( status ) || \
603 					( attrValue != CRYPT_CERTTYPE_CERTIFICATE && \
604 					  attrValue != CRYPT_CERTTYPE_CERTCHAIN ) )
605 					return( CRYPT_ARGERROR_NUM1 );
606 				}
607 			if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYCACERT )
608 				{
609 				status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
610 										  MESSAGE_CHECK_CA );
611 				if( cryptStatusError( status ) )
612 					return( CRYPT_ARGERROR_NUM1 );
613 				}
614 
615 			/* If we're using a certificate, make sure that it's currently
616 			   valid.  This self-check avoids ugly silent failures where
617 			   everything appears to work just fine on the server side but
618 			   the client gets invalid data back */
619 			if( requiredAttributeFlags & ( SESSION_NEEDS_PRIVKEYCERT | \
620 										   SESSION_NEEDS_PRIVKEYCACERT ) )
621 				{
622 				status = checkServerCertValid( value, SESSION_ERRINFO );
623 				if( cryptStatusError( status ) )
624 					return( CRYPT_ARGERROR_NUM1 );
625 				}
626 
627 			/* Perform any protocol-specific additional checks if necessary */
628 			if( FNPTR_ISSET( sessionInfoPtr->checkAttributeFunction ) )
629 				{
630 				const SES_CHECKATTRIBUTE_FUNCTION checkAttributeFunction = \
631 						FNPTR_GET( sessionInfoPtr->checkAttributeFunction );
632 
633 				REQUIRES( checkAttributeFunction != NULL );
634 
635 				status = checkAttributeFunction( sessionInfoPtr, &value,
636 												 attribute );
637 				if( status == OK_SPECIAL )
638 					{
639 					/* The value was dealt with as a side-effect of the check
640 					   function, there's nothing more to do */
641 					return( CRYPT_OK );
642 					}
643 				if( cryptStatusError( status ) )
644 					return( status );
645 				}
646 
647 			/* Add the private key and increment its reference count */
648 			krnlSendNotifier( value, IMESSAGE_INCREFCOUNT );
649 			sessionInfoPtr->privateKey = value;
650 
651 			return( CRYPT_OK );
652 			}
653 
654 		case CRYPT_SESSINFO_KEYSET:
655 			{
656 			int type;
657 
658 			/* Make sure that it's either a certificate store (rather than
659 			   just a generic keyset) if required, or specifically not a
660 			   certificate store if not required.  This is to prevent a
661 			   session running with unnecessary privileges, we should only
662 			   be using a certificate store if it's actually required.  The
663 			   checking is already performed by the kernel but we do it
664 			   again here just to be safe */
665 			status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE, &type,
666 									  CRYPT_IATTRIBUTE_SUBTYPE );
667 			if( cryptStatusError( status ) )
668 				return( CRYPT_ARGERROR_NUM1 );
669 			if( sessionInfoPtr->serverReqAttrFlags & SESSION_NEEDS_CERTSTORE )
670 				{
671 				if( type != SUBTYPE_KEYSET_DBMS_STORE )
672 					return( CRYPT_ARGERROR_NUM1 );
673 				}
674 			else
675 				{
676 				if( type != SUBTYPE_KEYSET_DBMS )
677 					return( CRYPT_ARGERROR_NUM1 );
678 				}
679 
680 			/* Add the keyset and increment its reference count */
681 			krnlSendNotifier( value, IMESSAGE_INCREFCOUNT );
682 			sessionInfoPtr->cryptKeyset = value;
683 
684 			return( CRYPT_OK );
685 			}
686 
687 		case CRYPT_SESSINFO_AUTHRESPONSE:
688 			sessionInfoPtr->authResponse = value ? AUTHRESPONSE_SUCCESS : \
689 												   AUTHRESPONSE_FAILURE;
690 			return( CRYPT_OK );
691 
692 		case CRYPT_SESSINFO_SESSION:
693 			/* If there's already a host or network socket specified then we
694 			   can't set a transport session as well */
695 			if( findSessionInfo( sessionInfoPtr->attributeList,
696 								 CRYPT_SESSINFO_SERVER_NAME ) != NULL )
697 				return( exitErrorInited( sessionInfoPtr,
698 										 CRYPT_SESSINFO_SERVER_NAME ) );
699 			if( sessionInfoPtr->networkSocket != CRYPT_ERROR )
700 				return( exitErrorInited( sessionInfoPtr,
701 										 CRYPT_SESSINFO_NETWORKSOCKET ) );
702 
703 			/* Add the transport mechanism and increment its reference
704 			   count */
705 			krnlSendNotifier( value, IMESSAGE_INCREFCOUNT );
706 			sessionInfoPtr->transportSession = value;
707 
708 			return( CRYPT_OK );
709 
710 		case CRYPT_SESSINFO_NETWORKSOCKET:
711 			{
712 			NET_CONNECT_INFO connectInfo;
713 			STREAM stream;
714 
715 			/* If there's already a host or session specified then we can't
716 			   set a network socket as well */
717 			if( findSessionInfo( sessionInfoPtr->attributeList,
718 								 CRYPT_SESSINFO_SERVER_NAME ) != NULL )
719 				return( exitErrorInited( sessionInfoPtr,
720 										 CRYPT_SESSINFO_SERVER_NAME ) );
721 			if( sessionInfoPtr->transportSession != CRYPT_ERROR )
722 				return( exitErrorInited( sessionInfoPtr,
723 										 CRYPT_SESSINFO_SESSION ) );
724 
725 			/* Create a dummy network stream to make sure that the network
726 			   socket is OK */
727 			initNetConnectInfo( &connectInfo, sessionInfoPtr->ownerHandle,
728 								sessionInfoPtr->readTimeout,
729 								sessionInfoPtr->connectTimeout,
730 								NET_OPTION_NETWORKSOCKET_DUMMY );
731 			connectInfo.networkSocket = value;
732 			status = sNetConnect( &stream, STREAM_PROTOCOL_TCP,
733 								  &connectInfo, &sessionInfoPtr->errorInfo );
734 			if( cryptStatusError( status ) )
735 				return( status );
736 			sNetDisconnect( &stream );
737 
738 			/* Add the network socket */
739 			sessionInfoPtr->networkSocket = value;
740 
741 			return( CRYPT_OK );
742 			}
743 		}
744 
745 	retIntError();
746 	}
747 
748 /* Set a string attribute */
749 
750 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
setSessionAttributeS(INOUT SESSION_INFO * sessionInfoPtr,IN_BUFFER (dataLength)const void * data,IN_LENGTH const int dataLength,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute)751 int setSessionAttributeS( INOUT SESSION_INFO *sessionInfoPtr,
752 						  IN_BUFFER( dataLength ) const void *data,
753 						  IN_LENGTH const int dataLength,
754 						  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
755 	{
756 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
757 	assert( isReadPtr( data, dataLength ) );
758 
759 	REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
760 	REQUIRES( isAttribute( attribute ) || \
761 			  isInternalAttribute( attribute ) );
762 
763 	/* Handle the various information types */
764 	switch( attribute )
765 		{
766 		case CRYPT_OPTION_NET_SOCKS_SERVER:
767 		case CRYPT_OPTION_NET_SOCKS_USERNAME:
768 		case CRYPT_OPTION_NET_HTTP_PROXY:
769 			/* These aren't implemented on a per-session level yet since
770 			   they're almost never used */
771 			return( CRYPT_ARGERROR_VALUE );
772 
773 		case CRYPT_SESSINFO_USERNAME:
774 		case CRYPT_SESSINFO_PASSWORD:
775 			{
776 			ATTRIBUTE_LIST *attributeListPtr = NULL;
777 			int flags = isServer( sessionInfoPtr ) ? \
778 						ATTR_FLAG_MULTIVALUED : ATTR_FLAG_NONE;
779 			int status;
780 
781 			REQUIRES( dataLength > 0 && dataLength <= CRYPT_MAX_TEXTSIZE );
782 
783 			/* If this is a client session then we can only have a single
784 			   instance of this attribute */
785 			if( !isServer( sessionInfoPtr ) && \
786 				findSessionInfo( sessionInfoPtr->attributeList,
787 								 attribute ) != NULL )
788 				return( exitErrorInited( sessionInfoPtr, attribute ) );
789 
790 			/* Get the last-added attribute so that we can check that it's
791 			   consistent with what's being added now */
792 			status = setSessionAttributeCursor( sessionInfoPtr->attributeList,
793 												&attributeListPtr,
794 												CRYPT_ATTRIBUTE_CURRENT_GROUP,
795 												CRYPT_CURSOR_LAST );
796 			if( attribute == CRYPT_SESSINFO_USERNAME )
797 				{
798 				/* It's a username make sure that the last attribute added
799 				   wasn't also a username and that it doesn't duplicate an
800 				   existing name */
801 				if( cryptStatusOK( status ) && \
802 					attributeListPtr->attributeID == CRYPT_SESSINFO_USERNAME )
803 					return( exitErrorInited( sessionInfoPtr,
804 											 CRYPT_SESSINFO_USERNAME ) );
805 				if( findSessionInfoEx( sessionInfoPtr->attributeList,
806 									   attribute, data, dataLength ) != NULL )
807 					{
808 					return( exitError( sessionInfoPtr, attribute,
809 									   CRYPT_ERRTYPE_ATTR_PRESENT,
810 									   CRYPT_ERROR_DUPLICATE ) );
811 					}
812 				}
813 			else
814 				{
815 				/* It's a password, make sure that there's an associated
816 				   username to go with it.  There are two approaches that
817 				   we can take here, the first simply requires that the
818 				   current cursor position is a username, implying that
819 				   the last-added attribute was a username.  The other is
820 				   to try and move the cursor to the last username in the
821 				   attribute list and check that the next attribute isn't
822 				   a password and then add it there, however this is doing
823 				   a bit too much behind the user's back, is somewhat
824 				   difficult to back out of, and leads to exceptions to
825 				   exceptions, so we keep it simple and only allow passwords
826 				   to be added if there's an immediately preceding
827 				   username */
828 				if( cryptStatusError( status ) || \
829 					attributeListPtr->attributeID != CRYPT_SESSINFO_USERNAME )
830 					return( exitErrorNotInited( sessionInfoPtr,
831 												CRYPT_SESSINFO_USERNAME ) );
832 				}
833 
834 			/* If it could be an encoded PKI value, check its validity */
835 			if( dataLength >= 15 && isPKIUserValue( data, dataLength ) )
836 				{
837 				BYTE decodedValue[ CRYPT_MAX_TEXTSIZE + 8 ];
838 				int decodedValueLen;
839 
840 				/* It's an encoded value, make sure that it's in order */
841 				status = decodePKIUserValue( decodedValue,
842 											 CRYPT_MAX_TEXTSIZE,
843 											 &decodedValueLen, data,
844 											 dataLength );
845 				zeroise( decodedValue, CRYPT_MAX_TEXTSIZE );
846 				if( cryptStatusError( status ) )
847 					return( status );
848 				flags = ATTR_FLAG_ENCODEDVALUE;
849 				}
850 
851 			/* Perform any protocol-specific additional checks if necessary */
852 			if( FNPTR_ISSET( sessionInfoPtr->checkAttributeFunction ) )
853 				{
854 				const SES_CHECKATTRIBUTE_FUNCTION checkAttributeFunction = \
855 						FNPTR_GET( sessionInfoPtr->checkAttributeFunction );
856 				MESSAGE_DATA msgData;
857 
858 				REQUIRES( checkAttributeFunction != NULL );
859 
860 				setMessageData( &msgData, ( MESSAGE_CAST ) data, dataLength );
861 				status = checkAttributeFunction( sessionInfoPtr, &msgData,
862 												 attribute );
863 				if( status == OK_SPECIAL )
864 					{
865 					/* The value was dealt with as a side-effect of the check
866 					   function, there's nothing more to do */
867 					return( CRYPT_OK );
868 					}
869 				if( cryptStatusError( status ) )
870 					return( status );
871 				}
872 
873 			/* Remember the value */
874 			return( addSessionInfoEx( &sessionInfoPtr->attributeList,
875 									  attribute, data, dataLength, flags ) );
876 			}
877 
878 		case CRYPT_SESSINFO_SERVER_FINGERPRINT_SHA1:
879 			/* Remember the value */
880 			return( addSessionInfoS( &sessionInfoPtr->attributeList,
881 									 attribute, data, dataLength ) );
882 
883 		case CRYPT_SESSINFO_SERVER_NAME:
884 			return( addUrl( sessionInfoPtr, data, dataLength ) );
885 		}
886 
887 	retIntError();
888 	}
889 
890 /****************************************************************************
891 *																			*
892 *								Delete Attributes							*
893 *																			*
894 ****************************************************************************/
895 
896 /* Delete an attribute */
897 
898 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
deleteSessionAttribute(INOUT SESSION_INFO * sessionInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute)899 int deleteSessionAttribute( INOUT SESSION_INFO *sessionInfoPtr,
900 							IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
901 	{
902 	const ATTRIBUTE_LIST *attributeListPtr;
903 
904 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
905 
906 	REQUIRES( isAttribute( attribute ) || \
907 			  isInternalAttribute( attribute ) );
908 
909 	/* Handle the various information types */
910 	switch( attribute )
911 		{
912 		case CRYPT_OPTION_NET_CONNECTTIMEOUT:
913 			if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
914 				return( exitErrorNotFound( sessionInfoPtr,
915 										   CRYPT_OPTION_NET_CONNECTTIMEOUT ) );
916 			sessionInfoPtr->connectTimeout = CRYPT_ERROR;
917 			return( CRYPT_OK );
918 
919 		case CRYPT_OPTION_NET_READTIMEOUT:
920 			if( sessionInfoPtr->readTimeout == CRYPT_ERROR )
921 				return( exitErrorNotFound( sessionInfoPtr,
922 										   CRYPT_OPTION_NET_READTIMEOUT ) );
923 			sessionInfoPtr->readTimeout = CRYPT_ERROR;
924 			return( CRYPT_OK );
925 
926 		case CRYPT_OPTION_NET_WRITETIMEOUT:
927 			if( sessionInfoPtr->writeTimeout == CRYPT_ERROR )
928 				return( exitErrorNotFound( sessionInfoPtr,
929 										   CRYPT_OPTION_NET_WRITETIMEOUT ) );
930 			sessionInfoPtr->writeTimeout = CRYPT_ERROR;
931 			return( CRYPT_OK );
932 
933 		case CRYPT_SESSINFO_USERNAME:
934 		case CRYPT_SESSINFO_PASSWORD:
935 		case CRYPT_SESSINFO_SERVER_NAME:
936 		case CRYPT_SESSINFO_SERVER_PORT:
937 			/* Make sure that the attribute to delete is actually present */
938 			attributeListPtr = \
939 				findSessionInfo( sessionInfoPtr->attributeList, attribute );
940 			if( attributeListPtr == NULL )
941 				return( exitErrorNotFound( sessionInfoPtr, attribute ) );
942 
943 			/* Delete the attribute.  If we're in the middle of a paired-
944 			   attribute add then the delete affects the paired attribute.
945 			   This can get quite complex because the user could (for
946 			   example) add a { username, password } pair, then add a second
947 			   username (but not password), and then delete the first
948 			   password, leaving an orphaned password followed by an
949 			   orphaned username.  There isn't any easy way to fix this
950 			   short of forcing some form of group delete of paired
951 			   attributes, but this gets too complicated both to implement
952 			   and to explain to the user in an error status.  What we do
953 			   here is handle the simple case and let the pre-session-
954 			   activation sanity check catch situations where the user's
955 			   gone out of their way to be difficult */
956 			deleteSessionInfo( &sessionInfoPtr->attributeList,
957 							   &sessionInfoPtr->attributeListCurrent,
958 							   ( ATTRIBUTE_LIST * ) attributeListPtr );
959 			return( CRYPT_OK );
960 
961 		case CRYPT_SESSINFO_REQUEST:
962 			if( sessionInfoPtr->iCertRequest == CRYPT_ERROR )
963 				return( exitErrorNotFound( sessionInfoPtr,
964 										   CRYPT_SESSINFO_REQUEST ) );
965 			krnlSendNotifier( sessionInfoPtr->iCertRequest,
966 							  IMESSAGE_DECREFCOUNT );
967 			sessionInfoPtr->iCertRequest = CRYPT_ERROR;
968 
969 			return( CRYPT_OK );
970 
971 		case CRYPT_SESSINFO_TSP_MSGIMPRINT:
972 			if( sessionInfoPtr->sessionTSP->imprintAlgo == CRYPT_ALGO_NONE || \
973 				sessionInfoPtr->sessionTSP->imprintSize <= 0 )
974 				return( exitErrorNotFound( sessionInfoPtr,
975 										   CRYPT_SESSINFO_TSP_MSGIMPRINT ) );
976 			sessionInfoPtr->sessionTSP->imprintAlgo = CRYPT_ALGO_NONE;
977 			sessionInfoPtr->sessionTSP->imprintSize = 0;
978 
979 			return( CRYPT_OK );
980 		}
981 
982 	retIntError();
983 	}
984 #endif /* USE_SESSIONS */
985