Exemplo n.º 1
0
/*
	Validate the cert chain and the private key for the material passed
	to matrixSslReadKeys.  Good to catch any user certifiate errors as
	soon as possible
*/
static int32 verifyReadKeys(psPool_t *pool, sslKeys_t *keys)
{
#ifdef USE_CERT_PARSE
	psX509Cert_t	*tmp;
#endif

	if (keys->cert == NULL && keys->privKey == NULL) {
		return PS_SUCCESS;
	}	
/*
	 Not allowed to have a certficate with no matching private key or 
	 private key with no cert to match with
*/
	if (keys->cert != NULL && keys->privKey == NULL) {
		psTraceInfo("No private key given to matrixSslReadKeys cert\n");
		return PS_CERT_AUTH_FAIL;
	}
	if (keys->privKey != NULL && keys->cert == NULL) {
		psTraceInfo("No cert given with private key to matrixSslReadKeys\n");
		return PS_CERT_AUTH_FAIL;
	}
#ifdef USE_CERT_PARSE	
/*
	If this is a chain, we can validate it here with psX509AuthenticateCert
	Don't check the error return code from this call because the chaining
	usage restrictions will test parent-most cert for self-signed.
	 
	But we can look at 'authStatus' on all but the final cert to see
	if the rest looks good
*/
	if (keys->cert != NULL && keys->cert->next != NULL) {
		psX509AuthenticateCert(pool, keys->cert, NULL);
		tmp = keys->cert;
		while (tmp->next != NULL) {
			if (tmp->authStatus != PS_TRUE) {
				psTraceInfo("Failed to authenticate cert chain\n");
				return PS_CERT_AUTH_FAIL;
			}
			tmp = tmp->next;
		}
	}

	if (keys->privKey != NULL && keys->privKey->type == PS_RSA) {
/*
		Testing the N member just as a sanity measure rather than
		attempting a full RSA crypt operation
*/
		if (pstm_cmp(&(keys->privKey->key->rsa.N),
				   &(keys->cert->publicKey.key->rsa.N)) != PSTM_EQ) {
			psTraceInfo("Private key doesn't match cert\n");	
			return PS_CERT_AUTH_FAIL;
		}
	}
#endif /* USE_CERT_PARSE */	
	return PS_SUCCESS;
}
Exemplo n.º 2
0
		/* User must re-enable rehandshaking before adding credits */
		if (ssl->rehandshakeCount >= 0) {
			if ((ssl->rehandshakeCount + credits) < 0x8000) {
				ssl->rehandshakeCount += credits;
			}
		}
	}
}

#else /* !SSL_REHANDSHAKES_ENABLED */
int32 matrixSslEncodeRehandshake(ssl_t *ssl, sslKeys_t *keys,
				int32 (*certCb)(ssl_t *ssl, psX509Cert_t *cert, int32 alert),
				uint32 sessionOption, uint32 cipherSpec[], uint16 cipherSpecLen)
{
	psTraceInfo("Rehandshaking is disabled.  matrixSslEncodeRehandshake off\n");
	return PS_FAILURE;
}
Exemplo n.º 3
0
/*
	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();
}
Exemplo n.º 4
0
/*
 *	Generates all key material.
 */
int32 sslDeriveKeys(ssl_t *ssl)
{
	psDigestContext_t	md5Ctx, sha1Ctx;
	unsigned char		buf[MD5_HASH_SIZE + SHA1_HASH_SIZE];
	unsigned char		*tmp;
	uint32				i;

/*
	If this session is resumed, we want to reuse the master secret to 
	regenerate the key block with the new random values.
*/
	if (ssl->flags & SSL_FLAGS_RESUMED) {
		goto skipPremaster;
	}
/*
	master_secret =
		MD5(pre_master_secret + SHA('A' + pre_master_secret +
			ClientHello.random + ServerHello.random)) +
		MD5(pre_master_secret + SHA('BB' + pre_master_secret +
			ClientHello.random + ServerHello.random)) +
		MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
			ClientHello.random + ServerHello.random));
*/
	tmp = ssl->sec.masterSecret;
	for (i = 0; i < 3; i++) {
		psSha1Init(&sha1Ctx);
		psSha1Update(&sha1Ctx, salt[i], i + 1);
		psSha1Update(&sha1Ctx, ssl->sec.premaster, ssl->sec.premasterSize);
		psSha1Update(&sha1Ctx, ssl->sec.clientRandom, SSL_HS_RANDOM_SIZE);
		psSha1Update(&sha1Ctx, ssl->sec.serverRandom, SSL_HS_RANDOM_SIZE);
		psSha1Final(&sha1Ctx, buf);
		
		psMd5Init(&md5Ctx);
		psMd5Update(&md5Ctx, ssl->sec.premaster, ssl->sec.premasterSize);
		psMd5Update(&md5Ctx, buf, SHA1_HASH_SIZE);
		psMd5Final(&md5Ctx, tmp);
		tmp += MD5_HASH_SIZE;
	}
	memset(buf, 0x0, MD5_HASH_SIZE + SHA1_HASH_SIZE);
/*
	premaster is now allocated for DH reasons.  Can free here
*/
	psFree(ssl->sec.premaster);
	ssl->sec.premaster = NULL;
	ssl->sec.premasterSize = 0;

skipPremaster:
	if (createKeyBlock(ssl, ssl->sec.clientRandom, ssl->sec.serverRandom, 
			ssl->sec.masterSecret, SSL_HS_MASTER_SIZE) < 0) {
		psTraceInfo("Unable to create key block\n");
		return PS_FAILURE;
	}
	
	return SSL_HS_MASTER_SIZE;
}
Exemplo n.º 5
0
/*
	Add a pre-shared key and ID to the static table in the first NULL spot
*/
int32 matrixSslLoadPsk(sslKeys_t *keys, unsigned char *key, uint32 keyLen,
				unsigned char *id, uint32 idLen)
{
	psPsk_t		*psk, *list;

	if (keys == NULL || key == NULL || id == NULL) {
		return PS_ARG_FAIL;
	}
	if (keyLen > SSL_PSK_MAX_KEY_SIZE) {
		psTraceIntInfo("Can't add PSK.  Key too large: %d\n", keyLen);
		return PS_ARG_FAIL;
	}

	if (idLen > SSL_PSK_MAX_ID_SIZE) {
		psTraceIntInfo("Can't add PSK.  Key ID too large: %d\n", idLen);
		return PS_ARG_FAIL;
	}

	if (keyLen < 1 || idLen < 1) {
		psTraceInfo("Can't add PSK. Both key and identity length must be >0\n");
		return PS_ARG_FAIL;
	}
	
	if ((psk = psMalloc(keys->pool, sizeof(psPsk_t))) == NULL) {
		return PS_MEM_FAIL;
	}
	memset(psk, 0, sizeof(psPsk_t));
	
	if ((psk->pskKey = psMalloc(keys->pool, keyLen)) == NULL) {
		psFree(psk);
		return PS_MEM_FAIL;
	}
	if ((psk->pskId = psMalloc(keys->pool, idLen)) == NULL) {
		psFree(psk->pskKey);
		psFree(psk);
		return PS_MEM_FAIL;
	}
	memcpy(psk->pskKey, key, keyLen);
	psk->pskLen = keyLen;
	
	memcpy(psk->pskId, id, idLen);
	psk->pskIdLen = idLen;
	
	if (keys->pskKeys == NULL) {
		keys->pskKeys = psk;
	} else {
		list = keys->pskKeys;
		while (list->next != NULL) {
			list = list->next;
		}
		list->next = psk;
	}
		
	return 0;
}
Exemplo n.º 6
0
/*
	Get the key from the pre-shared list based on id
*/
int32 matrixSslPskGetKey(ssl_t *ssl, unsigned char *id, uint32 idLen,
		unsigned char **key, uint32 *keyLen)
{
	psPsk_t	*psk;

	*key = NULL;

	psk = ssl->keys->pskKeys;

	if (psk == NULL) {
		psTraceInfo("No pre-shared keys loaded\n");
		return PS_FAILURE;
	}
	
	if (idLen <= 0) {
		psTraceIntInfo("Bad PSK identity length: %d\n", idLen);
		return PS_ARG_FAIL;
	}

/*
	Make sure the length matches as well
*/
	while (psk) {
		if ((uint32)psk->pskIdLen == idLen) {
			if (memcmp(psk->pskId, id, idLen) == 0) {
				*key = psk->pskKey;
				*keyLen = psk->pskLen;
				return PS_SUCCESS;
			}
		}
		psk = psk->next;
	}

	psTraceInfo("Can't find PSK key from id\n");
	return PS_SUCCESS;
}
Exemplo n.º 7
0
/*
	Get the id from the pre-shared key table based on given SSL session
	hint and hintLen are not currently used for the lookup
*/
int32 matrixSslPskGetKeyId(ssl_t *ssl, unsigned char **id, uint32 *idLen,
		char *hint, uint32 hintLen)
{
	psPsk_t	*psk;

	psk = ssl->keys->pskKeys;

	if (psk == NULL) {
		psTraceInfo("No pre-shared keys loaded\n");
		return PS_FAILURE;
	}
	
	*id = psk->pskId;
	*idLen = psk->pskIdLen;
	return PS_SUCCESS;
}
Exemplo n.º 8
0
/*
	File should be a binary .p12 or .pfx 
*/
int32 matrixSslLoadPkcs12(sslKeys_t *keys, unsigned char *certFile,
			unsigned char *importPass, int32 ipasslen,
			unsigned char *macPass, int32 mpasslen, int32 flags)
{
	unsigned char	*mPass;
	psPool_t	*pool;
	int32		rc;

	if (keys == NULL) {
		return PS_ARG_FAIL;
	}
	pool = keys->pool;
	
	if (macPass == NULL) {
		mPass = importPass;
		mpasslen = ipasslen;
	} else {
		mPass = macPass;
	}
		
	if ((rc = psPkcs12Parse(pool, &keys->cert, &keys->privKey, certFile, flags,
			importPass, ipasslen, mPass, mpasslen)) < 0) {
		if (keys->cert) {
			psX509FreeCert(keys->cert);
			keys->cert = NULL;
		}
		if (keys->privKey) {
			psFreePubKey(keys->privKey);
			keys->privKey = NULL;
		}
		return rc;
	}
	ReorderCertChain(keys->cert);
#ifdef USE_SERVER_SIDE_SSL
	if (verifyReadKeys(pool, keys) < PS_SUCCESS) {
		psTraceInfo("PKCS#12 parse success but material didn't validate\n");
		psX509FreeCert(keys->cert);
		psFreePubKey(keys->privKey);
		keys->cert = NULL;
		keys->privKey = NULL;
		return PS_CERT_AUTH_FAIL;
	}
#endif /* USE_SERVER_SIDE_SSL */	
	return PS_SUCCESS;
}
Exemplo n.º 9
0
/*
	Calls a user defined callback to allow for manual validation of the
	certificate.
*/
int32 matrixUserCertValidator(ssl_t *ssl, int32 alert, 
							  psX509Cert_t *subjectCert,
							  sslCertCb_t certValidator)
{
	int32			status;

/*
	If there is no callback, return PS_SUCCESS because there has already been
	a test for the case where the certificate did NOT PASS pubkey test
	and a callback does not exist to manually handle.  
	
	It is highly recommended that the user manually verify, but the cert
	material has internally authenticated and the user has implied that
	is sufficient enough.
*/
	if (certValidator == NULL) {
		psTraceInfo("Internal cert auth passed. No user callback registered\n");
		return PS_SUCCESS;
	}
	
/*
	Finally, let the user know what the alert status is and 
	give them the cert material to access.  Any non-zero value in alert
	indicates there is a pending fatal alert.	
	 
	The user can look at authStatus members if they want to examine the cert
	that did not pass.
*/
	if (alert == SSL_ALERT_NONE) {
		status = 0;
	} else {
		status = alert;
	}

/*
	The user callback
*/
	return certValidator(ssl, subjectCert, status);
}
Exemplo n.º 10
0
void matrixSslPrintHSDetails(ssl_t *ssl)
{
	if (ssl->hsState == SSL_HS_DONE) {
		psTraceInfo("\n");
		if (ssl->minVer == SSL3_MIN_VER) {
			psTraceInfo("SSL 3.0 ");
		} else if (ssl->minVer == TLS_MIN_VER) {
			psTraceInfo("TLS 1.0 ");
		} else if (ssl->minVer == TLS_1_1_MIN_VER) {
			psTraceInfo("TLS 1.1 ");
		} else if (ssl->minVer == TLS_1_2_MIN_VER) {
			psTraceInfo("TLS 1.2 ");
		}
		psTraceInfo("connection established: ");
		switch (ssl->cipher->ident) {
			case SSL_RSA_WITH_NULL_MD5:
				psTraceInfo("SSL_RSA_WITH_NULL_MD5\n");
				break;
			case SSL_RSA_WITH_NULL_SHA:
				psTraceInfo("SSL_RSA_WITH_NULL_SHA\n");
				break;
			case SSL_RSA_WITH_RC4_128_MD5:
				psTraceInfo("SSL_RSA_WITH_RC4_128_MD5\n");
				break;
			case SSL_RSA_WITH_RC4_128_SHA:
				psTraceInfo("SSL_RSA_WITH_RC4_128_SHA\n");
				break;
			case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
				psTraceInfo("SSL_RSA_WITH_3DES_EDE_CBC_SHA\n");
				break;
			case TLS_RSA_WITH_AES_128_CBC_SHA:
				psTraceInfo("TLS_RSA_WITH_AES_128_CBC_SHA\n");
				break;
			case TLS_RSA_WITH_AES_256_CBC_SHA:
				psTraceInfo("TLS_RSA_WITH_AES_256_CBC_SHA\n");
				break;
			default:
				psTraceIntInfo("!!!! DEFINE ME %d !!!!\n", ssl->cipher->ident);
		}
		//psTraceBytes("	Master Secret", ssl->sec.masterSecret,
		//	SSL_HS_MASTER_SIZE);
	}
	return;
}
Exemplo n.º 11
0
/*
	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) {
		psTraceInfo("SSL_FLAGS_SERVER passed to matrixSslNewSession but MatrixSSL lib was not compiled with server support\n");
		return PS_ARG_FAIL;
	}
#endif

#ifndef USE_CLIENT_SIDE_SSL
	if (!(flags & SSL_FLAGS_SERVER)) {
		psTraceInfo("SSL_FLAGS_SERVER was not passed to matrixSslNewSession but MatrixSSL was not compiled with client support\n");
		return PS_ARG_FAIL;
	}
#endif

	if (flags & SSL_FLAGS_CLIENT_AUTH) {
		psTraceInfo("SSL_FLAGS_CLIENT_AUTH passed to matrixSslNewSession but MatrixSSL was not compiled with USE_CLIENT_AUTH enabled\n");
		return PS_ARG_FAIL;
	}

	if (flags & SSL_FLAGS_SERVER) {
		if (keys == NULL) {
			psTraceInfo("NULL keys parameter passed to matrixSslNewSession\n");
			return PS_ARG_FAIL;
		}
		if (session != NULL) {
			psTraceInfo("Ignoring session parameter to matrixSslNewSession\n");
		}
	}

	*ssl = lssl = psMalloc(pool, sizeof(ssl_t));
	if (lssl == NULL) {
		psTraceInfo("Out of memory for ssl_t in matrixSslNewSession\n");
		return PS_MEM_FAIL;
	}
	memset(lssl, 0x0, sizeof(ssl_t));


/*
	Data buffers
*/
	lssl->outsize = SSL_DEFAULT_OUT_BUF_SIZE;
	lssl->outbuf = psMalloc(MATRIX_NO_POOL, lssl->outsize);
	if (lssl->outbuf == NULL) {
		psTraceInfo("Out of memory for outbuf in matrixSslNewSession\n");
		psFree(lssl);
		return PS_MEM_FAIL;
	}
	lssl->insize = SSL_DEFAULT_IN_BUF_SIZE;
	lssl->inbuf = psMalloc(MATRIX_NO_POOL, lssl->insize);
	if (lssl->inbuf == NULL) {
		psTraceInfo("Out of memory for inbuf in matrixSslNewSession\n");
		psFree(lssl->outbuf);
		psFree(lssl);
		return PS_MEM_FAIL;
	}

	lssl->sPool = pool;
	lssl->keys = keys;
	lssl->cipher = sslGetCipherSpec(lssl, SSL_NULL_WITH_NULL_NULL);
	sslActivateReadCipher(lssl);
	sslActivateWriteCipher(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.
*/
#ifdef USE_TLS
#ifndef DISABLE_TLS_1_0
		lssl->majVer = TLS_MAJ_VER;
		lssl->minVer = TLS_MIN_VER;
#endif		
#if defined(USE_TLS_1_1) && !defined(DISABLE_TLS_1_1)
		lssl->majVer = TLS_MAJ_VER;
		lssl->minVer = TLS_1_1_MIN_VER;
		lssl->flags |= SSL_FLAGS_TLS_1_1;
#endif /* USE_TLS_1_1 */
		if (lssl->majVer == 0) {
			/* USE_TLS enabled but all DISABLE_TLS versions are enabled so
				use SSLv3.  Compile time tests would catch if no versions are
				enabled at all */
			lssl->majVer = SSL3_MAJ_VER;
			lssl->minVer = SSL3_MIN_VER;
		} else {
			lssl->flags |= SSL_FLAGS_TLS;
		}
		

#else /* USE_TLS */
		lssl->majVer = SSL3_MAJ_VER;
		lssl->minVer = SSL3_MIN_VER;
#endif /* USE_TLS */


		lssl->hsState = SSL_HS_SERVER_HELLO;
		if (session != NULL && session->cipherId != SSL_NULL_WITH_NULL_NULL) {
			lssl->cipher = sslGetCipherSpec(lssl, session->cipherId);
			if (lssl->cipher == NULL) {
				psTraceInfo("Invalid session id to matrixSslNewSession\n");
			} 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->sid = session;
	}
	lssl->err = SSL_ALERT_NONE;

	return PS_SUCCESS;
}
Exemplo n.º 12
0
static int32 matrixSslLoadKeyMaterialMem(sslKeys_t *keys,
				unsigned char *certBuf,	int32 certLen, unsigned char *privBuf,
				int32 privLen, unsigned char *CAbuf, int32 CAlen,
				int32 privKeyType)
{
	psPool_t	*pool;
	int32		err, flags = 0;

	if (keys == NULL) {
		return PS_ARG_FAIL;
	}
	pool = keys->pool;
	
/*
	Setting flags to store raw ASN.1 stream for SSL CERTIFICATE message use
*/
	flags = CERT_STORE_UNPARSED_BUFFER;
	
	
	if (certBuf) {	
#ifdef USE_SERVER_SIDE_SSL
		if (keys->cert != NULL) {
			return PS_UNSUPPORTED_FAIL;
		}
		if ((err = psX509ParseCert(pool, certBuf, (uint32)certLen, &keys->cert,
				flags)) < 0) {
			psX509FreeCert(keys->cert);
			keys->cert = NULL;
			return err;
		}
#else
		psTraceInfo("Ignoring certBuf in matrixSslReadKeysMem\n");
#endif /* USE_SERVER_SIDE_SSL */			
	}
	
	if (privBuf) {
#ifdef USE_SERVER_SIDE_SSL
		if (keys->privKey != NULL) {
			return PS_UNSUPPORTED_FAIL;
		}
		if (privKeyType == PS_RSA) {		
			if ((err = pkcs1ParsePrivBin(pool, privBuf, (uint32)privLen,
					&keys->privKey)) < 0) {
#ifdef USE_PKCS8
				/* Attempt a PKCS#8 but mem parse doesn't take password */ 
				if ((err = pkcs8ParsePrivBin(pool, privBuf, (uint32)privLen,
						NULL, &keys->privKey)) < 0) {
					psX509FreeCert(keys->cert); keys->cert = NULL;
					return err;
				}
#else					
				psX509FreeCert(keys->cert); keys->cert = NULL;
				return err;
#endif
			}
		}

#else
		psTraceInfo("Ignoring privBuf in matrixSslReadKeysMem\n");
#endif /* USE_SERVER_SIDE_SSL */		
	}
	
#ifdef USE_SERVER_SIDE_SSL
	if (verifyReadKeys(pool, keys) < PS_SUCCESS) {
		psX509FreeCert(keys->cert);
		psFreePubKey(keys->privKey);
		keys->privKey = NULL;
		keys->cert = NULL;
		return PS_CERT_AUTH_FAIL;
	}
#endif /* USE_SERVER_SIDE_SSL */

/*
	 Not necessary to store binary representations of CA certs
*/
	flags &= ~CERT_STORE_UNPARSED_BUFFER;	
	
	if (CAbuf) {
#ifdef USE_CLIENT_SIDE_SSL
		if (keys->CAcerts != NULL) {
			return PS_UNSUPPORTED_FAIL;
		}
		if ((err = psX509ParseCert(pool, CAbuf, (uint32)CAlen, &keys->CAcerts,
				flags)) < 0) {
#ifdef USE_SERVER_SIDE_SSL		
			psFreePubKey(keys->privKey);
			psX509FreeCert(keys->cert);
			psX509FreeCert(keys->CAcerts);
			keys->privKey = NULL;
			keys->cert = keys->CAcerts = NULL;
#endif			
			return err;
		}
#else
		psTraceInfo("Ignoring CAbuf in matrixSslReadKeysMem\n");		
#endif /* USE_CLIENT_SIDE_SSL */
	}

	return PS_SUCCESS;
}
Exemplo n.º 13
0
Arquivo: tls.c Projeto: Deadolus/ecc
int32 sslActivateWriteCipher(ssl_t *ssl)
{
#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
		if (ssl->retransmit == 0) {
			ssl->oencrypt = ssl->encrypt;
			ssl->ogenerateMac = ssl->generateMac;
			ssl->oenMacSize = ssl->enMacSize;
			ssl->oenNativeHmacSize = ssl->nativeEnMacSize;
			ssl->oenBlockSize = ssl->enBlockSize;
			ssl->oenIvSize = ssl->enIvSize;
			memcpy(ssl->owriteMAC, ssl->sec.writeMAC, ssl->enMacSize);
			memcpy(&ssl->oencryptCtx, &ssl->sec.encryptCtx,
				   sizeof(psCipherContext_t));
			memcpy(ssl->owriteIV, ssl->sec.writeIV, ssl->cipher->ivSize);
		}
	}
#endif /* USE_DTLS */

	ssl->encrypt = ssl->cipher->encrypt;
	ssl->generateMac = ssl->cipher->generateMac;
	ssl->nativeEnMacSize = ssl->cipher->macSize;
	if (ssl->extFlags.truncated_hmac) {
		if (ssl->cipher->macSize > 0) { /* Only for HMAC-based ciphers */
			ssl->enMacSize = 10;
		} else {
			ssl->enMacSize = ssl->cipher->macSize;
		}
	} else {
		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->ident != SSL_NULL_WITH_NULL_NULL) {
		ssl->flags |= SSL_FLAGS_WRITE_SECURE;

#ifdef USE_TLS_1_2
		if (ssl->enMacSize == 0) {
			/* Need a concept for AEAD read and write start times for the
				cases surrounding changeCipherSpec if moving from one suite
				to another */
			ssl->flags |= SSL_FLAGS_AEAD_W;
			if (ssl->cipher->flags & CRYPTO_FLAGS_CHACHA) {
				ssl->flags &= ~SSL_FLAGS_NONCE_W;
			} else {
				ssl->flags |= SSL_FLAGS_NONCE_W;
			}
		} else {
			ssl->flags &= ~SSL_FLAGS_AEAD_W;
			ssl->flags &= ~SSL_FLAGS_NONCE_W;
		}
#endif

/*
		Copy the newly activated write keys into the live buffers
*/
		memcpy(ssl->sec.writeMAC, ssl->sec.wMACptr, ssl->enMacSize);
		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) {
			if (ssl->cipher->init(&(ssl->sec), INIT_ENCRYPT_CIPHER,
					ssl->cipher->keySize) < 0) {
				psTraceInfo("Unable to init write cipher suite\n");
				return PS_FAILURE;
			}
		}
	}
	return PS_SUCCESS;
}
Exemplo n.º 14
0
Arquivo: tls.c Projeto: Deadolus/ecc
/* Master secret generation if extended_master_secret extension is used */
int32_t tlsExtendedDeriveKeys(ssl_t *ssl)
{
	unsigned char	msSeed[SHA384_HASHLEN + LABEL_EXT_SIZE];
	unsigned char	hash[SHA384_HASHLEN];
	uint32_t		outLen;
	int32_t			rc = PS_FAIL;
	
#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS && ssl->retransmit == 1) {
		/* The keyblock is still valid from the first pass */
		return SSL_HS_MASTER_SIZE;
	}
#endif
/*
	If this session is resumed, we should reuse the master_secret to
	regenerate the key block with the new random values. We should not
	be here regenerating the master_secret!
*/
	if (ssl->extFlags.extended_master_secret == 0 ||
			ssl->flags & SSL_FLAGS_RESUMED) {
		psTraceInfo("Invalid invokation of extended key derivation.\n");
		return PS_FAIL;
	}
	
	extMasterSecretSnapshotHSHash(ssl, hash, &outLen);
/*
	master_secret = PRF(pre_master_secret, "extended master secret",
		session_hash);
*/
	memcpy(msSeed, LABEL_EXT_MASTERSEC, LABEL_EXT_SIZE);
	memcpy(msSeed + LABEL_EXT_SIZE, hash, outLen);

#ifdef USE_TLS_1_2
	if (ssl->flags & SSL_FLAGS_TLS_1_2) {
		if ((rc = prf2(ssl->sec.premaster, ssl->sec.premasterSize, msSeed,
				outLen + LABEL_EXT_SIZE, ssl->sec.masterSecret,
				SSL_HS_MASTER_SIZE, ssl->cipher->flags)) < 0) {
			return rc;
		}
#ifndef USE_ONLY_TLS_1_2
	} else {
		if ((rc = prf(ssl->sec.premaster, ssl->sec.premasterSize, msSeed,
			outLen + LABEL_EXT_SIZE, ssl->sec.masterSecret,
			SSL_HS_MASTER_SIZE)) < 0) {
			return rc;
		}
#endif
	}
#else
	if ((rc = prf(ssl->sec.premaster, ssl->sec.premasterSize, msSeed,
		outLen + LABEL_EXT_SIZE, ssl->sec.masterSecret,
		SSL_HS_MASTER_SIZE)) < 0) {
			return rc;
		}
#endif

#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
/*
		May need premaster for retransmits.  DTLS will free this when handshake
		is known to be complete
*/
		return genKeyBlock(ssl);
	}
#endif /* USE_DTLS */
/*
	 premaster is now allocated for DH reasons.  Can free here
*/
	psFree(ssl->sec.premaster, ssl->hsPool);
	ssl->sec.premaster = NULL;
	ssl->sec.premasterSize = 0;

	return genKeyBlock(ssl);
}
Exemplo n.º 15
0
/*
	Caller has received data from the network and is notifying the SSL layer
 */
int32 matrixSslReceivedData(ssl_t *ssl, uint32 bytes, unsigned char **ptbuf,
							uint32 *ptlen)
{
	unsigned char	*buf, *prevBuf;
	int32			rc, decodeRet, size, sanity, decodeErr;
	uint32			processed, start, len, reqLen;
	unsigned char	alertLevel, alertDesc;
	unsigned char	*p;

	if (!ssl || !ptbuf || !ptlen) {
		return PS_ARG_FAIL;
	}

	psAssert(ssl->outsize > 0 && ssl->outbuf != NULL);
	psAssert(ssl->insize > 0 && ssl->inbuf != NULL);
	*ptbuf = NULL;
	*ptlen = 0;
	ssl->inlen += bytes;
	if (ssl->inlen == 0) {
		return PS_SUCCESS; /* Nothing to do.  Basically a poll */
	}
	/* This is outside the loop b/c we may want to parse within inbuf later */
	buf = ssl->inbuf;
DECODE_MORE:
	/* Parameterized sanity check to avoid infinite loops */
	if (matrixSslHandshakeIsComplete(ssl)) {
		/* Minimum possible record size once negotiated */
		sanity = ssl->inlen / (SSL3_HEADER_LEN + MD5_HASH_SIZE);
	} else {
		/* Even with an SSLv2 hello, the sanity check will let 1 pass through */
		sanity = ssl->inlen / (SSL3_HEADER_LEN + SSL3_HANDSHAKE_HEADER_LEN);
	}
	if (sanity-- < 0) {
		return PS_PROTOCOL_FAIL;	/* We've tried to decode too many times */
	}
	len = ssl->inlen;
	size = ssl->insize - (buf - ssl->inbuf);
	prevBuf = buf;
	decodeRet = matrixSslDecode(ssl, &buf, &len, size, &start, &reqLen,
						 &decodeErr, &alertLevel, &alertDesc);

/*
	Convenience for the cases that expect buf to have moved
		- calculate the number of encoded bytes that were decoded
*/
	processed = buf - prevBuf;
	rc = PS_PROTOCOL_FAIL;
	switch (decodeRet) {

	case MATRIXSSL_SUCCESS:

		ssl->inlen -= processed;
		if (ssl->inlen > 0) {
			psAssert(buf > ssl->inbuf);
/*
			Pack ssl->inbuf so there is immediate maximum room for potential
			outgoing data that needs to be written
*/
			memmove(ssl->inbuf, buf, ssl->inlen);
			buf = ssl->inbuf;
			goto DECODE_MORE;	/* More data in buffer to process */
		}
/*
		In this case, we've parsed a finished message and no additional data is
		available to parse. We let the client know the handshake is complete,
		which can be used as a trigger to begin for example a HTTP request.
*/
		if (!(ssl->bFlags & BFLAG_HS_COMPLETE)) {
			if (matrixSslHandshakeIsComplete(ssl)) {
				ssl->bFlags |= BFLAG_HS_COMPLETE;
#ifdef USE_CLIENT_SIDE_SSL
				matrixSslGetSessionId(ssl, ssl->sid);
#endif /* USE_CLIENT_SIDE_SSL */
				rc = MATRIXSSL_HANDSHAKE_COMPLETE;
			} else {
				rc = MATRIXSSL_REQUEST_RECV; /* Need to recv more handshake data */
			}
		} else {
#ifdef USE_DTLS
			rc = MATRIXSSL_REQUEST_RECV; /* Got FINISHED without CCS */
#else
			/* This is an error - we shouldn't get here */
#endif
		}
		break;

#ifdef USE_DTLS
	case DTLS_RETRANSMIT:
		/* Only request a resend if last record in buffer */
		ssl->inlen -= processed;
		if (ssl->inlen > 0) {
			psAssert(buf > ssl->inbuf);
/*
			Pack ssl->inbuf so there is immediate maximum room for potential
			outgoing data that needs to be written
*/
			memmove(ssl->inbuf, buf, ssl->inlen);
			buf = ssl->inbuf;
			goto DECODE_MORE;	/* More data in buffer to process */
		}

		/* Flight will be rebuilt when matrixDtlsGetOutdata is called while
		outbuf is empty.  This is the return case where we are actually
		seeing a repeat handshake message so we know something was lost in
		flight. */
		return MATRIXSSL_REQUEST_SEND;
#endif

	case SSL_SEND_RESPONSE:
#ifdef ENABLE_FALSE_START
		/*
			If FALSE START is supported, there may be APPLICATION_DATA directly
			following the FINISHED message, even though we haven't sent our
			CHANGE_CIPHER_SPEC or FINISHED message. This is signalled by buf
			having been moved forward, and our response being put directly into
			ssl->outbuf, rather than in buf (ssl->inbuf). Return a REQUEST_SEND
			so that the data in outbuf is flushed before the remaining data in
			ssl->inbuf is parsed.
		 */
		if ((ssl->flags & SSL_FLAGS_FALSE_START) && buf != prevBuf) {
			ssl->inlen -= processed;
			psAssert(ssl->inlen > 0);
			psAssert((uint32)ssl->inlen == start);
			psAssert(buf > ssl->inbuf);
			memmove(ssl->inbuf, buf, ssl->inlen);	/* Pack ssl->inbuf */
			buf = ssl->inbuf;
			return MATRIXSSL_REQUEST_SEND;
		}
#endif
		/*
			This must be handshake data (or alert) or we'd be in PROCESS_DATA
			so there is no way there is anything left inside inbuf to process.
			...so processed isn't valid because the output params are outbuf
			related and we simply reset inlen
		*/
		ssl->inlen = 0;

		/* If alert, close connection after sending */
		if (alertDesc != SSL_ALERT_NONE) {
			ssl->bFlags |= BFLAG_CLOSE_AFTER_SENT;
		}
		psAssert(prevBuf == buf);
		psAssert(ssl->insize >= (int32)len);
		psAssert(start == 0);
		psAssert(buf == ssl->inbuf);
		if (ssl->outlen > 0) {
			/* If data's in outbuf, append inbuf.  This is a corner case that
				can happen if application data is queued but then incoming data
				is processed and discovered to be a re-handshake request.
				matrixSslDecode will have constructed the response flight but
				we don't want to forget about the app data we haven't sent */
			if (ssl->outlen + (int32)len > ssl->outsize) {
				if ((p = psRealloc(ssl->outbuf, ssl->outlen + len,
						ssl->bufferPool)) == NULL) {
					return PS_MEM_FAIL;
				}
				ssl->outbuf = p;
				ssl->outsize = ssl->outlen + len;
			}
			memcpy(ssl->outbuf + ssl->outlen, ssl->inbuf, len);
			ssl->outlen += len;
		} else { /* otherwise, swap inbuf and outbuf */
			buf = ssl->outbuf; ssl->outbuf = ssl->inbuf; ssl->inbuf = buf;
			ssl->outlen = len;
			len = ssl->outsize; ssl->outsize = ssl->insize; ssl->insize = len;
			buf = ssl->inbuf;
			len = ssl->outlen;
		}
		rc = MATRIXSSL_REQUEST_SEND;	/* We queued data to send out */
		break;

	case MATRIXSSL_ERROR:
		if (decodeErr >= 0) {
			//printf("THIS SHOULD BE A NEGATIVE VALUE?\n");
		}
		return decodeErr; /* Will be a negative value */

	case SSL_ALERT:
		if (alertLevel == SSL_ALERT_LEVEL_FATAL) {
			psTraceIntInfo("Received FATAL alert %d.\n", alertDesc);
		} else {
			/* Closure notify is the normal case */
			if (alertDesc == SSL_ALERT_CLOSE_NOTIFY) {
				psTraceInfo("Normal SSL closure alert\n");
			} else {
				psTraceIntInfo("Received WARNING alert %d\n", alertDesc);
			}
		}
		/* Let caller access the 2 data bytes (severity and description) */
#ifdef USE_TLS_1_1
		/* Been ignoring the explicit IV up to this final return point. */
		if ((ssl->flags & SSL_FLAGS_READ_SECURE) &&
				(ssl->flags & SSL_FLAGS_TLS_1_1) &&	(ssl->enBlockSize > 1)) {
			prevBuf += ssl->enBlockSize;
		}
#endif /* USE_TLS_1_1 */
		psAssert(len == 2);
		*ptbuf = prevBuf;
		*ptlen = len;
		ssl->inlen -= processed;
		return MATRIXSSL_RECEIVED_ALERT;

	case SSL_PARTIAL:
		if (reqLen > SSL_MAX_BUF_SIZE) {
			return PS_MEM_FAIL;
		}
		if (reqLen > (uint32)ssl->insize) {
			if ((p = psRealloc(ssl->inbuf, reqLen, ssl->bufferPool)) == NULL) {
				return PS_MEM_FAIL;
			}
			ssl->inbuf = p;
			ssl->insize = reqLen;
			buf = ssl->inbuf;
			/* Don't need to change inlen */
		}


		rc = MATRIXSSL_REQUEST_RECV;	/* Expecting more data */
		break;

	/* We've got outgoing data that's larger than our buffer */
	case SSL_FULL:
		if (reqLen > SSL_MAX_BUF_SIZE) {
			return PS_MEM_FAIL;
		}
		/* We balk if we get a large handshake message */
		if (reqLen > SSL_MAX_PLAINTEXT_LEN &&
				!matrixSslHandshakeIsComplete(ssl)) {
			if (reqLen > SSL_MAX_PLAINTEXT_LEN) {
				return PS_MEM_FAIL;
			}
		}
		/*
			Can't envision any possible case where there is remaining data
			in inbuf to process and are getting SSL_FULL.
		*/
		ssl->inlen = 0;

		/* Grow inbuf */
		if (reqLen > (uint32)ssl->insize) {
			len = ssl->inbuf - buf;
			if ((p = psRealloc(ssl->inbuf, reqLen, ssl->bufferPool)) == NULL) {
				return PS_MEM_FAIL;
			}
			ssl->inbuf = p;
			ssl->insize = reqLen;
			buf = ssl->inbuf + len;
			/* Note we leave inlen untouched here */
		} else {
			psTraceInfo("Encoding error. Possible wrong flight messagSize\n");
			return PS_PROTOCOL_FAIL;	/* error in our encoding */
		}
		goto DECODE_MORE;

	case SSL_PROCESS_DATA:
/*
		Possible we received a finished message and app data in the same
		flight. In this case, the caller is not notified that the handshake
		is complete, but rather is notified that there is application data to
		process.
 */
		if (!(ssl->bFlags & BFLAG_HS_COMPLETE) &&
			matrixSslHandshakeIsComplete(ssl)) {
			ssl->bFlags |= BFLAG_HS_COMPLETE;
#ifdef USE_CLIENT_SIDE_SSL
			matrixSslGetSessionId(ssl, ssl->sid);
#endif /* USE_CLIENT_SIDE_SSL */
		}
/*
		 .	prevbuf points to start of unencrypted data
		 .	buf points to start of any remaining unencrypted data
		 .	start is length of remaining encrypted data yet to decode
		 .	len is length of unencrypted data ready for user processing
 */
		ssl->inlen -= processed;
		psAssert((uint32)ssl->inlen == start);

		/* Call user plaintext data handler */
#ifdef USE_TLS_1_1
		/* Been ignoring the explicit IV up to this final return point. */
		/* NOTE: This test has been on enBlockSize for a very long time but
			it looks like it should be on deBlockSize since this a decryption.
			Changed and added an assert to see if these ever don't match */
		psAssert(ssl->enBlockSize == ssl->deBlockSize);
		if ((ssl->flags & SSL_FLAGS_READ_SECURE) &&
				(ssl->flags & SSL_FLAGS_TLS_1_1) &&	(ssl->deBlockSize > 1)) {
			len -= ssl->deBlockSize;
			prevBuf += ssl->deBlockSize;
		}
		/* END enBlockSize to deBlockSize change */
#endif /* USE_TLS_1_1 */
		*ptbuf = prevBuf;
		*ptlen = len;
#ifdef USE_DTLS
/*
		This flag is used in conjuction with flightDone in the buffer
		management API set to determine whether we are still in a handshake
		state for attempting flight resends. If we are getting app data we
		know for certain we are out of the hs states. Testing HandshakeComplete
		is not enough because you never know if the other side got FINISHED.
*/
		if (ssl->flags & SSL_FLAGS_DTLS) {
			ssl->appDataExch = 1;
		}
#endif
#ifdef USE_ZLIB_COMPRESSION
		if (ssl->compression > 0) {
			return MATRIXSSL_APP_DATA_COMPRESSED;
		}
#endif
		return MATRIXSSL_APP_DATA;
	} /* switch decodeRet */

	if (ssl->inlen > 0 && (buf != ssl->inbuf)) {
		psAssert(0);
	}
/*
	Shrink inbuf to default size once inlen < default size, and we aren't
	expecting any more data in the buffer. If SSL_PARTIAL, don't shrink the
	buffer, since we expect to fill it up shortly.
*/
	if (decodeRet != SSL_PARTIAL) {
		revertToDefaultBufsize(ssl, SSL_INBUF);
	}

	return rc;
}
Exemplo n.º 16
0
int32_t matrixSslNewClientSession(ssl_t **ssl, const sslKeys_t *keys,
				sslSessionId_t *sid,
				const uint16_t cipherSpec[], uint8_t cipherSpecLen,
				sslCertCb_t certCb,
				const char *expectedName, tlsExtension_t *extensions,
				sslExtCb_t extCb,
				sslSessOpts_t *options)
{
	ssl_t		*lssl;
	psBuf_t		tmp;
	uint32		len;
	int32		rc, i;

	if (!ssl) {
		return PS_ARG_FAIL;
	}
	if (cipherSpecLen > 0 && (cipherSpec == NULL || cipherSpec[0] == 0)) {
		return PS_ARG_FAIL;
	}
	if (options == NULL) {
		return PS_ARG_FAIL;
	}

	*ssl = NULL;
	lssl = NULL;

	/* Give priority to cipher suite if session id is provided and doesn't match */
	if (cipherSpec != NULL && cipherSpec[0] != 0 && sid != NULL &&
			sid->cipherId != 0) {
		rc = 1;
		for (i = 0; i < cipherSpecLen; i++) {
			if (cipherSpec[i] == sid->cipherId) {
				rc = 0;
			}
		}
		if (rc) {
			psTraceInfo("Explicit cipher suite will override session cache\n");
			memset(sid->id, 0, SSL_MAX_SESSION_ID_SIZE);
			memset(sid->masterSecret, 0, SSL_HS_MASTER_SIZE);
			sid->cipherId = 0;
		}
	}

	if ((rc = matrixSslNewSession(&lssl, keys, sid, options)) < 0) {
		return rc;
	}
	lssl->userPtr = options->userPtr;

#ifndef USE_ONLY_PSK_CIPHER_SUITE
	if (expectedName) {
		if (psX509ValidateGeneralName((char*)expectedName) < 0) {
			matrixSslDeleteSession(lssl);
			return rc;
		}
		rc = strlen(expectedName);
		lssl->expectedName = psMalloc(lssl->sPool, rc + 1);
		strcpy(lssl->expectedName, expectedName);
	}
	if (certCb) {
		matrixSslSetCertValidator(lssl, certCb);
	}
#endif
	if (extCb) {
		lssl->extCb = extCb;
	}
RETRY_HELLO:
	tmp.size = lssl->outsize;
	tmp.buf = tmp.start = tmp.end = lssl->outbuf;
	if ((rc = matrixSslEncodeClientHello(lssl, &tmp, cipherSpec, cipherSpecLen,
			&len, extensions, options)) < 0) {
		if (rc == SSL_FULL) {
			if ((tmp.buf = psRealloc(lssl->outbuf, len, lssl->bufferPool))
					== NULL) {
				matrixSslDeleteSession(lssl);
				return PS_MEM_FAIL;
			}
			lssl->outbuf = tmp.buf;
			lssl->outsize = len;
			goto RETRY_HELLO;
		} else {
			matrixSslDeleteSession(lssl);
			return rc;
		}
	}
	psAssert(tmp.start == tmp.buf);
	lssl->outlen = tmp.end - tmp.start;
	*ssl = lssl;
	return MATRIXSSL_REQUEST_SEND;
}
Exemplo n.º 17
0
int32 matrixSslReEnableRehandshakes(ssl_t *ssl)
{
	psTraceInfo("Rehandshaking is not compiled into library at all.\n");
	return PS_FAILURE;
}
Exemplo n.º 18
0
/*
	Encode a CLIENT_HELLO or HELLO_REQUEST to re-handshake an existing
	connection.

	Can't "downgrade" the re-handshake.  This means if keys or certCb are
	NULL we stick with whatever the session already has loaded.

	keys should be NULL if no change in key material is being made

	cipherSpec is only used by clients
 */
int32_t matrixSslEncodeRehandshake(ssl_t *ssl, sslKeys_t *keys,
				int32 (*certCb)(ssl_t *ssl, psX509Cert_t *cert, int32 alert),
				uint32 sessionOption,
				const uint16_t cipherSpec[], uint8_t cipherSpecLen)
{
	sslBuf_t		sbuf;
	int32			rc, i;
	uint32			reqLen, newLen;
	unsigned char	*p;
	sslSessOpts_t	options;

	/* Clear extFlags for rehandshakes */
	ssl->extFlags.truncated_hmac = 0;
	ssl->extFlags.sni = 0;
	
	if (!ssl) {
		return PS_ARG_FAIL;
	}
	if (cipherSpecLen > 0 && (cipherSpec == NULL || cipherSpec[0] == 0)) {
		return PS_ARG_FAIL;
	}
	if (ssl->bFlags & BFLAG_CLOSE_AFTER_SENT) {
		return PS_PROTOCOL_FAIL;
	}
	psAssert(ssl->outsize > 0 && ssl->outbuf != NULL);

#ifdef DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM
#endif /* DISABLE_DTLS_CLIENT_CHANGE_CIPHER_FROM_GCM_TO_GCM */

#ifdef USE_ZLIB_COMPRESSION
	/* Re-handshakes are not currently supported for compressed sessions. */
	if (ssl->compression > 0) {
		psTraceInfo("Re-handshakes not supported for compressed sessions\n");
		return PS_UNSUPPORTED_FAIL;
	}
#endif
/*
	The only explicit option that can be passsed in is
	SSL_OPTION_FULL_HANDSHAKE to indicate no resumption is allowed
*/
	if (sessionOption == SSL_OPTION_FULL_HANDSHAKE) {
		matrixSslSetSessionOption(ssl, sessionOption, NULL);
	}
/*
	If the key material or cert callback are provided we have to assume it
	was intentional to "upgrade" the re-handshake and we force full handshake
	No big overhead calling SetSessionOption with FULL_HS multiple times.
*/
	if (keys != NULL) {
		ssl->keys = keys;
		matrixSslSetSessionOption(ssl, SSL_OPTION_FULL_HANDSHAKE, NULL);
	}

#ifndef USE_ONLY_PSK_CIPHER_SUITE
	if (certCb != NULL) {
		matrixSslSetSessionOption(ssl, SSL_OPTION_FULL_HANDSHAKE, NULL);
#if defined(USE_CLIENT_AUTH) || defined(USE_CLIENT_SIDE_SSL)
		matrixSslSetCertValidator(ssl, certCb);
#endif /* USE_CLIENT_AUTH || USE_CLIENT_SIDE_SSL */
#if defined(USE_CLIENT_AUTH) && defined(USE_SERVER_SIDE_SSL)
/*
		If server, a certCb is an explicit flag to set client auth just as
		it is in matrixSslNewServerSession
*/
		if (ssl->flags & SSL_FLAGS_SERVER) {
			matrixSslSetSessionOption(ssl, SSL_OPTION_ENABLE_CLIENT_AUTH, NULL);
		}
#endif /* USE_CLIENT_AUTH && USE_SERVER_SIDE_SSL */
	}
#endif /* !USE_ONLY_PSK_CIPHER_SUITE */

/*
	If cipher spec is explicitly different from current, force a full handshake
*/
	if (!(ssl->flags & SSL_FLAGS_SERVER)) {
		rc = 0;
		if (cipherSpecLen > 0) {
			rc = 1;
			for (i = 0; i < cipherSpecLen; i++) {
				if (cipherSpec[i] == ssl->cipher->ident) {
					rc = 0;
				}
			}
		}
		if (rc) {
			matrixSslSetSessionOption(ssl, SSL_OPTION_FULL_HANDSHAKE, NULL);
		}
	}
#ifdef USE_DTLS
	if (ssl->flags & SSL_FLAGS_DTLS) {
		/* Resend epoch should be brought up-to-date with new epoch */
		ssl->resendEpoch[0] = ssl->epoch[0];
		ssl->resendEpoch[1] = ssl->epoch[1];

		ssl->msn = ssl->resendMsn = 0;
	}
#endif /* USE_DTLS */
/*
	Options are set.  Encode the HELLO message
*/
	newLen = 0;
L_REHANDSHAKE:
	if (ssl->flags & SSL_FLAGS_SERVER) {
		sbuf.buf = sbuf.start = sbuf.end = ssl->outbuf + ssl->outlen;
		sbuf.size = ssl->outsize - ssl->outlen;
		if ((rc = matrixSslEncodeHelloRequest(ssl, &sbuf, &reqLen)) < 0) {
			if (rc == SSL_FULL && newLen == 0) {
				newLen = ssl->outlen + reqLen;
				if (newLen < SSL_MAX_BUF_SIZE) {
					if ((p = psRealloc(ssl->outbuf, newLen, ssl->bufferPool))
							== NULL){
						return PS_MEM_FAIL;
					}
					ssl->outbuf = p;
					ssl->outsize = newLen;
					goto L_REHANDSHAKE;
				}
			}
			return rc;
		}
	} else {
		sbuf.buf = sbuf.start = sbuf.end = ssl->outbuf + ssl->outlen;
		sbuf.size = ssl->outsize - ssl->outlen;
		memset(&options, 0x0, sizeof(sslSessOpts_t));
#ifdef USE_ECC_CIPHER_SUITE
		options.ecFlags = ssl->ecInfo.ecFlags;
#endif
		/* Use extended master secret if original connection used it */
		if (ssl->extFlags.extended_master_secret == 1) {
			options.extendedMasterSecret = 1;
			ssl->extFlags.extended_master_secret = 0;
		} else {
			options.extendedMasterSecret = -1;
		}
	
		if ((rc = matrixSslEncodeClientHello(ssl, &sbuf, cipherSpec,
				cipherSpecLen, &reqLen, NULL, &options)) < 0) {
			if (rc == SSL_FULL && newLen == 0) {
				newLen = ssl->outlen + reqLen;
				if (newLen < SSL_MAX_BUF_SIZE) {
					if ((p = psRealloc(ssl->outbuf, newLen, ssl->bufferPool))
							== NULL) {
						return PS_MEM_FAIL;
					}
					ssl->outbuf = p;
					ssl->outsize = newLen;
					goto L_REHANDSHAKE;
				}
			}
			return rc;
		}
	}
	ssl->outlen += sbuf.end - sbuf.start;
	return MATRIXSSL_SUCCESS;
}
Exemplo n.º 19
0
static int32 matrixSslLoadKeyMaterial(sslKeys_t *keys, const char *certFile,
				const char *privFile, const char *privPass, const char *CAfile,
				int32 privKeyType)
{
	psPool_t	*pool;
	int32		err, flags;

	if (keys == NULL) {
		return PS_ARG_FAIL;
	}
	pool = keys->pool;

/*
	Setting flags to store raw ASN.1 stream for SSL CERTIFICATE message use
*/
	flags = CERT_STORE_UNPARSED_BUFFER;
	

	if (certFile) {
#ifdef USE_SERVER_SIDE_SSL	
		if (keys->cert != NULL) {
			return PS_UNSUPPORTED_FAIL;
		}
		if ((err = psX509ParseCertFile(pool, (char*)certFile,
				&keys->cert, flags)) < 0) {
			return err;
		}
#else
		psTraceStrInfo("Ignoring %s certFile in matrixSslReadKeys\n",
					(char*)certFile);
#endif /* USE_SERVER_SIDE_SSL */		
	}
/*
	Parse the private key file
*/
	if (privFile) {
#ifdef USE_SERVER_SIDE_SSL
		if (keys->privKey != NULL) {
			if (keys->cert) {
				psX509FreeCert(keys->cert);
				keys->cert = NULL;
			}
			return PS_UNSUPPORTED_FAIL;
		}
		if (privKeyType == PS_RSA) {
			if ((err = pkcs1ParsePrivFile(pool, (char*)privFile,
					(char*)privPass, &keys->privKey)) < 0) {
				if (keys->cert) {	
					psX509FreeCert(keys->cert);
					keys->cert = NULL;
				}
				return err;
			}
		}
#else
		psTraceStrInfo("Ignoring %s privFile in matrixSslReadKeys\n",
					(char*)privFile);
#endif /* USE_SERVER_SIDE_SSL */			
	}

#ifdef USE_SERVER_SIDE_SSL
	if (verifyReadKeys(pool, keys) < PS_SUCCESS) {
		psTraceInfo("Cert parse success but material didn't validate\n");
		psX509FreeCert(keys->cert);
		psFreePubKey(keys->privKey);
		keys->cert = NULL;
		keys->privKey = NULL;
		return PS_CERT_AUTH_FAIL;
	}
#endif /* USE_SERVER_SIDE_SSL */
	
/*
	Not necessary to store binary representations of CA certs
*/
	flags &= ~CERT_STORE_UNPARSED_BUFFER;

	if (CAfile) {	
#ifdef USE_CLIENT_SIDE_SSL
		if (keys->CAcerts != NULL) {
			return PS_UNSUPPORTED_FAIL;
		}
		if ((err = psX509ParseCertFile(pool, (char*)CAfile,
				&keys->CAcerts, flags)) < 0) {
#ifdef USE_SERVER_SIDE_SSL				
			if (keys->cert) {
				psX509FreeCert(keys->cert);
				keys->cert = NULL;
			} 
			if (keys->privKey) {
				psFreePubKey(keys->privKey);
				keys->privKey = NULL;
			}
#endif /* USE_SERVER_SIDE_SSL */	
			return err;
		}
#else
		psTraceStrInfo("Ignoring %s CAfile in matrixSslReadKeys\n", (char*)CAfile);		
#endif /* USE_CLIENT_SIDE_SSL */
	}

	return PS_SUCCESS;
}
Exemplo n.º 20
0
/*
	Encode a CLIENT_HELLO or HELLO_REQUEST to re-handshake an existing
	connection.
		
	Can't "downgrade" the re-handshake.  This means if keys or certCb are
	NULL we stick with whatever the session already has loaded.
	
	keys should be NULL if no change in key material is being made
	
	cipherSpec is only used by clients
 */
int32 matrixSslEncodeRehandshake(ssl_t *ssl, sslKeys_t *keys,
				int32 (*certCb)(ssl_t *ssl, psX509Cert_t *cert, int32 alert),
				uint32 sessionOption, uint32 cipherSpec[], uint16 cipherSpecLen)
{
	sslBuf_t		sbuf;
	int32			rc, i;
	uint32			reqLen, newLen;
	unsigned char	*p;
	
	if (!ssl) {
		return PS_ARG_FAIL;
	}
	if (cipherSpecLen > 0 && (cipherSpec == NULL || cipherSpec[0] == 0)) {
		return PS_ARG_FAIL;
	}
	if (ssl->bFlags & BFLAG_CLOSE_AFTER_SENT) {
		return PS_PROTOCOL_FAIL;
	}	
	psAssert(ssl->outsize > 0 && ssl->outbuf != NULL);
	
#ifdef USE_ZLIB_COMPRESSION
	/* Re-handshakes are not currently supported for compressed sessions. */
	if (ssl->compression > 0) {
		psTraceInfo("Re-handshakes not supported for compressed sessions\n");
		return PS_UNSUPPORTED_FAIL;
	}
#endif
/*
	The only explicit option that can be passsed in is
	SSL_OPTION_FULL_HANDSHAKE to indicate no resumption is allowed
*/
	if (sessionOption == SSL_OPTION_FULL_HANDSHAKE) {
		matrixSslSetSessionOption(ssl, sessionOption, NULL);
	}
/*
	If the key material or cert callback are provided we have to assume it
	was intentional to "upgrade" the re-handshake and we force full handshake
	No big overhead calling SetSessionOption with FULL_HS multiple times.
*/
	if (keys != NULL) {
		ssl->keys = keys;
		matrixSslSetSessionOption(ssl, SSL_OPTION_FULL_HANDSHAKE, NULL);
	}

#ifndef USE_ONLY_PSK_CIPHER_SUITE
	if (certCb != NULL) { 	
		matrixSslSetSessionOption(ssl, SSL_OPTION_FULL_HANDSHAKE, NULL);
#if defined(USE_CLIENT_AUTH) || defined(USE_CLIENT_SIDE_SSL)
		matrixSslSetCertValidator(ssl, (sslCertCb_t)certCb);
#endif /* USE_CLIENT_AUTH || USE_CLIENT_SIDE_SSL */
#if defined(USE_CLIENT_AUTH) && defined(USE_SERVER_SIDE_SSL) 		
/*
		If server, a certCb is an explicit flag to set client auth just as
		it is in matrixSslNewServerSession
*/		
		if (ssl->flags & SSL_FLAGS_SERVER) {
			matrixSslSetSessionOption(ssl, SSL_OPTION_ENABLE_CLIENT_AUTH, NULL);
		}
#endif /* USE_CLIENT_AUTH && USE_SERVER_SIDE_SSL */
	}	
#endif /* !USE_ONLY_PSK_CIPHER_SUITE */
	
/*
	If cipher spec is explicitly different from current, force a full handshake
*/
	if (!(ssl->flags & SSL_FLAGS_SERVER)) {
		rc = 0;
		if (cipherSpecLen > 0) {
			rc = 1;
			for (i = 0; i < cipherSpecLen; i++) {
				if (cipherSpec[i] == ssl->cipher->ident) {
					rc = 0;
				}
			}
		}
		if (rc) {
			matrixSslSetSessionOption(ssl, SSL_OPTION_FULL_HANDSHAKE, NULL);
		}
	}
/*
	Options are set.  Encode the HELLO message
*/
	newLen = 0;
L_REHANDSHAKE:
	if (ssl->flags & SSL_FLAGS_SERVER) {
		sbuf.buf = sbuf.start = sbuf.end = ssl->outbuf + ssl->outlen;
		sbuf.size = ssl->outsize - ssl->outlen;
		if ((rc = matrixSslEncodeHelloRequest(ssl, &sbuf, &reqLen)) < 0) {
			if (rc == SSL_FULL && newLen == 0) {
				newLen = ssl->outlen + reqLen;
				if (newLen < SSL_MAX_BUF_SIZE) {
					if ((p = psRealloc(ssl->outbuf, newLen)) == NULL){
						return PS_MEM_FAIL;
					}
					ssl->outbuf = p;
					ssl->outsize = newLen;
					goto L_REHANDSHAKE;
				}
			}
			return rc;
		}
	} else {
		sbuf.buf = sbuf.start = sbuf.end = ssl->outbuf + ssl->outlen;
		sbuf.size = ssl->outsize - ssl->outlen;
		if ((rc = matrixSslEncodeClientHello(ssl, &sbuf, cipherSpec,
				cipherSpecLen, &reqLen, NULL)) < 0) {
			if (rc == SSL_FULL && newLen == 0) {
				newLen = ssl->outlen + reqLen;
				if (newLen < SSL_MAX_BUF_SIZE) {
					if ((p = psRealloc(ssl->outbuf, newLen)) == NULL) {
						return PS_MEM_FAIL;
					}
					ssl->outbuf = p;
					ssl->outsize = newLen;
					goto L_REHANDSHAKE;
				}
			}
			return rc;
		}
	}
	ssl->outlen += sbuf.end - sbuf.start;
	return MATRIXSSL_SUCCESS;
}
Exemplo n.º 21
0
Arquivo: tls.c Projeto: Deadolus/ecc
/*
	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->nativeDeMacSize = ssl->cipher->macSize;
	if (ssl->extFlags.truncated_hmac) {
		if (ssl->cipher->macSize > 0) { /* Only for HMAC-based ciphers */
			ssl->deMacSize = 10;
		} else {
			ssl->deMacSize = ssl->cipher->macSize;
		}
	} else {
		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->ident != SSL_NULL_WITH_NULL_NULL) {
		/* Sanity */
		if (ssl->sec.rMACptr == NULL) {
			psTraceInfo("sslActivateReadCipher sanity fail\n");
			return PS_FAILURE;
		}
		ssl->flags |= SSL_FLAGS_READ_SECURE;

#ifdef USE_TLS_1_2
		if (ssl->deMacSize == 0) {
			/* Need a concept for AEAD read and write start times for the
				cases surrounding changeCipherSpec if moving from one suite
				to another */
			ssl->flags |= SSL_FLAGS_AEAD_R;
			if (ssl->cipher->flags & CRYPTO_FLAGS_CHACHA) {
				ssl->flags &= ~SSL_FLAGS_NONCE_R;
			} else {
				ssl->flags |= SSL_FLAGS_NONCE_R;
			}
		} else {
			ssl->flags &= ~SSL_FLAGS_AEAD_R;
			ssl->flags &= ~SSL_FLAGS_NONCE_R;
		}
#endif
/*
		Copy the newly activated read keys into the live buffers
*/
		memcpy(ssl->sec.readMAC, ssl->sec.rMACptr, ssl->deMacSize);
		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) {
			if (ssl->cipher->init(&(ssl->sec), INIT_DECRYPT_CIPHER,
					ssl->cipher->keySize) < 0) {
				psTraceInfo("Unable to initialize read cipher suite\n");
				return PS_FAILURE;
			}
		}

	}
	return PS_SUCCESS;
}