Exemple #1
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;
}
Exemple #2
0
/*
	Server initiated rehandshake.  Builds and sends the HELLO_REQUEST message
*/
void sslRehandshake(sslConn_t *cp)
{
	matrixSslEncodeHelloRequest(cp->ssl, &cp->outsock);
	psSocketWrite(cp->fd, &cp->outsock);
	cp->outsock.start = cp->outsock.end = cp->outsock.buf;
}
Exemple #3
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;
}