diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 13:58:15 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 13:58:15 +0100 |
commit | 4aca87515a5083ae0e31ce3177189fd43b6d05ac (patch) | |
tree | 7b1d9a31393ca090757dc6f0d3859b4fcd93f271 /release/src/router/matrixssl/src/matrixSsl.c | |
parent | 008d0be72b2f160382c6e880765e96b64a050c65 (diff) | |
download | tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.gz tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.bz2 |
patch to Vanilla Tomato 1.28
Diffstat (limited to 'release/src/router/matrixssl/src/matrixSsl.c')
-rw-r--r-- | release/src/router/matrixssl/src/matrixSsl.c | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/release/src/router/matrixssl/src/matrixSsl.c b/release/src/router/matrixssl/src/matrixSsl.c new file mode 100644 index 00000000..1242728a --- /dev/null +++ b/release/src/router/matrixssl/src/matrixSsl.c @@ -0,0 +1,805 @@ +/* + * matrixSsl.c + * Release $Name: MATRIXSSL_1_8_8_OPEN $ + * + * Secure Sockets Layer session management + */ +/* + * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved. + * The latest version of this code is available at http://www.matrixssl.org + * + * This software is open source; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This General Public License does NOT permit incorporating this software + * into proprietary programs. If you are unable to comply with the GPL, a + * commercial license for this software may be purchased from PeerSec Networks + * at http://www.peersec.com + * + * This program is distributed in WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * http://www.gnu.org/copyleft/gpl.html + */ +/******************************************************************************/ + +#include "matrixInternal.h" + +#ifndef WINCE +#include <time.h> +#endif + +/******************************************************************************/ + +static char copyright[]= "Copyright PeerSec Networks Inc. All rights reserved."; + +#ifdef USE_SERVER_SIDE_SSL +/* + Static session table for session cache and lock for multithreaded env +*/ +static sslMutex_t sessionTableLock; +static sslSessionEntry_t sessionTable[SSL_SESSION_TABLE_SIZE]; +#endif /* USE_SERVER_SIDE_SSL */ + +/******************************************************************************/ +/* + Open and close the SSL module. These routines are called once in the + lifetime of the application and initialize and clean up the library + respectively. +*/ +int32 matrixSslOpen(void) +{ + if (matrixPkiOpen() < 0) { + matrixStrDebugMsg("PKI open failure\n", NULL); + return -1; + } + +#ifdef USE_SERVER_SIDE_SSL + memset(sessionTable, 0x0, + sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE); + sslCreateMutex(&sessionTableLock); +#endif /* USE_SERVER_SIDE_SSL */ + + + 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(); +} + +/******************************************************************************/ +/* + Wrappers around the RSA versions. Necessary to keep API backwards compat +*/ +#ifdef USE_FILE_SYSTEM +int32 matrixSslReadKeys(sslKeys_t **keys, const char *certFile, + const char *privFile, const char *privPass, + const char *trustedCAFile) +{ + return matrixX509ReadKeys(keys, certFile, privFile, privPass, trustedCAFile); +} +#endif /* USE_FILE_SYSTEM */ + +int32 matrixSslReadKeysMem(sslKeys_t **keys, unsigned char *certBuf, + int32 certLen, unsigned char *privBuf, int32 privLen, + unsigned char *trustedCABuf, int32 trustedCALen) +{ + return matrixX509ReadKeysMem(keys, certBuf, certLen, privBuf, privLen, + trustedCABuf, trustedCALen); +} + +void matrixSslFreeKeys(sslKeys_t *keys) +{ + matrixRsaFreeKeys(keys); +} + + + +/******************************************************************************/ +/* + New SSL protocol context + This structure is associated with a single SSL connection. Each socket + using SSL should be associated with a new SSL context. + + certBuf and privKey ARE NOT duplicated within the server context, in order + to minimize memory usage with multiple simultaneous requests. They must + not be deleted by caller until all server contexts using them are deleted. +*/ +int32 matrixSslNewSession(ssl_t **ssl, sslKeys_t *keys, sslSessionId_t *session, + int32 flags) +{ + psPool_t *pool = NULL; + ssl_t *lssl; + +/* + First API level chance to make sure a user is not attempting to use + client or server support that was not built into this library compile +*/ +#ifndef USE_SERVER_SIDE_SSL + if (flags & SSL_FLAGS_SERVER) { + matrixStrDebugMsg("MatrixSSL lib not compiled with server support\n", + NULL); + return -1; + } +#endif +#ifndef USE_CLIENT_SIDE_SSL + if (!(flags & SSL_FLAGS_SERVER)) { + matrixStrDebugMsg("MatrixSSL lib not compiled with client support\n", + NULL); + return -1; + } +#endif + if (flags & SSL_FLAGS_CLIENT_AUTH) { + matrixStrDebugMsg("MatrixSSL lib not compiled with client " \ + "authentication support\n", NULL); + return -1; + } + + if (flags & SSL_FLAGS_SERVER) { + if (keys == NULL) { + matrixStrDebugMsg("NULL keys in matrixSslNewSession\n", NULL); + return -1; + } + if (session != NULL) { + matrixStrDebugMsg("Server session must be NULL\n", NULL); + return -1; + } + } + + *ssl = lssl = psMalloc(pool, sizeof(ssl_t)); + if (lssl == NULL) { + return SSL_MEM_ERROR; + } + memset(lssl, 0x0, sizeof(ssl_t)); + + lssl->pool = pool; + lssl->cipher = sslGetCipherSpec(SSL_NULL_WITH_NULL_NULL); + sslActivateReadCipher(lssl); + sslActivateWriteCipher(lssl); + sslActivatePublicCipher(lssl); + + lssl->recordHeadLen = SSL3_HEADER_LEN; + lssl->hshakeHeadLen = SSL3_HANDSHAKE_HEADER_LEN; + + if (flags & SSL_FLAGS_SERVER) { + lssl->flags |= SSL_FLAGS_SERVER; +/* + Client auth can only be requested by server, not set by client +*/ + if (flags & SSL_FLAGS_CLIENT_AUTH) { + lssl->flags |= SSL_FLAGS_CLIENT_AUTH; + } + lssl->hsState = SSL_HS_CLIENT_HELLO; + } else { +/* + Client is first to set protocol version information based on + compile and/or the 'flags' parameter so header information in + the handshake messages will be correctly set. +*/ + lssl->majVer = SSL3_MAJ_VER; + lssl->minVer = SSL3_MIN_VER; + lssl->hsState = SSL_HS_SERVER_HELLO; + if (session != NULL && session->cipherId != SSL_NULL_WITH_NULL_NULL) { + lssl->cipher = sslGetCipherSpec(session->cipherId); + if (lssl->cipher == NULL) { + matrixStrDebugMsg("Invalid session id to matrixSslNewSession\n", + NULL); + } else { + memcpy(lssl->sec.masterSecret, session->masterSecret, + SSL_HS_MASTER_SIZE); + lssl->sessionIdLen = SSL_MAX_SESSION_ID_SIZE; + memcpy(lssl->sessionId, session->id, SSL_MAX_SESSION_ID_SIZE); + } + } + } + lssl->err = SSL_ALERT_NONE; + lssl->keys = keys; + + return 0; +} + +/******************************************************************************/ +/* + Delete an SSL session. Some information on the session may stay around + in the session resumption cache. + SECURITY - We memset relevant values to zero before freeing to reduce + the risk of our keys floating around in memory after we're done. +*/ +void matrixSslDeleteSession(ssl_t *ssl) +{ + + if (ssl == NULL) { + return; + } + ssl->flags |= SSL_FLAGS_CLOSED; +/* + If we have a sessionId, for servers we need to clear the inUse flag in + the session cache so the ID can be replaced if needed. In the client case + the caller should have called matrixSslGetSessionId already to copy the + master secret and sessionId, so free it now. + + In all cases except a successful updateSession call on the server, the + master secret must be freed. +*/ +#ifdef USE_SERVER_SIDE_SSL + if (ssl->sessionIdLen > 0 && (ssl->flags & SSL_FLAGS_SERVER)) { + matrixUpdateSession(ssl); + } +#endif /* USE_SERVER_SIDE_SSL */ + ssl->sessionIdLen = 0; + +#ifdef USE_CLIENT_SIDE_SSL + if (ssl->sec.cert) { + matrixX509FreeCert(ssl->sec.cert); + ssl->sec.cert = NULL; + } +#endif /* USE_CLIENT_SIDE_SSL */ + +/* + Premaster could also be allocated if this DeleteSession is the result + of a failed handshake. This test is fine since all frees will NULL pointer +*/ + if (ssl->sec.premaster) { + psFree(ssl->sec.premaster); + } + + + +/* + The cipher and mac contexts are inline in the ssl structure, so + clearing the structure clears those states as well. +*/ + memset(ssl, 0x0, sizeof(ssl_t)); + psFree(ssl); +} + +/******************************************************************************/ +/* + Generic session option control for changing already connected sessions. + (ie. rehandshake control). arg param is future for options that may + require a value. +*/ +void matrixSslSetSessionOption(ssl_t *ssl, int32 option, void *arg) +{ + if (option == SSL_OPTION_DELETE_SESSION) { +#ifdef USE_SERVER_SIDE_SSL + if (ssl->flags & SSL_FLAGS_SERVER) { + matrixClearSession(ssl, 1); + } +#endif /* USE_SERVER_SIDE_SSL */ + ssl->sessionIdLen = 0; + memset(ssl->sessionId, 0x0, SSL_MAX_SESSION_ID_SIZE); + } +} + +/******************************************************************************/ +/* + The ssl_t struct is opaque to the socket layer. Just needed an access + routine for the 'anon' status +*/ +void matrixSslGetAnonStatus(ssl_t *ssl, int32 *certArg) +{ + *certArg = ssl->sec.anon; +} + +/******************************************************************************/ +/* + Again, the ssl_t is opaque. Need to associate the new keys with + the session for mid-session rekeying +*/ +void matrixSslAssignNewKeys(ssl_t *ssl, sslKeys_t *keys) +{ + ssl->keys = keys; +} + +/******************************************************************************/ +/* + Returns 1 if we've completed the SSL handshake. 0 if we're in process. +*/ +int32 matrixSslHandshakeIsComplete(ssl_t *ssl) +{ + return (ssl->hsState == SSL_HS_DONE) ? 1 : 0; +} + +#ifdef USE_CLIENT_SIDE_SSL +/******************************************************************************/ +/* + Set a custom callback to receive the certificate being presented to the + session to perform custom authentication if needed +*/ +void matrixSslSetCertValidator(ssl_t *ssl, + int32 (*certValidator)(sslCertInfo_t *t, void *arg), void *arg) +{ + if (certValidator) { + ssl->sec.validateCert = certValidator; + ssl->sec.validateCertArg = arg; + } +} +#else /* Public API, so should always be linkable */ +void matrixSslSetCertValidator(ssl_t *ssl, + int32 (*certValidator)(sslCertInfo_t *t, void *arg), void *arg) +{ + matrixStrDebugMsg("matrixSslSetCertValidator is not available\n", NULL); + matrixStrDebugMsg("Library not built for cert validation support\n", NULL); +} +#endif /* USE_CLIENT_SIDE_SSL */ + +/******************************************************************************/ +/* + Initialize the SHA1 and MD5 hash contexts for the handshake messages +*/ +int32 sslInitHSHash(ssl_t *ssl) +{ + matrixSha1Init(&ssl->sec.msgHashSha1); + matrixMd5Init(&ssl->sec.msgHashMd5); + return 0; +} + +/******************************************************************************/ +/* + Add the given data to the running hash of the handshake messages +*/ +int32 sslUpdateHSHash(ssl_t *ssl, unsigned char *in, int32 len) +{ + matrixMd5Update(&ssl->sec.msgHashMd5, in, len); + matrixSha1Update(&ssl->sec.msgHashSha1, in, len); + return 0; +} + +/******************************************************************************/ +/* + Snapshot is called by the receiver of the finished message to produce + a hash of the preceeding handshake messages for comparison to incoming + message. +*/ +int32 sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag) +{ + sslMd5Context_t md5; + sslSha1Context_t sha1; + +/* + Use a backup of the message hash-to-date because we don't want + to destroy the state of the handshaking until truly complete +*/ + md5 = ssl->sec.msgHashMd5; + sha1 = ssl->sec.msgHashSha1; + + return sslGenerateFinishedHash(&md5, &sha1, ssl->sec.masterSecret, + out, senderFlag); +} + +/******************************************************************************/ +/* + Cipher suites are chosen before they are activated with the + ChangeCipherSuite message. Additionally, the read and write cipher suites + are activated at different times in the handshake process. The following + APIs activate the selected cipher suite callback functions. +*/ +int32 sslActivateReadCipher(ssl_t *ssl) +{ + ssl->decrypt = ssl->cipher->decrypt; + ssl->verifyMac = ssl->cipher->verifyMac; + ssl->deMacSize = ssl->cipher->macSize; + ssl->deBlockSize = ssl->cipher->blockSize; + ssl->deIvSize = ssl->cipher->ivSize; +/* + Reset the expected incoming sequence number for the new suite +*/ + memset(ssl->sec.remSeq, 0x0, sizeof(ssl->sec.remSeq)); + + if (ssl->cipher->id != SSL_NULL_WITH_NULL_NULL) { + ssl->flags |= SSL_FLAGS_READ_SECURE; +/* + Copy the newly activated read keys into the live buffers +*/ + memcpy(ssl->sec.readMAC, ssl->sec.rMACptr, ssl->cipher->macSize); + memcpy(ssl->sec.readKey, ssl->sec.rKeyptr, ssl->cipher->keySize); + memcpy(ssl->sec.readIV, ssl->sec.rIVptr, ssl->cipher->ivSize); +/* + set up decrypt contexts + */ + if (ssl->cipher->init(&(ssl->sec), INIT_DECRYPT_CIPHER) < 0) { + matrixStrDebugMsg("Unable to initialize read cipher suite\n", NULL); + return -1; + } + } + return 0; +} + +int32 sslActivateWriteCipher(ssl_t *ssl) +{ + + ssl->encrypt = ssl->cipher->encrypt; + ssl->generateMac = ssl->cipher->generateMac; + ssl->enMacSize = ssl->cipher->macSize; + ssl->enBlockSize = ssl->cipher->blockSize; + ssl->enIvSize = ssl->cipher->ivSize; +/* + Reset the outgoing sequence number for the new suite +*/ + memset(ssl->sec.seq, 0x0, sizeof(ssl->sec.seq)); + if (ssl->cipher->id != SSL_NULL_WITH_NULL_NULL) { + ssl->flags |= SSL_FLAGS_WRITE_SECURE; +/* + Copy the newly activated write keys into the live buffers +*/ + memcpy(ssl->sec.writeMAC, ssl->sec.wMACptr, ssl->cipher->macSize); + memcpy(ssl->sec.writeKey, ssl->sec.wKeyptr, ssl->cipher->keySize); + memcpy(ssl->sec.writeIV, ssl->sec.wIVptr, ssl->cipher->ivSize); +/* + set up encrypt contexts + */ + if (ssl->cipher->init(&(ssl->sec), INIT_ENCRYPT_CIPHER) < 0) { + matrixStrDebugMsg("Unable to init write cipher suite\n", NULL); + return -1; + } + } + return 0; +} + +int32 sslActivatePublicCipher(ssl_t *ssl) +{ + ssl->encryptPriv = ssl->cipher->encryptPriv; + ssl->decryptPub = ssl->cipher->decryptPub; + ssl->decryptPriv = ssl->cipher->decryptPriv; + ssl->encryptPub = ssl->cipher->encryptPub; + if (ssl->cipher->id != SSL_NULL_WITH_NULL_NULL) { + ssl->flags |= SSL_FLAGS_PUBLIC_SECURE; + } + return 0; +} + +#ifdef USE_SERVER_SIDE_SSL +/******************************************************************************/ +/* + 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; +} + +/******************************************************************************/ +/* + 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; +} + +/******************************************************************************/ +/* + 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; +} + +/******************************************************************************/ +/* + 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 matrixSslSetResumptionFlag(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; + } + sessionTable[i].flag = flag; + 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; +} +#endif /* USE_SERVER_SIDE_SSL */ + +#ifdef USE_CLIENT_SIDE_SSL +/******************************************************************************/ +/* + Get session information from the ssl structure and populate the given + session structure. Session will contain a copy of the relevant session + information, suitable for creating a new, resumed session. +*/ +int32 matrixSslGetSessionId(ssl_t *ssl, sslSessionId_t **session) +{ + sslSessionId_t *lsession; + + if (ssl == NULL || ssl->flags & SSL_FLAGS_SERVER) { + return -1; + } + + if (ssl->cipher != NULL && ssl->cipher->id != SSL_NULL_WITH_NULL_NULL && + ssl->sessionIdLen == SSL_MAX_SESSION_ID_SIZE) { + *session = lsession = psMalloc(PEERSEC_BASE_POOL, + sizeof(sslSessionId_t)); + if (lsession == NULL) { + return SSL_MEM_ERROR; + } + lsession->cipherId = ssl->cipher->id; + memcpy(lsession->id, ssl->sessionId, ssl->sessionIdLen); + memcpy(lsession->masterSecret, ssl->sec.masterSecret, + SSL_HS_MASTER_SIZE); + return 0; + } + return -1; +} + +/******************************************************************************/ +/* + Must be called on session returned from matrixSslGetSessionId +*/ +void matrixSslFreeSessionId(sslSessionId_t *sessionId) +{ + if (sessionId != NULL) { + psFree(sessionId); + } +} +#endif /* USE_CLIENT_SIDE_SSL */ + +/******************************************************************************/ +/* + Rehandshake. Free any allocated sec members that will be repopulated +*/ +void sslResetContext(ssl_t *ssl) +{ +#ifdef USE_SERVER_SIDE_SSL + if (ssl->flags & SSL_FLAGS_SERVER) { +/* + Clear the inUse flag of the current session so it may be found again + if client attempts to reuse session id +*/ + matrixClearSession(ssl, 0); + } +#endif /* USE_SERVER_SIDE_SSL */ + +} + +/******************************************************************************/ + + + |