/* Update session information in the cache. This is called when we've determined the master secret and when we're closing the connection to update various values in the cache. */ int32 matrixUpdateSession(ssl_t *ssl) { char *id; uint32 i; if (!(ssl->flags & SSL_FLAGS_SERVER)) { return -1; } if ((id = ssl->sessionId) == NULL) { return -1; } i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; if (i < 0 || i >= SSL_SESSION_TABLE_SIZE) { return -1; } /* If there is an error on the session, invalidate for any future use */ sslLockMutex(&sessionTableLock); sessionTable[i].inUse = ssl->flags & SSL_FLAGS_CLOSED ? 0 : 1; if (ssl->flags & SSL_FLAGS_ERROR) { memset(sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE); sessionTable[i].cipher = NULL; sslUnlockMutex(&sessionTableLock); return -1; } memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret, SSL_HS_MASTER_SIZE); sessionTable[i].cipher = ssl->cipher; sslUnlockMutex(&sessionTableLock); return 0; }
int32 matrixSslGetResumptionFlag(ssl_t *ssl, char *flag) { char *id; uint32 i; if (!(ssl->flags & SSL_FLAGS_SERVER)) { return -1; } if ((id = ssl->sessionId) == NULL) { return -1; } i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; if (i < 0 || i >= SSL_SESSION_TABLE_SIZE) { return -1; } sslLockMutex(&sessionTableLock); sessionTable[i].inUse = ssl->flags & SSL_FLAGS_CLOSED ? 0 : 1; if (ssl->flags & SSL_FLAGS_ERROR) { sslUnlockMutex(&sessionTableLock); return -1; } *flag = sessionTable[i].flag; sslUnlockMutex(&sessionTableLock); return 0; }
/* Clear the inUse flag during re-handshakes so the entry may be found */ int32 matrixClearSession(ssl_t *ssl, int32 remove) { char *id; uint32 i; if (ssl->sessionIdLen <= 0) { return -1; } id = ssl->sessionId; i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; if (i >= SSL_SESSION_TABLE_SIZE || i < 0) { return -1; } sslLockMutex(&sessionTableLock); sessionTable[i].inUse = 0; sessionTable[i].flag = 0; /* If this is a full removal, actually delete the entry rather than just setting the inUse to 0. Also need to clear any RESUME flag on the ssl connection so a new session will be correctly registered. */ if (remove) { memset(ssl->sessionId, 0x0, SSL_MAX_SESSION_ID_SIZE); ssl->sessionIdLen = 0; memset(&sessionTable[i], 0x0, sizeof(sslSessionEntry_t)); ssl->flags &= ~SSL_FLAGS_RESUMED; } sslUnlockMutex(&sessionTableLock); return 0; }
void sslDestroyMutex(sslMutex_t *mutex) { if (mutex == NULL) { return; } sslLockMutex(mutex); semDelete((SEM_ID) mutex); }
/* Look up a session ID in the cache. If found, set the ssl masterSecret and cipher to the pre-negotiated values */ int32 matrixResumeSession(ssl_t *ssl) { char *id; uint32 i; if (!(ssl->flags & SSL_FLAGS_SERVER)) { return -1; } if (ssl->sessionIdLen <= 0) { return -1; } id = ssl->sessionId; i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; sslLockMutex(&sessionTableLock); if (i >= SSL_SESSION_TABLE_SIZE || i < 0 || sessionTable[i].cipher == NULL) { sslUnlockMutex(&sessionTableLock); return -1; } /* Id looks valid. Update the access time for expiration check. Expiration is done on daily basis (86400 seconds) */ sslInitMsecs(&sessionTable[i].accessTime); if (memcmp(sessionTable[i].id, id, min(ssl->sessionIdLen, SSL_MAX_SESSION_ID_SIZE)) != 0 || sslDiffSecs(sessionTable[i].startTime, sessionTable[i].accessTime) > 86400 || sessionTable[i].inUse || sessionTable[i].majVer != ssl->majVer || sessionTable[i].minVer != ssl->minVer) { sslUnlockMutex(&sessionTableLock); return -1; } memcpy(ssl->sec.masterSecret, sessionTable[i].masterSecret, SSL_HS_MASTER_SIZE); ssl->cipher = sessionTable[i].cipher; sessionTable[i].inUse = 1; sslUnlockMutex(&sessionTableLock); return 0; }
void matrixSslClose(void) { #ifdef USE_SERVER_SIDE_SSL int32 i; sslLockMutex(&sessionTableLock); for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) { if (sessionTable[i].inUse == 1) { matrixStrDebugMsg("Warning: closing while session still in use\n", NULL); } } memset(sessionTable, 0x0, sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE); sslUnlockMutex(&sessionTableLock); sslDestroyMutex(&sessionTableLock); #endif /* USE_SERVER_SIDE_SSL */ matrixPkiClose(); }
/* Register a session in the session resumption cache. If successful (rc >=0), the ssl sessionId and sessionIdLength fields will be non-NULL upon return. */ int32 matrixRegisterSession(ssl_t *ssl) { uint32 i, j; sslTime_t t; if (!(ssl->flags & SSL_FLAGS_SERVER)) { return -1; } /* Iterate the session table, looking for an empty entry (cipher null), and the oldest entry that is not in use */ sslLockMutex(&sessionTableLock); j = SSL_SESSION_TABLE_SIZE; t = sessionTable[0].accessTime; for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) { if (sessionTable[i].cipher == NULL) { break; } if (sslCompareTime(sessionTable[i].accessTime, t) && sessionTable[i].inUse == 0) { t = sessionTable[i].accessTime; j = i; } } /* If there were no empty entries, get the oldest unused entry. If all entries are in use, return -1, meaning we can't cache the session at this time */ if (i >= SSL_SESSION_TABLE_SIZE) { if (j < SSL_SESSION_TABLE_SIZE) { i = j; } else { sslUnlockMutex(&sessionTableLock); return -1; } } /* Register the incoming masterSecret and cipher, which could still be null, depending on when we're called. */ memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret, SSL_HS_MASTER_SIZE); sessionTable[i].cipher = ssl->cipher; sessionTable[i].inUse = 1; sslUnlockMutex(&sessionTableLock); /* The sessionId is the current serverRandom value, with the first 4 bytes replaced with the current cache index value for quick lookup later. FUTURE SECURITY - Should generate more random bytes here for the session id. We re-use the server random as the ID, which is OK, since it is sent plaintext on the network, but an attacker listening to a resumed connection will also be able to determine part of the original server random used to generate the master key, even if he had not seen it initially. */ memcpy(sessionTable[i].id, ssl->sec.serverRandom, min(SSL_HS_RANDOM_SIZE, SSL_MAX_SESSION_ID_SIZE)); ssl->sessionIdLen = SSL_MAX_SESSION_ID_SIZE; sessionTable[i].id[0] = (unsigned char)(i & 0xFF); sessionTable[i].id[1] = (unsigned char)((i & 0xFF00) >> 8); sessionTable[i].id[2] = (unsigned char)((i & 0xFF0000) >> 16); sessionTable[i].id[3] = (unsigned char)((i & 0xFF000000) >> 24); memcpy(ssl->sessionId, sessionTable[i].id, SSL_MAX_SESSION_ID_SIZE); /* startTime is used to check expiry of the entry accessTime is used to for cache replacement logic The versions are stored, because a cached session must be reused with same SSL version. */ sslInitMsecs(&sessionTable[i].startTime); sessionTable[i].accessTime = sessionTable[i].startTime; sessionTable[i].majVer = ssl->majVer; sessionTable[i].minVer = ssl->minVer; sessionTable[i].flag = 0; return i; }