Stream Contexts

Stream contexts are quite different from either connection or datagram contexts. Stream contexts were introduced to handle the secure streams-oriented protocols such as SSL or PCT.

In the interest of sharing the same interface, similar credential management, and so on, the Security Support Provider Interface has been extended to provide support for stream contexts. The security protocol incorporated both the authentication scheme, and the record formats. This posed a problem to the typical implementation, which required the blocking to be done by the caller.

To satisfy the requirements of the stream-oriented protocols, a security package that supports stream contexts has the following characteristics:

  1. The package sets the SECPKG_FLAG_STREAM flag to indicate that it supports stream semantics, just as it would set a flag to indicate support for connection and datagram semantics.
  2. A transport application requests stream semantics by setting the ISC_REQ_STREAM and ASC_REQ_STREAM flags in the calls to the InitializeSecurityContext and AcceptSecurityContext functions.
  3. The application calls the QueryContextAttributes function with a SecPkgContext_StreamSizes structure to query the security context for the number of buffers to provide, and the sizes to reserve for headers or trailers.
  4. The application provides buffer descriptors to spare during the actual processing of the data.

Obviously, item 4 is of the most interest. By specifying stream semantics, the caller is indicating a willingness to do extra so the security provider can handle the blocking of the messages.

In essence, for the MakeSignature and VerifySignature functions, the caller passes in a list of buffers. When a message is received from a channel that is stream-oriented (such as a TCP port), the caller passes in a buffer list as follows:

Buffer Length Buffer Type
1 MessageLength SECBUFFER_DATA
2 0 SECBUFFER_EMPTY
3 0 SECBUFFER_EMPTY
4 0 SECBUFFER_EMPTY
5 0 SECBUFFER_EMPTY

The security package then goes to work on the blob. If the function returns successfully, the buffer list looks like this:

Buffer Length Buffer Type
1 Header Length SECBUFFER_STREAM_HEADER
2 Data Length SECBUFFER_DATA
3 Trailer Length SECBUFFER_STREAM_TRAILER
4 0 SECBUFFER_EMPTY
5 0 SECBUFFER_EMPTY

The provider could have also returned buffer #4 as follows:

Buffer Length Buffer Type
4 x SECBUFFER_EXTRA

This indicates that the data in this buffer is part of the next record, and has not yet been processed.

Conversely, if the message function returns the SEC_E_INCOMPLETE_MESSAGE error code, the returned buffer list would look like this:

Buffer Length Buffer Type
1 x SECBUFFER_MISSING

This indicates that more data was needed to process the record. Unlike most errors returned from a message function, this buffer type does not indicate that the context has been compromised, just that more data is needed. Security providers must not update their state in this condition.

Similarly, on the send side of the communication, the caller can simply call the MakeSignature function, in which case the security package may need to reallocate the buffer, copy things around, and so on. Or the caller can be more efficient by providing a buffer list as follows:

Buffer Length Type
1 Header Length SECBUFFER_STREAM_HEADER
2 Data Length SECBUFFER_DATA
3 Trailer Length SECBUFFER_STREAM_TRAILER

This allows the caller to use the buffers more efficiently. By calling the QueryContextAttributes function to determine the amount of space to reserve before calling MakeSignature, the operation is more efficient for the application and the security package.