/* matrixSslClose */ void matrixSslClose(void) { #ifdef USE_SERVER_SIDE_SSL int32 i; #ifdef USE_MULTITHREADING psLockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) { if (sessionTable[i].inUse > 1) { psTraceInfo("Warning: closing while session still in use\n"); } } memset(sessionTable, 0x0, sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE); #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); psDestroyMutex(&sessionTableLock); psUnlockMutex(&prngLock); psDestroyMutex(&prngLock); #endif /* USE_MULTITHREADING */ #endif /* USE_SERVER_SIDE_SSL */ psCoreClose(); }
/* Decrement inUse to keep the reference count meaningful */ int32 matrixClearSession(ssl_t *ssl, int32 remove) { char *id; uint32 i; if (ssl->sessionIdLen <= 0) { return PS_ARG_FAIL; } id = ssl->sessionId; i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; if (i >= SSL_SESSION_TABLE_SIZE) { return PS_LIMIT_FAIL; } #ifdef USE_MULTITHREADING psLockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ sessionTable[i].inUse -= 1; /* If this is a full removal, actually delete the entry. 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; } #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_SUCCESS; }
/* MatrixSSL PRNG retrieval */ int32 matrixSslGetPrngData(unsigned char *bytes, uint32 size) { int32 rc; #ifdef USE_MULTITHREADING psLockMutex(&prngLock); #endif /* USE_MULTITHREADING */ rc = psGetPrng(&gMatrixsslPrng, bytes, size); #ifdef USE_MULTITHREADING psUnlockMutex(&prngLock); #endif /* USE_MULTITHREADING */ return rc; }
/* 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 PS_ARG_FAIL; } if (ssl->sessionIdLen <= 0) { return PS_ARG_FAIL; } id = ssl->sessionId; i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; #ifdef USE_MULTITHREADING psLockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ if (i >= SSL_SESSION_TABLE_SIZE || sessionTable[i].cipher == NULL) { #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_LIMIT_FAIL; } /* Id looks valid. Update the access time for expiration check. Expiration is done on daily basis (86400 seconds) */ psGetTime(&sessionTable[i].accessTime); if ((memcmp(sessionTable[i].id, id, (uint32)min(ssl->sessionIdLen, SSL_MAX_SESSION_ID_SIZE)) != 0) || (psDiffMsecs(sessionTable[i].startTime, sessionTable[i].accessTime) > SSL_SESSION_ENTRY_LIFE) || (sessionTable[i].majVer != ssl->majVer) || (sessionTable[i].minVer != ssl->minVer)) { #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_FAILURE; } memcpy(ssl->sec.masterSecret, sessionTable[i].masterSecret, SSL_HS_MASTER_SIZE); ssl->cipher = sessionTable[i].cipher; sessionTable[i].inUse += 1; #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_SUCCESS; }
/* Blindly append a CRL to the g_CRL list. Consider psCRL_Update instead. 1 - Added, 0 - Didn't */ int psCRL_Insert(psX509Crl_t *crl) { int rc; # ifdef USE_MULTITHREADING psLockMutex(&g_crlTableLock); # endif /* USE_MULTITHREADING */ rc = internalCRLInsert(crl); # ifdef USE_MULTITHREADING psUnlockMutex(&g_crlTableLock); # endif /* USE_MULTITHREADING */ return rc; }
/* Main PRNG retrieval API for Matrix based apps to lock all PRNG and entropy fetches */ int32 matrixCryptoGetPrngData(unsigned char *bytes, uint32 size, void *userPtr) { int32 rc; if (gPrngInit == 0) { return PS_FAILURE; } #ifdef USE_MULTITHREADING psLockMutex(&prngLock); #endif /* USE_MULTITHREADING */ rc = psGetPrng(&gMatrixPrng, bytes, size, userPtr); #ifdef USE_MULTITHREADING psUnlockMutex(&prngLock); #endif /* USE_MULTITHREADING */ return rc; }
/* 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 PS_ARG_FAIL; } if ((id = ssl->sessionId) == NULL) { return PS_ARG_FAIL; } i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; if (i >= SSL_SESSION_TABLE_SIZE) { return PS_LIMIT_FAIL; } /* If there is an error on the session, invalidate for any future use */ #ifdef USE_MULTITHREADING psLockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ sessionTable[i].inUse += ssl->flags & SSL_FLAGS_CLOSED ? -1 : 0; if (ssl->flags & SSL_FLAGS_ERROR) { memset(sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE); sessionTable[i].cipher = NULL; #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_FAILURE; } memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret, SSL_HS_MASTER_SIZE); sessionTable[i].cipher = ssl->cipher; #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_SUCCESS; }
/* 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; psTime_t t; if (!(ssl->flags & SSL_FLAGS_SERVER)) { return PS_FAILURE; } /* Iterate the session table, looking for an empty entry (cipher null), or the oldest entry that is not in use */ #ifdef USE_MULTITHREADING psLockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ 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 (psCompareTime(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 { #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ return PS_LIMIT_FAIL; } } /* 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; #ifdef USE_MULTITHREADING psUnlockMutex(&sessionTableLock); #endif /* USE_MULTITHREADING */ /* 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. */ psGetTime(&sessionTable[i].startTime); sessionTable[i].accessTime = sessionTable[i].startTime; sessionTable[i].majVer = ssl->majVer; sessionTable[i].minVer = ssl->minVer; return i; }