ReactOS 0.4.17-dev-1005-g171e1de
session.c
Go to the documentation of this file.
1//
2// session.c code for Session API implementation
3//
4// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5//
6
7#include "precomp.h"
8
15{
16 // Make sure we only specify the correct flags
17 if (flags != 0)
18 {
19 return SYMCRYPT_INVALID_ARGUMENT;
20 }
21
22 pSession->replayState.messageNumber = 0;
23 pSession->senderId = senderId;
24 pSession->flags = SYMCRYPT_FLAG_SESSION_ENCRYPT;
25 pSession->pMutex = NULL;
26
27 return SYMCRYPT_NO_ERROR;
28}
29
36{
38
39 // Make sure we only specify the correct flags
40 if (flags != 0)
41 {
42 return SYMCRYPT_INVALID_ARGUMENT;
43 }
44
45#if SYMCRYPT_CPU_AMD64
46 if ( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_CMPXCHG16B ) )
47 {
49 if( pMutex == NULL )
50 {
51 return SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
52 }
53 }
54#elif SYMCRYPT_CPU_ARM64 // Arm64 always has support for CAS128 - so never need a lock
55#else // 32b and generic platforms will always need to use a lock
57 if( pMutex == NULL )
58 {
59 return SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
60 }
61#endif
62 pSession->pMutex = pMutex;
63
64 // This represents that the message numbers 1-64 inclusive have not yet been successfully use in decryption
65 pSession->replayState.replayMask = 0;
66 pSession->replayState.messageNumber = 64;
67
68 pSession->senderId = senderId;
69 pSession->flags = 0;
70
71 return SYMCRYPT_NO_ERROR;
72}
73
74VOID
77{
78 if ( pSession->pMutex != NULL )
79 {
81 }
82 SymCryptWipeKnownSize(pSession, sizeof(*pSession));
83}
84
90 _In_reads_opt_( cbAuthData ) PCBYTE pbAuthData,
95 _Out_writes_( cbTag ) PBYTE pbTag,
97 _Out_opt_ PUINT64 pu64MessageNumber )
98{
99 BYTE nonce[12];
101
103 {
104 return SYMCRYPT_INVALID_ARGUMENT;
105 }
106
107 messageNumber = SYMCRYPT_ATOMIC_ADD64_POST_RELAXED(&pSession->replayState.messageNumber, 1);
108
109 // We do not allow messageNumber to go above some maximum value (currently 2^64 - 2^32)
111 {
112 // Decrement the session messageNumber on the error path so that this session will continue
113 // to only generate errors
114 SYMCRYPT_ATOMIC_ADD64_POST_RELAXED(&pSession->replayState.messageNumber, -1ll);
115 return SYMCRYPT_INVALID_ARGUMENT;
116 }
117
118 SYMCRYPT_STORE_MSBFIRST32(&nonce[0], pSession->senderId);
120
123 nonce,
124 sizeof(nonce),
125 pbAuthData,
127 pbSrc,
128 pbDst,
129 cbData,
130 pbTag,
131 cbTag);
132
133 if( pu64MessageNumber != NULL )
134 {
135 *pu64MessageNumber = messageNumber;
136 }
137
138 return SYMCRYPT_NO_ERROR;
139}
140
141// Convenience function used in SymCryptSessionDecryptUpdateState*
142//
143// Given an observedState check whether messageNumber represents a replay
144// If it does, return SYMCRYPT_SESSION_REPLAY_FAILURE
145// Otherwise, set desiredState to the observedState updated to represent messageNumber has been seen
146// and return SYMCRYPT_NO_ERROR
154{
155 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
156 UINT64 messageMask;
157 UINT64 shiftAmount;
158 UINT64 shiftedMask;
159
160 if ( messageNumber > observedState->messageNumber )
161 {
162 // The observed message number is behind messageNumber that we want to mark successful
163 // Shift replayMask appropriately to preserve previously seen message numbers
164 shiftedMask = 0;
165 shiftAmount = messageNumber - observedState->messageNumber;
166 if( shiftAmount < 64 )
167 {
168 shiftedMask = observedState->replayMask << shiftAmount;
169 }
170 // Mark messageNumber as seen in the replayMask
171 desiredState->replayMask = shiftedMask | 1;
172 desiredState->messageNumber = messageNumber;
173 }
174 else if ( messageNumber <= observedState->messageNumber - 64 )
175 {
176 // The observed message number is too far ahead of messageNumber
177 // We cannot hope to succeed
178 scError = SYMCRYPT_SESSION_REPLAY_FAILURE;
179 goto cleanup;
180 }
181 else
182 {
183 // The observed message number is ahead of or equal to messageNumber
184 // Check if messageNumber has already been used
185 messageMask = 1ull << (observedState->messageNumber - messageNumber); // shiftAmount is in [0, 63]
186 if ((messageMask & observedState->replayMask) == messageMask)
187 {
188 scError = SYMCRYPT_SESSION_REPLAY_FAILURE;
189 goto cleanup;
190 }
191 // This is first time we have seen messageNumber - set the replayMask bit appropriately
192 desiredState->replayMask = observedState->replayMask | messageMask;
193 desiredState->messageNumber = observedState->messageNumber;
194 }
195
196cleanup:
197 return scError;
198}
199
200#if SYMCRYPT_USE_CAS128
201
204SymCryptSessionDecryptUpdateStateCAS128(
205 _Inout_ PSYMCRYPT_SESSION pSession,
207{
208 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
209 SYMCRYPT_SESSION_REPLAY_STATE expectedState;
211
212 // Non-atomic read of pSession's replayState. We can use this initial value as a good guess of
213 // the expected state, but we cannot fail based on it (as replayMask and messageNumber may have
214 // been read from different writes to the replayState)
215 expectedState = pSession->replayState;
216
217 // Compute desiredState based on non-atomic read
218 // If it looks like this may be a replay, ensure we fail first CAS so we recompute desiredState
219 // from an atomic read in the loop below
220 if ( SymCryptSessionDecryptComputeDesiredReplayState(&expectedState, &desiredState, messageNumber) != SYMCRYPT_NO_ERROR )
221 {
222 // pSession->replayState.messageNumber can never take the value 0 as it starts at 64 and is
223 // monotonic increasing
224 expectedState.messageNumber = 0;
225 }
226
227 while( scError == SYMCRYPT_NO_ERROR )
228 {
229 if ( SymCryptAtomicCas128Relaxed((PUINT64)&pSession->replayState, (PUINT64)&expectedState, (PUINT64)&desiredState) )
230 {
231 // We succeeded in updating pSession->replayState and are done
232 break;
233 }
234
235 // Compute new desiredState based on atomic read from CAS failure
236 // We may now correctly fall out of loop if a replay is detected
237 scError = SymCryptSessionDecryptComputeDesiredReplayState(&expectedState, &desiredState, messageNumber);
238 }
239
240 return scError;
241}
242
243#endif
244
248 _Inout_ PSYMCRYPT_SESSION pSession,
250{
251 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
253
254 if ( pSession->pMutex == NULL )
255 {
256 return SYMCRYPT_INVALID_ARGUMENT;
257 }
258
259 // Check whether we are definitely too late to proceed before attempting to acquire mutex
260 // Do not need atomic read of full replayState here, but do need atomic 64b read of
261 // pSession->replayState.messageNumber
262 if ( messageNumber <= (UINT64) SYMCRYPT_ATOMIC_LOAD64_RELAXED(&pSession->replayState.messageNumber) - 64 )
263 {
264 return SYMCRYPT_SESSION_REPLAY_FAILURE;
265 }
266
269 // !!! Do not return until we have called SymCryptCallbackReleaseMutexFastInproc !!!
271
272 scError = SymCryptSessionDecryptComputeDesiredReplayState(&pSession->replayState, &desiredState, messageNumber);
273 if ( scError == SYMCRYPT_NO_ERROR )
274 {
275 pSession->replayState = desiredState;
276 }
277
279
280 return scError;
281}
282
286 _Inout_ PSYMCRYPT_SESSION pSession,
288{
289 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
290
291#if SYMCRYPT_CPU_AMD64
292 if ( SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_CMPXCHG16B ) )
293 {
294 scError = SymCryptSessionDecryptUpdateStateCAS128( pSession, messageNumber );
295 }
296 else
297 {
299 }
300#elif SYMCRYPT_CPU_ARM64 // Arm64 always has support for CAS128 (possibly via LDXP + STXP)
301 scError = SymCryptSessionDecryptUpdateStateCAS128( pSession, messageNumber );
302#else // 32b and generic platforms will always need to use a lock
304#endif
305
306 return scError;
307}
308
312 _Inout_ PSYMCRYPT_SESSION pSession,
315 _In_reads_opt_( cbAuthData ) PCBYTE pbAuthData,
320 _In_reads_( cbTag ) PCBYTE pbTag,
321 SIZE_T cbTag )
322{
323 BYTE nonce[12];
324 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
325
326 if ( (pSession->flags & SYMCRYPT_FLAG_SESSION_ENCRYPT) != 0 )
327 {
328 scError = SYMCRYPT_INVALID_ARGUMENT;
329 goto cleanup;
330 }
331
332 // Check for messageNumbers which are too high or not valid
334 {
335 scError = SYMCRYPT_INVALID_ARGUMENT;
336 goto cleanup;
337 }
338
339 // Check whether we are definitely too late to proceed before attempting to acquire mutex
340 // Do not need atomic read of full replayState here, but do need atomic 64b read of
341 // pSession->replayState.messageNumber
342 if ( messageNumber <= (UINT64) SYMCRYPT_ATOMIC_LOAD64_RELAXED(&pSession->replayState.messageNumber) - 64 )
343 {
344 scError = SYMCRYPT_SESSION_REPLAY_FAILURE;
345 goto cleanup;
346 }
347
348 SYMCRYPT_STORE_MSBFIRST32(&nonce[0], pSession->senderId);
350
351 scError = SymCryptGcmDecrypt(
353 nonce,
354 sizeof(nonce),
355 pbAuthData,
357 pbSrc,
358 pbDst,
359 cbData,
360 pbTag,
361 cbTag);
362
363 if ( scError != SYMCRYPT_NO_ERROR )
364 {
365 goto cleanup; // wipes pbDst twice, but we don't care about performance in the error case
366 }
367
369
370cleanup:
371 if ( scError != SYMCRYPT_NO_ERROR )
372 {
374 }
375
376 return scError;
377}
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
unsigned __int64 * PUINT64
Definition: basetsd.h:181
#define NULL
Definition: types.h:112
static void cleanup(void)
Definition: main.c:1335
GLbitfield flags
Definition: glext.h:7161
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _Out_writes_(s)
Definition: no_sal2.h:176
#define _Out_
Definition: no_sal2.h:160
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
BYTE * PBYTE
Definition: pedump.c:66
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionGcmDecrypt(_Inout_ PSYMCRYPT_SESSION pSession, UINT64 messageNumber, _In_ PCSYMCRYPT_GCM_EXPANDED_KEY pExpandedKey, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData, _In_reads_(cbTag) PCBYTE pbTag, SIZE_T cbTag)
Definition: session.c:311
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionDecryptUpdateStateLock(_Inout_ PSYMCRYPT_SESSION pSession, UINT64 messageNumber)
Definition: session.c:247
FORCEINLINE SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionDecryptComputeDesiredReplayState(_In_ PCSYMCRYPT_SESSION_REPLAY_STATE observedState, _Out_ PSYMCRYPT_SESSION_REPLAY_STATE desiredState, UINT64 messageNumber)
Definition: session.c:150
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionReceiverInit(_Inout_ PSYMCRYPT_SESSION pSession, UINT32 senderId, UINT32 flags)
Definition: session.c:32
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionDecryptUpdateState(_Inout_ PSYMCRYPT_SESSION pSession, UINT64 messageNumber)
Definition: session.c:285
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionGcmEncrypt(_Inout_ PSYMCRYPT_SESSION pSession, _In_ PCSYMCRYPT_GCM_EXPANDED_KEY pExpandedKey, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData, _Out_writes_(cbTag) PBYTE pbTag, SIZE_T cbTag, _Out_opt_ PUINT64 pu64MessageNumber)
Definition: session.c:87
VOID SYMCRYPT_CALL SymCryptSessionDestroy(_Inout_ PSYMCRYPT_SESSION pSession)
Definition: session.c:76
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSessionSenderInit(_Inout_ PSYMCRYPT_SESSION pSession, UINT32 senderId, UINT32 flags)
Definition: session.c:11
VOID SYMCRYPT_CALL SymCryptCallbackFreeMutexFastInproc(_Inout_ PVOID pMutex)
FORCEINLINE VOID SYMCRYPT_CALL SymCryptWipeKnownSize(_Out_writes_bytes_(cbData) PVOID pbData, SIZE_T cbData)
VOID SYMCRYPT_CALL SymCryptCallbackAcquireMutexFastInproc(_Inout_ PVOID pMutex)
VOID SYMCRYPT_CALL SymCryptWipe(_Out_writes_bytes_(cbData) PVOID pbData, SIZE_T cbData)
Definition: libmain.c:137
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptGcmDecrypt(_In_ PCSYMCRYPT_GCM_EXPANDED_KEY pExpandedKey, _In_reads_(cbNonce) PCBYTE pbNonce, SIZE_T cbNonce, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData, _In_reads_(cbTag) PCBYTE pbTag, SIZE_T cbTag)
Definition: gcm.c:731
PVOID SYMCRYPT_CALL SymCryptCallbackAllocateMutexFastInproc(void)
VOID SYMCRYPT_CALL SymCryptCallbackReleaseMutexFastInproc(_Inout_ PVOID pMutex)
VOID SYMCRYPT_CALL SymCryptGcmEncrypt(_In_ PCSYMCRYPT_GCM_EXPANDED_KEY pExpandedKey, _In_reads_(cbNonce) PCBYTE pbNonce, SIZE_T cbNonce, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData, _Out_writes_(cbTag) PBYTE pbTag, SIZE_T cbTag)
Definition: gcm.c:618
#define SYMCRYPT_STORE_MSBFIRST32(p, v)
Definition: symcrypt.h:311
#define SYMCRYPT_STORE_MSBFIRST64(p, v)
Definition: symcrypt.h:312
SYMCRYPT_ERROR
Definition: symcrypt.h:227
SIZE_T cbTag
PCBYTE pbSrc
#define SYMCRYPT_CALL
SYMCRYPT_SESSION_REPLAY_STATE
UINT64 messageNumber
#define SYMCRYPT_SESSION_MAX_MESSAGE_NUMBER
#define SYMCRYPT_FLAG_SESSION_ENCRYPT
UINT64 cbAuthData
const SYMCRYPT_SESSION_REPLAY_STATE * PCSYMCRYPT_SESSION_REPLAY_STATE
#define SYMCRYPT_CPU_FEATURES_PRESENT(x)
* PSYMCRYPT_SESSION
PCBYTE PBYTE SIZE_T cbData
PCBYTE PBYTE pbDst
* PSYMCRYPT_SESSION_REPLAY_STATE
PVOID pMutex
const SYMCRYPT_GCM_EXPANDED_KEY * PCSYMCRYPT_GCM_EXPANDED_KEY
const BYTE * PCBYTE
UINT32 senderId
UINT32 nonce[3]
PCVOID pExpandedKey
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t UINT32
Definition: typedefs.h:59
#define FORCEINLINE
Definition: wdftypes.h:67
unsigned char BYTE
Definition: xxhash.c:193