cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sess_attr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Session Attribute Routines *
4 * Copyright Peter Gutmann 1998-2008 *
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 
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 
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,
55  }
56 
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,
68  }
69 
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,
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 ) ) \
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,
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. For TSP
111  and CMP the user can also specify the braindamaged "TCP transport"
112  protocol but luckily this seems to have sunk without trace, other
113  portions of the session-handling code also discourage its use so we
114  don't encourate it here */
115  status = sNetParseURL( &urlInfo, url, urlLength,
116  ( sessionInfoPtr->type == CRYPT_SESSION_SSH ) ? \
117  URL_TYPE_SSH : \
118  ( sessionInfoPtr->type == CRYPT_SESSION_SSL ) ? \
120  if( cryptStatusError( status ) )
121  return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
123 
124  /* We can only use autodetection with PKI services */
125  if( urlInfo.hostLen == 12 && \
126  !strCompare( urlInfo.host, "[Autodetect]", urlInfo.hostLen ) && \
127  !protocolInfoPtr->isReqResp )
128  return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
130 
131  /* Remember the server name */
132  if( urlInfo.hostLen + urlInfo.locationLen >= MAX_URL_SIZE )
133  {
134  /* This should never happen since the overall URL size has to be
135  less than MAX_URL_SIZE */
136  assert( INTERNAL_ERROR );
137  return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
139  }
140  if( urlInfo.locationLen <= 0 )
141  {
142  status = addSessionInfoS( &sessionInfoPtr->attributeList,
144  urlInfo.host, urlInfo.hostLen );
145  }
146  else
147  {
148  char urlBuffer[ MAX_URL_SIZE + 8 ];
149 
150  ENSURES( rangeCheck( urlInfo.hostLen, urlInfo.locationLen,
151  MAX_URL_SIZE ) );
152  memcpy( urlBuffer, urlInfo.host, urlInfo.hostLen );
153  memcpy( urlBuffer + urlInfo.hostLen, urlInfo.location,
154  urlInfo.locationLen );
155  status = addSessionInfoS( &sessionInfoPtr->attributeList,
156  CRYPT_SESSINFO_SERVER_NAME, urlBuffer,
157  urlInfo.hostLen + urlInfo.locationLen );
158  }
159  if( cryptStatusError( status ) )
160  return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
162 
163  /* If there's a port or user name specified in the URL, remember them.
164  We have to add the user name after we add any other attributes
165  because it's paired with a password, so adding the user name and then
166  following it with something that isn't a password will cause an error
167  return */
168  if( urlInfo.port > 0 )
169  {
170  ( void ) krnlSendMessage( sessionInfoPtr->objectHandle,
173  status = krnlSendMessage( sessionInfoPtr->objectHandle,
174  IMESSAGE_SETATTRIBUTE, &urlInfo.port,
176  }
177  if( cryptStatusOK( status ) && urlInfo.userInfoLen > 0 )
178  {
179  MESSAGE_DATA userInfoMsgData;
180 
181  ( void ) krnlSendMessage( sessionInfoPtr->objectHandle,
184  setMessageData( &userInfoMsgData, ( MESSAGE_CAST ) urlInfo.userInfo,
185  urlInfo.userInfoLen );
186  status = krnlSendMessage( sessionInfoPtr->objectHandle,
187  IMESSAGE_SETATTRIBUTE_S, &userInfoMsgData,
189  }
190  if( cryptStatusError( status ) )
191  return( exitError( sessionInfoPtr, CRYPT_SESSINFO_SERVER_NAME,
193 
194  /* Remember the transport type */
195 #ifdef USE_CMP_TRANSPORT
196  if( protocolInfoPtr->altProtocolInfo != NULL && \
197  urlInfo.schemaLen == \
198  protocolInfoPtr->altProtocolInfo->uriTypeLen && \
199  !strCompare( urlInfo.schema,
200  protocolInfoPtr->altProtocolInfo->uriType,
201  protocolInfoPtr->altProtocolInfo->uriTypeLen ) )
202  {
203  /* The caller has specified the use of the alternate transport
204  protocol type, switch to that instead of HTTP */
205  sessionInfoPtr->flags &= ~protocolInfoPtr->altProtocolInfo->oldFlagsMask;
206  sessionInfoPtr->flags |= protocolInfoPtr->altProtocolInfo->newFlags;
207  }
208  else
209 #endif /* USE_CMP_TRANSPORT */
210  {
211  if( sessionInfoPtr->protocolInfo->flags & SESSION_ISHTTPTRANSPORT )
212  {
213  sessionInfoPtr->flags &= ~SESSION_USEALTTRANSPORT;
214  sessionInfoPtr->flags |= SESSION_ISHTTPTRANSPORT;
215  }
216  }
217 
218  return( CRYPT_OK );
219  }
220 
221 /****************************************************************************
222 * *
223 * Get Attributes *
224 * *
225 ****************************************************************************/
226 
227 /* Get a numeric/boolean attribute */
228 
229 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
230 int getSessionAttribute( INOUT SESSION_INFO *sessionInfoPtr,
231  OUT_INT_Z int *valuePtr,
233  {
234  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
235  assert( isWritePtr( valuePtr, sizeof( int ) ) );
236 
237  REQUIRES( isAttribute( attribute ) || \
238  isInternalAttribute( attribute ) );
239 
240  /* Clear return value */
241  *valuePtr = 0;
242 
243  /* Handle the various information types */
244  switch( attribute )
245  {
248  {
250  int status;
251 
252  status = getSessionAttributeCursor( sessionInfoPtr->attributeList,
253  sessionInfoPtr->attributeListCurrent,
254  attribute, &attributeID );
255  if( status == OK_SPECIAL )
256  {
257  /* The attribute list wasn't initialised yet, initialise it
258  now */
259  sessionInfoPtr->attributeListCurrent = \
260  sessionInfoPtr->attributeList;
261  }
262  else
263  {
264  if( cryptStatusError( status ) )
265  return( exitError( sessionInfoPtr, attribute,
266  CRYPT_ERRTYPE_ATTR_ABSENT, status ) );
267  }
268  *valuePtr = attributeID;
269 
270  return( CRYPT_OK );
271  }
272 
274  if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
275  return( exitErrorNotInited( sessionInfoPtr,
277  *valuePtr = sessionInfoPtr->connectTimeout;
278  return( CRYPT_OK );
279 
281  if( sessionInfoPtr->readTimeout == CRYPT_ERROR )
282  return( exitErrorNotInited( sessionInfoPtr,
284  *valuePtr = sessionInfoPtr->readTimeout;
285  return( CRYPT_OK );
286 
288  if( sessionInfoPtr->writeTimeout == CRYPT_ERROR )
289  return( exitErrorNotInited( sessionInfoPtr,
291  *valuePtr = sessionInfoPtr->writeTimeout;
292  return( CRYPT_OK );
293 
295  *valuePtr = sessionInfoPtr->errorType;
296  return( CRYPT_OK );
297 
299  *valuePtr = sessionInfoPtr->errorLocus;
300  return( CRYPT_OK );
301 
303  *valuePtr = sessionInfoPtr->receiveBufSize;
304  return( CRYPT_OK );
305 
307  /* Only secure transport sessions can be persistently active,
308  request/response sessions are only active while the
309  transaction is in progress. Note that this differs from the
310  connection-active state below, which records the fact that
311  there's a network-level connection established but not whether
312  there's any messages or a secure session active across it.
313  See the comment in setSessionAttribute() for more on this */
314  *valuePtr = sessionInfoPtr->iCryptInContext != CRYPT_ERROR && \
315  ( sessionInfoPtr->flags & SESSION_ISOPEN ) ? \
316  TRUE : FALSE;
317  return( CRYPT_OK );
318 
320  *valuePtr = ( sessionInfoPtr->flags & SESSION_ISOPEN ) ? \
321  TRUE : FALSE;
322  return( CRYPT_OK );
323 
326  {
328  findSessionInfo( sessionInfoPtr->attributeList,
329  attribute );
330  if( attributeListPtr == NULL )
331  return( exitErrorNotInited( sessionInfoPtr, attribute ) );
332  *valuePtr = attributeListPtr->intValue;
333  return( CRYPT_OK );
334  }
335 
337  *valuePtr = sessionInfoPtr->version;
338  return( CRYPT_OK );
339 
341  if( sessionInfoPtr->authResponse == AUTHRESPONSE_NONE )
342  return( exitErrorNotFound( sessionInfoPtr,
344  *valuePtr = \
345  ( sessionInfoPtr->authResponse == AUTHRESPONSE_SUCCESS ) ? \
346  TRUE : FALSE;
347  return( CRYPT_OK );
348  }
349 
350  retIntError();
351  }
352 
353 /* Get a string attribute */
354 
355 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
356 int getSessionAttributeS( INOUT SESSION_INFO *sessionInfoPtr,
358  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
359  {
361 
362  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
363  assert( isWritePtr( msgData, sizeof( MESSAGE_DATA ) ) );
364 
365  /* Handle the various information types */
366  switch( attribute )
367  {
371  /* These aren't implemented on a per-session level yet since
372  they're almost never user */
373  return( exitErrorNotFound( sessionInfoPtr, attribute ) );
374 
376  {
377 #ifdef USE_ERRMSGS
378  ERROR_INFO *errorInfo = &sessionInfoPtr->errorInfo;
379 
380  if( errorInfo->errorStringLength > 0 )
381  {
382  return( attributeCopy( msgData, errorInfo->errorString,
383  errorInfo->errorStringLength ) );
384  }
385 #endif /* USE_ERRMSGS */
386 
387  /* We don't set extended error information for this atribute
388  because it's usually read in response to an existing error,
389  which would overwrite the existing error information */
390  return( CRYPT_ERROR_NOTFOUND );
391  }
392 
398  attributeListPtr = findSessionInfo( sessionInfoPtr->attributeList,
399  attribute );
400  if( attributeListPtr == NULL )
401  return( exitErrorNotInited( sessionInfoPtr, attribute ) );
402  return( attributeCopy( msgData, attributeListPtr->value,
403  attributeListPtr->valueLength ) );
404  }
405 
406  retIntError();
407  }
408 
409 /****************************************************************************
410 * *
411 * Set Attributes *
412 * *
413 ****************************************************************************/
414 
415 /* Set a numeric/boolean attribute */
416 
418 int setSessionAttribute( INOUT SESSION_INFO *sessionInfoPtr,
419  IN_INT_Z const int value,
420  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
421  {
422  int status;
423 
424  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
425 
426  REQUIRES( ( attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
427  attribute == CRYPT_ATTRIBUTE_CURRENT ) ||
428  /* CURRENT = cursor positioning code */
429  ( value >= 0 && value < MAX_INTLENGTH ) );
430  REQUIRES( isAttribute( attribute ) || \
431  isInternalAttribute( attribute ) );
432 
433  /* Handle the various information types */
434  switch( attribute )
435  {
438  {
439  ATTRIBUTE_LIST *attributeListPtr = \
440  sessionInfoPtr->attributeListCurrent;
441 
442  status = setSessionAttributeCursor( sessionInfoPtr->attributeList,
443  &attributeListPtr, attribute, value );
444  if( cryptStatusError( status ) )
445  return( exitError( sessionInfoPtr, attribute,
446  CRYPT_ERRTYPE_ATTR_ABSENT, status ) );
447  sessionInfoPtr->attributeListCurrent = attributeListPtr;
448  return( CRYPT_OK );
449  }
450 
452  sessionInfoPtr->connectTimeout = value;
453  return( CRYPT_OK );
454 
456  sessionInfoPtr->readTimeout = value;
457  return( CRYPT_OK );
458 
460  sessionInfoPtr->writeTimeout = value;
461  return( CRYPT_OK );
462 
464  REQUIRES( !( sessionInfoPtr->flags & SESSION_ISOPEN ) );
465 
466  sessionInfoPtr->receiveBufSize = value;
467  return( CRYPT_OK );
468 
470  {
471  CRYPT_ATTRIBUTE_TYPE missingInfo;
472 
473  /* Session state and persistent sessions are handled as follows:
474  The CRYPT_SESSINFO_ACTIVE attribute records the active state
475  of the session as a whole, and the CRYPT_SESSINFO_-
476  CONNECTIONACTIVE attribute records the state of the
477  underlying comms session. Setting CRYPT_SESSINFO_ACTIVE for
478  the first time activates the comms session and leaves it
479  active if the underlying mechanism (e.g. HTTP 1.1 persistent
480  connections) supports it. The CRYPT_SESSINFO_ACTIVE
481  attribute is reset once the transaction completes, and
482  further transactions can be initiated as long as
483  CRYPT_SESSINFO_CONNECTIONACTIVE is set:
484 
485  Obj.state _active _connactive
486  --------- ------- -----------
487  create 0 0 0
488  setattr 0 0 0
489  (clear out_param)
490  activate 1 0 -> 1 -> 0 1
491  (clear in_param)
492  setattr 1 0 1
493  (clear out_param)
494  activate 1 0 -> 1 -> 0 1
495  (clear in_param)
496  (peer closes conn) 1 0 0
497  setattr CRYPT_ERROR_COMPLETE */
498  if( value == FALSE )
499  return( CRYPT_OK ); /* No-op */
500 
501  /* If the session is in the partially-open state while we wait
502  for the caller to allow or disallow the session authentication
503  they have to provide a clear yes or no indication by setting
504  the CRYPT_SESSINFO_AUTHRESPONSE to TRUE or FALSE before they
505  can try to continue the session activation */
506  if( ( sessionInfoPtr->flags & SESSION_PARTIALOPEN ) && \
507  sessionInfoPtr->authResponse == AUTHRESPONSE_NONE )
508  return( exitErrorNotInited( sessionInfoPtr,
510 
511  /* Make sure that all of the information that we need to proceed
512  is present */
513  missingInfo = checkMissingInfo( sessionInfoPtr->attributeList,
514  isServer( sessionInfoPtr ) ? TRUE : FALSE );
515  if( missingInfo != CRYPT_ATTRIBUTE_NONE )
516  return( exitErrorNotInited( sessionInfoPtr, missingInfo ) );
517 
518  status = activateSession( sessionInfoPtr );
519  if( cryptArgError( status ) )
520  {
521  /* Catch leaked low-level status values. The session
522  management code does a large amount of work involving
523  other cryptlib objects so it's possible that an
524  unexpected failure at some point will leak through an
525  inappropriate status value */
526  DEBUG_DIAG(( "Session activate returned argError status" ));
527  assert( DEBUG_WARN );
528  status = CRYPT_ERROR_FAILED;
529  }
530  return( status );
531  }
532 
534  /* If there's already a transport session or network socket
535  specified then we can't set a port as well */
536  if( sessionInfoPtr->transportSession != CRYPT_ERROR )
537  return( exitErrorInited( sessionInfoPtr,
539  if( sessionInfoPtr->networkSocket != CRYPT_ERROR )
540  return( exitErrorInited( sessionInfoPtr,
542 
543  return( addSessionInfo( &sessionInfoPtr->attributeList,
544  CRYPT_SESSINFO_SERVER_PORT, value ) );
545 
547  if( value < sessionInfoPtr->protocolInfo->minVersion || \
548  value > sessionInfoPtr->protocolInfo->maxVersion )
549  return( CRYPT_ARGERROR_VALUE );
550  sessionInfoPtr->version = value;
551  return( CRYPT_OK );
552 
554  {
555  const int requiredAttributeFlags = isServer( sessionInfoPtr ) ? \
556  sessionInfoPtr->serverReqAttrFlags : \
557  sessionInfoPtr->clientReqAttrFlags;
558 
559  /* Make sure that it's a private key */
560  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
562  if( cryptStatusError( status ) )
563  {
564  if( sessionInfoPtr->type != CRYPT_SESSION_SSL )
565  return( CRYPT_ARGERROR_NUM1 );
566 
567  /* SSL can also do key agreement-based key exchange so we
568  fall back to this if key transport-based exchange isn't
569  possible */
570  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
572  if( cryptStatusError( status ) )
573  return( CRYPT_ARGERROR_NUM1 );
574  }
575 
576  /* If we need a private key with certain capabilities, make sure
577  that it has these capabilities. This is a more specific check
578  than that allowed by the kernel ACLs */
579  if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYSIGN )
580  {
581  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
583  if( cryptStatusError( status ) )
584  {
585  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
587  return( CRYPT_ARGERROR_NUM1 );
588  }
589  }
590  if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYCRYPT )
591  {
592  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
594  if( cryptStatusError( status ) )
595  {
596  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
598  return( CRYPT_ARGERROR_NUM1 );
599  }
600  }
601 
602  /* If we need a private key with a certificate, make sure that
603  the appropriate type of initialised certificate object is
604  present. This is a more specific check than that allowed by
605  the kernel ACLs */
606  if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYCERT )
607  {
608  int attrValue;
609 
610  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
611  &attrValue, CRYPT_CERTINFO_IMMUTABLE );
612  if( cryptStatusError( status ) || !attrValue )
613  return( CRYPT_ARGERROR_NUM1 );
614  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
615  &attrValue, CRYPT_CERTINFO_CERTTYPE );
616  if( cryptStatusError( status ) || \
617  ( attrValue != CRYPT_CERTTYPE_CERTIFICATE && \
618  attrValue != CRYPT_CERTTYPE_CERTCHAIN ) )
619  return( CRYPT_ARGERROR_NUM1 );
620  }
621  if( requiredAttributeFlags & SESSION_NEEDS_PRIVKEYCACERT )
622  {
623  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
625  if( cryptStatusError( status ) )
626  return( CRYPT_ARGERROR_NUM1 );
627  }
628 
629  /* If we're using a certificate, make sure that it's currently
630  valid. This self-check avoids ugly silent failures where
631  everything appears to work just fine on the server side but
632  the client gets invalid data back */
633  if( requiredAttributeFlags & ( SESSION_NEEDS_PRIVKEYCERT | \
634  SESSION_NEEDS_PRIVKEYCACERT ) )
635  {
636  status = checkServerCertValid( value, &sessionInfoPtr->errorLocus,
637  &sessionInfoPtr->errorType );
638  if( cryptStatusError( status ) )
639  return( CRYPT_ARGERROR_NUM1 );
640  }
641 
642  /* Perform any protocol-specific additional checks if necessary */
643  if( sessionInfoPtr->checkAttributeFunction != NULL )
644  {
645  status = sessionInfoPtr->checkAttributeFunction( sessionInfoPtr,
646  &value, attribute );
647  if( status == OK_SPECIAL )
648  {
649  /* The value was dealt with as a side-effect of the check
650  function, there's nothing more to do */
651  return( CRYPT_OK );
652  }
653  if( cryptStatusError( status ) )
654  return( status );
655  }
656 
657  /* Add the private key and increment its reference count */
659  sessionInfoPtr->privateKey = value;
660 
661  return( CRYPT_OK );
662  }
663 
665  {
666  int type;
667 
668  /* Make sure that it's either a certificate store (rather than
669  just a generic keyset) if required, or specifically not a
670  certificate store if not required. This is to prevent a
671  session running with unnecessary privileges, we should only
672  be using a certificate store if it's actually required. The
673  checking is already performed by the kernel but we do it
674  again here just to be safe */
675  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE, &type,
676  CRYPT_IATTRIBUTE_SUBTYPE );
677  if( cryptStatusError( status ) )
678  return( CRYPT_ARGERROR_NUM1 );
679  if( sessionInfoPtr->serverReqAttrFlags & SESSION_NEEDS_CERTSTORE )
680  {
681  if( type != SUBTYPE_KEYSET_DBMS_STORE )
682  return( CRYPT_ARGERROR_NUM1 );
683  }
684  else
685  {
686  if( type != SUBTYPE_KEYSET_DBMS )
687  return( CRYPT_ARGERROR_NUM1 );
688  }
689 
690  /* Add the keyset and increment its reference count */
692  sessionInfoPtr->cryptKeyset = value;
693 
694  return( CRYPT_OK );
695  }
696 
698  sessionInfoPtr->authResponse = value ? AUTHRESPONSE_SUCCESS : \
699  AUTHRESPONSE_FAILURE;
700  return( CRYPT_OK );
701 
703  /* If there's already a host or network socket specified then we
704  can't set a transport session as well */
705  if( findSessionInfo( sessionInfoPtr->attributeList,
706  CRYPT_SESSINFO_SERVER_NAME ) != NULL )
707  return( exitErrorInited( sessionInfoPtr,
709  if( sessionInfoPtr->networkSocket != CRYPT_ERROR )
710  return( exitErrorInited( sessionInfoPtr,
712 
713  /* Add the transport mechanism and increment its reference
714  count */
716  sessionInfoPtr->transportSession = value;
717 
718  return( CRYPT_OK );
719 
721  {
723  STREAM stream;
724 
725  /* If there's already a host or session specified then we can't
726  set a network socket as well */
727  if( findSessionInfo( sessionInfoPtr->attributeList,
728  CRYPT_SESSINFO_SERVER_NAME ) != NULL )
729  return( exitErrorInited( sessionInfoPtr,
731  if( sessionInfoPtr->transportSession != CRYPT_ERROR )
732  return( exitErrorInited( sessionInfoPtr,
734 
735  /* Create a dummy network stream to make sure that the network
736  socket is OK */
737  initNetConnectInfo( &connectInfo, sessionInfoPtr->ownerHandle,
738  sessionInfoPtr->readTimeout,
739  sessionInfoPtr->connectTimeout,
741  connectInfo.networkSocket = value;
742  status = sNetConnect( &stream, STREAM_PROTOCOL_TCPIP,
743  &connectInfo, &sessionInfoPtr->errorInfo );
744  if( cryptStatusError( status ) )
745  return( status );
746  sNetDisconnect( &stream );
747 
748  /* Add the network socket */
749  sessionInfoPtr->networkSocket = value;
750 
751  return( CRYPT_OK );
752  }
753  }
754 
755  retIntError();
756  }
757 
758 /* Set a string attribute */
759 
760 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
761 int setSessionAttributeS( INOUT SESSION_INFO *sessionInfoPtr,
762  IN_BUFFER( dataLength ) const void *data,
763  IN_LENGTH const int dataLength,
764  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
765  {
766  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
767  assert( isReadPtr( data, dataLength ) );
768 
769  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
770  REQUIRES( isAttribute( attribute ) || \
771  isInternalAttribute( attribute ) );
772 
773  /* Handle the various information types */
774  switch( attribute )
775  {
779  /* These aren't implemented on a per-session level yet since
780  they're almost never used */
781  return( CRYPT_ARGERROR_VALUE );
782 
785  {
786  ATTRIBUTE_LIST *attributeListPtr = NULL;
787  int flags = isServer( sessionInfoPtr ) ? \
788  ATTR_FLAG_MULTIVALUED : ATTR_FLAG_NONE;
789  int status;
790 
791  REQUIRES( dataLength > 0 && dataLength <= CRYPT_MAX_TEXTSIZE );
792 
793  /* If this is a client session then we can only have a single
794  instance of this attribute */
795  if( !isServer( sessionInfoPtr ) && \
796  findSessionInfo( sessionInfoPtr->attributeList,
797  attribute ) != NULL )
798  return( exitErrorInited( sessionInfoPtr, attribute ) );
799 
800  /* Get the last-added attribute so that we can check that it's
801  consistent with what's being added now */
802  status = setSessionAttributeCursor( sessionInfoPtr->attributeList,
803  &attributeListPtr,
806  if( attribute == CRYPT_SESSINFO_USERNAME )
807  {
808  /* It's a username make sure that the last attribute added
809  wasn't also a username and that it doesn't duplicate an
810  existing name */
811  if( cryptStatusOK( status ) && \
812  attributeListPtr->attributeID == CRYPT_SESSINFO_USERNAME )
813  return( exitErrorInited( sessionInfoPtr,
815  if( findSessionInfoEx( sessionInfoPtr->attributeList,
816  attribute, data, dataLength ) != NULL )
817  {
818  return( exitError( sessionInfoPtr, attribute,
821  }
822  }
823  else
824  {
825  /* It's a password, make sure that there's an associated
826  username to go with it. There are two approaches that
827  we can take here, the first simply requires that the
828  current cursor position is a username, implying that
829  the last-added attribute was a username. The other is
830  to try and move the cursor to the last username in the
831  attribute list and check that the next attribute isn't
832  a password and then add it there, however this is doing
833  a bit too much behind the user's back, is somewhat
834  difficult to back out of, and leads to exceptions to
835  exceptions, so we keep it simple and only allow passwords
836  to be added if there's an immediately preceding
837  username */
838  if( cryptStatusError( status ) || \
839  attributeListPtr->attributeID != CRYPT_SESSINFO_USERNAME )
840  return( exitErrorNotInited( sessionInfoPtr,
842  }
843 
844  /* If it could be an encoded PKI value, check its validity */
845  if( dataLength >= 15 && isPKIUserValue( data, dataLength ) )
846  {
847  BYTE decodedValue[ CRYPT_MAX_TEXTSIZE + 8 ];
848  int decodedValueLen;
849 
850  /* It's an encoded value, make sure that it's in order */
851  status = decodePKIUserValue( decodedValue,
853  &decodedValueLen, data,
854  dataLength );
855  zeroise( decodedValue, CRYPT_MAX_TEXTSIZE );
856  if( cryptStatusError( status ) )
857  return( status );
858  flags = ATTR_FLAG_ENCODEDVALUE;
859  }
860 
861  /* Perform any protocol-specific additional checks if necessary */
862  if( sessionInfoPtr->checkAttributeFunction != NULL )
863  {
865 
866  setMessageData( &msgData, ( MESSAGE_CAST ) data, dataLength );
867  status = sessionInfoPtr->checkAttributeFunction( sessionInfoPtr,
868  &msgData, attribute );
869  if( status == OK_SPECIAL )
870  {
871  /* The value was dealt with as a side-effect of the check
872  function, there's nothing more to do */
873  return( CRYPT_OK );
874  }
875  if( cryptStatusError( status ) )
876  return( status );
877  }
878 
879  /* Remember the value */
880  return( addSessionInfoEx( &sessionInfoPtr->attributeList,
881  attribute, data, dataLength, flags ) );
882  }
883 
885  /* Remember the value */
886  return( addSessionInfoS( &sessionInfoPtr->attributeList,
887  attribute, data, dataLength ) );
888 
890  return( addUrl( sessionInfoPtr, data, dataLength ) );
891  }
892 
893  retIntError();
894  }
895 
896 /****************************************************************************
897 * *
898 * Delete Attributes *
899 * *
900 ****************************************************************************/
901 
902 /* Delete an attribute */
903 
905 int deleteSessionAttribute( INOUT SESSION_INFO *sessionInfoPtr,
906  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
907  {
909 
910  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
911 
912  REQUIRES( isAttribute( attribute ) || \
913  isInternalAttribute( attribute ) );
914 
915  /* Handle the various information types */
916  switch( attribute )
917  {
919  if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
920  return( exitErrorNotFound( sessionInfoPtr,
922  sessionInfoPtr->connectTimeout = CRYPT_ERROR;
923  return( CRYPT_OK );
924 
926  if( sessionInfoPtr->readTimeout == CRYPT_ERROR )
927  return( exitErrorNotFound( sessionInfoPtr,
929  sessionInfoPtr->readTimeout = CRYPT_ERROR;
930  return( CRYPT_OK );
931 
933  if( sessionInfoPtr->writeTimeout == CRYPT_ERROR )
934  return( exitErrorNotFound( sessionInfoPtr,
936  sessionInfoPtr->writeTimeout = CRYPT_ERROR;
937  return( CRYPT_OK );
938 
943  /* Make sure that the attribute to delete is actually present */
944  attributeListPtr = \
945  findSessionInfo( sessionInfoPtr->attributeList, attribute );
946  if( attributeListPtr == NULL )
947  return( exitErrorNotFound( sessionInfoPtr, attribute ) );
948 
949  /* Delete the attribute. If we're in the middle of a paired-
950  attribute add then the delete affects the paired attribute.
951  This can get quite complex because the user could (for
952  example) add a { username, password } pair, then add a second
953  username (but not password), and then delete the first
954  password, leaving an orphaned password followed by an
955  orphaned username. There isn't any easy way to fix this
956  short of forcing some form of group delete of paired
957  attributes, but this gets too complicated both to implement
958  and to explain to the user in an error status. What we do
959  here is handle the simple case and let the pre-session-
960  activation sanity check catch situations where the user's
961  gone out of their way to be difficult */
962  deleteSessionInfo( &sessionInfoPtr->attributeList,
963  &sessionInfoPtr->attributeListCurrent,
964  ( ATTRIBUTE_LIST * ) attributeListPtr );
965  return( CRYPT_OK );
966 
968  if( sessionInfoPtr->iCertRequest == CRYPT_ERROR )
969  return( exitErrorNotFound( sessionInfoPtr,
971  krnlSendNotifier( sessionInfoPtr->iCertRequest,
973  sessionInfoPtr->iCertRequest = CRYPT_ERROR;
974 
975  return( CRYPT_OK );
976 
978  if( sessionInfoPtr->sessionTSP->imprintAlgo == CRYPT_ALGO_NONE || \
979  sessionInfoPtr->sessionTSP->imprintSize <= 0 )
980  return( exitErrorNotFound( sessionInfoPtr,
982  sessionInfoPtr->sessionTSP->imprintAlgo = CRYPT_ALGO_NONE;
983  sessionInfoPtr->sessionTSP->imprintSize = 0;
984 
985  return( CRYPT_OK );
986  }
987 
988  retIntError();
989  }
990 #endif /* USE_SESSIONS */