summaryrefslogtreecommitdiff
path: root/release/src/router/matrixssl/src/matrixSsl.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
commit4aca87515a5083ae0e31ce3177189fd43b6d05ac (patch)
tree7b1d9a31393ca090757dc6f0d3859b4fcd93f271 /release/src/router/matrixssl/src/matrixSsl.c
parent008d0be72b2f160382c6e880765e96b64a050c65 (diff)
downloadtomato-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.c805
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 */
+
+}
+
+/******************************************************************************/
+
+
+