Example #1
0
/*
   Stub for a user-level certificate validator.  Just using
   the default validation value here.
 */
static int32 certValidator(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
{
    /* Example to allow anonymous connections based on a define */
    if (alert > 0)
    {
        if (ALLOW_ANON_CONNECTIONS)
        {
            /* Could be NULL if SERVER_WILL_ACCEPT_EMPTY_CLIENT_CERT_MSG */
            if (cert)
            {
                _psTraceStr("Allowing anonymous connection for: %s.\n",
                    cert->subject.commonName);
            }
            else
            {
                _psTrace("Client didn't send certificate. Reverting to standard handshake due to SERVER_WILL_ACCEPT_EMPTY_CLIENT_CERT_MSG\n");
            }
            return SSL_ALLOW_ANON_CONNECTION;
        }
        _psTrace("Certificate callback returning fatal alert\n");
        return alert;
    }
    _psTraceStr("Validated cert for: %s.\n", cert->subject.commonName);
    return 0;
}
Example #2
0
File: corelib.c Project: B-Rich/NUL
void psTraceBytes(char *tag, unsigned char *p, int l)
{
	char	s[17];
	int		i;

	s[16] = '\0';
	_psTraceStr("psTraceBytes(%s, ", tag);
	_psTraceInt("%d);", l);
	for (i = 0; i < l; i++) {
		if (!(i & 0xF)) {
			if (i != 0) {
				mem2str(s, p - 16, 16);
				_psTraceStr("  %s", s);
			}
			_psTraceInt("\n0x%08x:", (int)p);
		}
		_psTraceInt("%02x ", *p++);
	}
	memset(s, 0x0, 16);
	i = l & 0xF;
	mem2str(s, p - i, (unsigned int)i);
	for (;i < 16; i++) {
		_psTrace("   ");
	}
	_psTraceStr("  %s", s);
	_psTrace("\n");
}
Example #3
0
File: corelib.c Project: B-Rich/NUL
void _psErrorStr(char *msg, char *val)
{
	_psTraceStr(msg, val);
#ifdef HALT_ON_PS_ERROR		
	osdepBreak();
#endif	
} 
Example #4
0
/*
	Create an HTTP request and encode it to the SSL buffer
 */
static int32 httpWriteRequest(ssl_t *ssl)
{
	unsigned char   *buf;
	uint32          available, requested;

	requested = strlen((char *)g_httpRequestHdr) + 1;
	if ((available = matrixSslGetWritebuf(ssl, &buf, requested)) < 0) {
		return PS_MEM_FAIL;
	}
	requested = min(requested, available);
	strncpy((char *)buf, (char *)g_httpRequestHdr, requested);
	_psTraceStr("SEND: [%s]\n", (char*)buf);
	if (matrixSslEncodeWritebuf(ssl, strlen((char *)buf)) < 0) {
		return PS_MEM_FAIL;
	}
	return MATRIXSSL_REQUEST_SEND;
}
Example #5
0
int main(int argc, char **argv)
{
	int32			id;
	sslConn_t		*svrConn, *clnConn;
#ifdef ENABLE_PERF_TIMING
	int32			perfIter;
	uint32			clnTime, svrTime;
#endif /* ENABLE_PERF_TIMING */
		
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}

	svrConn = psMalloc(PEERSEC_NO_POOL, sizeof(sslConn_t));
	clnConn = psMalloc(PEERSEC_NO_POOL, sizeof(sslConn_t));
	memset(svrConn, 0, sizeof(sslConn_t));
	memset(clnConn, 0, sizeof(sslConn_t));
	
	for (id = 0; ciphers[id].cipherId > 0; id++) {
		matrixSslInitSessionId(clientSessionId);
		_psTraceStr("Testing %s suite\n", ciphers[id].name);
/*
		Standard Handshake
*/
		_psTrace("	Standard handshake test\n");
#ifdef ENABLE_PERF_TIMING
/*
		Each matrixSsl call in the handshake is wrapped by a timer.  The 
		data exchange phase is not being included in the time
*/
		clnTime = svrTime = 0;
		for (perfIter = 0; perfIter < CONN_ITER; perfIter++) {
#endif /* ENABLE_PERF_TIMING */		
		if (initializeHandshake(clnConn, svrConn, ciphers[id],
				&clientSessionId) < 0) {
			_psTrace("		FAILED: initializing Standard handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Standard handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Standard handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
#ifdef ENABLE_PERF_TIMING
		clnTime += clnConn->runningTime;
		svrTime += svrConn->runningTime;
		/* Have to reset conn for full handshake... except last time through */
		if (perfIter + 1 != CONN_ITER) {
			matrixSslDeleteSession(clnConn->ssl);
			matrixSslDeleteSession(svrConn->ssl);
			matrixSslInitSessionId(clientSessionId);
		}
		} /* iteration loop close */
		_psTraceInt("CLIENT:  %d " TIME_UNITS, (int32)clnTime/CONN_ITER);
		_psTraceInt("SERVER:  %d " TIME_UNITS, (int32)svrTime/CONN_ITER);
//		_psTrace("Press any key to continue tests");
		_psTrace("\n==========\n");
//		getchar();
#endif /* ENABLE_PERF_TIMING */
		
#ifdef SSL_REHANDSHAKES_ENABLED		
/*
		 Re-Handshake (full handshake over existing connection)
*/		
		_psTrace("	Re-handshake test (client-initiated)\n");		
		if (initializeReHandshake(clnConn, svrConn, ciphers[id].cipherId) < 0) {
			_psTrace("		FAILED: initializing Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}	
#else
		_psTrace("	Re-handshake tests are disabled (ENABLE_SECURE_REHANDSHAKES)\n");
#endif
				
/*
		Resumed handshake (fast handshake over new connection)
*/				
		_psTrace("	Resumed handshake test (new connection)\n");
#ifdef ENABLE_PERF_TIMING
		clnTime = svrTime = 0;
		for (perfIter = 0; perfIter < CONN_ITER; perfIter++) {
#endif /* ENABLE_PERF_TIMING */			
		if (initializeResumedHandshake(clnConn, svrConn,
				ciphers[id]) < 0) {
			_psTrace("		FAILED: initializing Resumed handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Resumed handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Resumed handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
#ifdef ENABLE_PERF_TIMING
		clnTime += clnConn->runningTime;
		svrTime += svrConn->runningTime;
		/* Have to reset conn for full handshake */
		} /* iteration loop */
		_psTraceInt("CLIENT:  %d " TIME_UNITS, (int32)clnTime/CONN_ITER);
		_psTraceInt("SERVER:  %d " TIME_UNITS, (int32)svrTime/CONN_ITER);
		_psTrace("Press any key to continue tests");
		_psTrace("\n==========\n");
//		getchar();
#endif /* ENABLE_PERF_TIMING */		
		
#ifdef SSL_REHANDSHAKES_ENABLED		
/*
		 Re-handshake initiated by server (full handshake over existing conn)
*/			
		_psTrace("	Re-handshake test (server initiated)\n");
		if (initializeServerInitiatedReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
			_psTrace("		FAILED: initializing Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(svrConn, clnConn) < 0) {
			_psTrace("		FAILED: Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}	
	
/*
		Resumed re-handshake (fast handshake over existing connection)
*/				
		_psTrace("	Resumed Re-handshake test (client initiated)\n");
		if (initializeResumedReHandshake(clnConn, svrConn,
				 ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: initializing Resumed Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Resumed Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Resumed Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
		
/*
		 Resumed re-handshake initiated by server (fast handshake over conn)
*/		
		_psTrace("	Resumed Re-handshake test (server initiated)\n");
		if (initializeServerInitiatedResumedReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: initializing Resumed Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(svrConn, clnConn) < 0) {
			_psTrace("		FAILED: Resumed Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Resumed Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}		
/*
		Re-handshaking with "upgraded" parameters
*/
		_psTrace("	Change cert callback Re-handshake test\n");
		if (initializeUpgradeCertCbackReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: init upgrade certCback Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Upgrade cert callback Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Upgrade cert callback Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}		
/*
		Upgraded keys
*/
		_psTrace("	Change keys Re-handshake test\n");
		if (initializeUpgradeKeysReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: init upgrade keys Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Upgrade keys Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Upgrade keys Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
/*
		Change cipher spec test.  Changing to a hardcoded RSA suite so this
		will not work on suites that don't have RSA material loaded
*/
		if (ciphers[id].rsa == 1) {
			_psTrace("	Change cipher suite Re-handshake test\n");
			if (initializeChangeCipherReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
					_psTrace("		FAILED: init change cipher Re-handshake\n");
				goto LBL_FREE;
			}
			if (performHandshake(clnConn, svrConn) < 0) {
				_psTrace("		FAILED: Change cipher suite Re-handshake\n");
				goto LBL_FREE;
			} else {
				testTrace("		PASSED: Change cipher suite Re-handshake");
				if (exchangeAppData(clnConn, svrConn) < 0) {
					_psTrace(" but FAILED to exchange application data\n");
				} else {
					testTrace("\n");
				}
			}
		}
#endif /* !SSL_REHANDSHAKES_ENABLED */


LBL_FREE:
		freeSessionAndConnection(svrConn);
		freeSessionAndConnection(clnConn);
	}
	psFree(svrConn);
	psFree(clnConn);
	matrixSslClose();

#ifdef WIN32
	_psTrace("Press any key to close");
	getchar();
#endif

	return PS_SUCCESS;	
}
Example #6
0
int main(int argc, char **argv)
{
	psPool_t		*pool, *misc;
	psDhParams_t	dhParams;
	psDhKey_t		dhKeyPriv, dhKeyPub;
	uint16_t		pLen, gLen;
	unsigned char	*p, *g;
	psTime_t		start, end;
	uint16_t		iter, i = 0;
	unsigned char	out[512];
	uint16_t		outLen = sizeof(out);

	pool = misc = NULL;
	if (psCryptoOpen(PSCRYPTO_CONFIG) < PS_SUCCESS) {
		_psTrace("Failed to initialize library:  psCryptoOpen failed\n");
		return -1;
	}
	_psTraceStr("STARTING DHPERF\n", NULL);

	while (keys[i].key != NULL) {
		_psTraceStr("Test %s...\n", keys[i].name);
		pkcs3ParseDhParamBin(misc, (unsigned char*)keys[i].key,	keys[i].len,
			&dhParams);

		iter = 0;

#ifdef DO_GEN_INTS
		psGetTime(&start, NULL);
		while (iter < keys[i].iter) {
			if (psDhGenKeyInts(pool, dhParams.size, &dhParams.p, &dhParams.g,
					&dhKeyPriv, NULL) < 0) {
				_psTrace("	FAILED OPERATION\n");
			}

			psDhClearKey(&dhKeyPriv);
			iter++;
		}
		psGetTime(&end, NULL);
		_psTraceInt(TIME_UNITS " genInts\n", psDiffMsecs(start, end, NULL));
#endif /* DO_GEN_INTS */

#ifdef DO_GEN_SECRET
		psDhExportParameters(misc, &dhParams, &p, &pLen, &g, &gLen);
		if (psDhGenKeyInts(misc, dhParams.size, &dhParams.p, &dhParams.g,
				&dhKeyPriv, NULL) < 0) {
			_psTrace("	FAILED OPERATION\n");
		}
		if (psDhGenKeyInts(misc, dhParams.size, &dhParams.p, &dhParams.g,
				&dhKeyPub, NULL) < 0) {
			_psTrace("	FAILED OPERATION\n");
		}
		iter = 0;
		outLen = sizeof(out);
		psGetTime(&start, NULL);
		while (iter < keys[i].iter) {
			if (psDhGenSharedSecret(pool, &dhKeyPriv, &dhKeyPub, p, pLen,
					out, &outLen, NULL) < 0) {
				_psTrace("	FAILED OPERATION\n");
			}

			iter++;
		}
		psGetTime(&end, NULL);
		psDhClearKey(&dhKeyPriv);
		psDhClearKey(&dhKeyPub);
		_psTraceInt(TIME_UNITS " genSecret\n", psDiffMsecs(start, end, NULL));
#endif /* DO_GEN_SECRET */

		psFree(p, misc);
		psFree(g, misc);
		pkcs3ClearDhParams(&dhParams);
		i++;
	}

#ifdef WIN32
	_psTrace("Press any key to close");
	getchar();
#endif
	_psTraceStr("FINISHED DHPERF\n", NULL);
	psCryptoClose();
	return 0;
}
Example #7
0
/*
	Example callback to do additional certificate validation.
	If this callback is not registered in matrixSslNewService,
	the connection will be accepted or closed based on the status flag.
 */
static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
{
#ifdef POSIX
	struct tm	t;
	time_t		rawtime;
	char		*c;
	int			y, m, d;
#endif
	
	/* Example to allow anonymous connections based on a define */
	if (alert > 0) {
		if (ALLOW_ANON_CONNECTIONS) {
			_psTraceStr("Allowing anonymous connection for: %s.\n", 
						cert->subject.commonName);
			return SSL_ALLOW_ANON_CONNECTION;
		}
		_psTrace("Certificate callback returning fatal alert\n");
		return alert;
	}
	
#ifdef POSIX
	/* Validate the dates in the cert */
	time(&rawtime);
	localtime_r(&rawtime, &t);
	/* Localtime does months from 0-11 and (year-1900)! Normalize it. */
	t.tm_mon++;
	t.tm_year += 1900;
	
	/* Validate the 'not before' date */
	if ((c = cert->notBefore) != NULL) {
		if (strlen(c) < 8) {
			return PS_FAILURE;
		}
		/* UTCTIME, defined in 1982, has just a 2 digit year */
		if (cert->timeType == ASN_UTCTIME) {
			y =  2000 + 10 * (c[0] - '0') + (c[1] - '0'); c += 2;
		} else {
			y = 1000 * (c[0] - '0') + 100 * (c[1] - '0') + 
			10 * (c[2] - '0') + (c[3] - '0'); c += 4;
		}
		m = 10 * (c[0] - '0') + (c[1] - '0'); c += 2;
		d = 10 * (c[0] - '0') + (c[1] - '0'); 
		if (t.tm_year < y) return PS_FAILURE; 
		if (t.tm_year == y) {
			if (t.tm_mon < m) return PS_FAILURE;
			if (t.tm_mon == m && t.tm_mday < d) return PS_FAILURE;
		}
/*		_psTraceStr("Validated notBefore: %s\n", cert->notBefore); */
	}
	
	/* Validate the 'not after' date */
	if ((c = cert->notAfter) != NULL) {
		if (strlen(c) < 8) {
			return PS_FAILURE;
		}
		/* UTCTIME, defined in 1982 has just a 2 digit year */
		if (cert->timeType == ASN_UTCTIME) {
			y =  2000 + 10 * (c[0] - '0') + (c[1] - '0'); c += 2;
		} else {
			y = 1000 * (c[0] - '0') + 100 * (c[1] - '0') + 
			10 * (c[2] - '0') + (c[3] - '0'); c += 4;
		}
		m = 10 * (c[0] - '0') + (c[1] - '0'); c += 2;
		d = 10 * (c[0] - '0') + (c[1] - '0'); 
		if (t.tm_year > y) return PS_FAILURE; 
		if (t.tm_year == y) {
			if (t.tm_mon > m) return PS_FAILURE;
			if (t.tm_mon == m && t.tm_mday > d) return PS_FAILURE;
		}
/*		_psTraceStr("Validated notAfter: %s\n", cert->notAfter); */
	}
#endif /* POSIX */
	_psTraceStr("Validated cert for: %s.\n", cert->subject.commonName);
	
	return PS_SUCCESS;
}
Example #8
0
int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url,
				uint32 urlLen)
{
	SOCKET			fd;
	struct hostent	*ip;
	struct in_addr	intaddr;
	char			*pageStart, *replyPtr, *ipAddr;
	char			hostAddr[HOST_ADDR_LEN], getReq[GET_REQ_LEN];
	char			crlBuf[CRL_BUF_SIZE];
	int				hostAddrLen, getReqLen, pageLen;
	int32			transferred;
	int32			err, httpUriLen, port, offset;
	uint32			crlBinLen;
	
	/* Is URI in expected URL form? */
	if (strstr(url, "http://") == NULL) {
		if (strstr(url, "https://") == NULL) {
			_psTraceStr("crlCb: Unsupported CRL URI: %s\n", url);
			return -1;
		}
		httpUriLen = 8;
		port = 80; /* No example yet of using SSL to fetch CRL */
	} else {
		httpUriLen = 7;
		port = 80;
	}
	
	/* Parsing host and page and setting up IP address and GET request */
	if ((pageStart = strchr(url + httpUriLen, '/')) == NULL) {
		_psTrace("crlCb: No host/page divider found\n");
		return -1;
	}
	if ((hostAddrLen = (int)(pageStart - url) - httpUriLen) > HOST_ADDR_LEN) {
		_psTrace("crlCb: HOST_ADDR_LEN needs to be increased\n");
		return -1; /* ipAddr too small to hold */
	}
	
	memset(hostAddr, 0, HOST_ADDR_LEN);
	memcpy(hostAddr, url + httpUriLen, hostAddrLen);
	if ((ip = gethostbyname(hostAddr)) == NULL) {
		_psTrace("crlCb: gethostbyname failed\n");
		return -1;
	}
	
	memcpy((char *) &intaddr, (char *) ip->h_addr_list[0],
        (size_t) ip->h_length);
	if ((ipAddr = inet_ntoa(intaddr)) == NULL) {
		_psTrace("crlCb: inet_ntoa failed\n");
		return -1;
	}
	
	pageLen = (urlLen - hostAddrLen - httpUriLen);
	getReqLen = pageLen + hostAddrLen + GET_OH_LEN + HTTP_OH_LEN +
		HOST_OH_LEN + ACCEPT_OH_LEN;
	if (getReqLen > GET_REQ_LEN) {
		_psTrace("crlCb: GET_REQ_LEN needs to be increased\n");
		return -1;
	}
	
	// Build the request:
	//
	//	GET /page.crl HTTP/1.0
	//	Host: www.host.com
	//	Accept: */*
	//	
	memset(getReq, 0, GET_REQ_LEN);
	memcpy(getReq, crl_getHdr, GET_OH_LEN);
	offset = GET_OH_LEN;
	memcpy(getReq + offset, pageStart, pageLen);
	offset += pageLen;
	memcpy(getReq + offset, crl_httpHdr, HTTP_OH_LEN);
	offset += HTTP_OH_LEN;
	memcpy(getReq + offset, crl_hostHdr, HOST_OH_LEN);
	offset += HOST_OH_LEN;
	memcpy(getReq + offset, hostAddr, hostAddrLen);
	offset += hostAddrLen;
	memcpy(getReq + offset, crl_acceptHdr, ACCEPT_OH_LEN);
	
	/* Connect and send */
	fd = socketConnect(ipAddr, port, &err);
	if (fd == INVALID_SOCKET || err != PS_SUCCESS) {
		_psTraceInt("crlCb: socketConnect failed: %d\n", err);
		return PS_PLATFORM_FAIL;
	}

	/* Send request and receive response */
	offset = 0;
	while (getReqLen) {
		if ((transferred = send(fd, getReq + offset, getReqLen, 0)) < 0) {
			_psTraceInt("crlCb: socket send failed: %d\n", errno);
			close(fd);
			return PS_PLATFORM_FAIL;
		}
		getReqLen -= transferred;
		offset += transferred;
	}
	
	/* Not a good full recv */
	if ((transferred = recv(fd, crlBuf, CRL_BUF_SIZE, 0)) <= 0) {
		_psTrace("crlCb: socket recv closed or failed\n");
		close(fd);
		return PS_PLATFORM_FAIL;
	} 
	if (transferred == CRL_BUF_SIZE) {
		/* CRL larger than max */
		_psTrace("crlCb: CRL_BUF_SIZE needs to be increased\n");
		close(fd);
		return -1;
	}
	close(fd);
	
	/* Did we get an OK response? */
	if (strstr(crlBuf, "200 OK") == NULL) {
		_psTrace("crlCb: server reply was not '200 OK'\n");
		return -1;
	}
	/* Length parse */
	if ((replyPtr = strstr(crlBuf, "Content-Length: ")) == NULL) {
		return -1;
	}
	crlBinLen = (int)atoi(replyPtr + 16);
	
	/* Data begins after CRLF CRLF */
	if ((replyPtr = strstr(crlBuf, "\r\n\r\n")) == NULL) {
		return -1;
	}
	/* A sanity test that the length matches the remainder */
	if ((transferred - (replyPtr - crlBuf) - 4) != crlBinLen) {
		return -1;
	}
	
	/* Lastly, pass the CRL to matrixSslLoadCRL to parse, perform signature
		validation, and cache the revoked certificates for this CA */
	return matrixSslLoadCRL(pool, CA, append, replyPtr + 4, crlBinLen);
}
Example #9
0
/*
    EXAMPLE ONLY - SHOULD NOT BE USED FOR PRODUCTION CODE

    Process an HTTP request from a client.
    Very simple - we just print it, and return success.
    No HTTP validation at all is done on the data.
 */
int32 httpBasicParse(httpConn_t *cp, unsigned char *buf, uint32 len,
    int32 trace)
{
    unsigned char *c, *end, *tmp;
    int32 l;

    /*
        SSL/TLS can provide zero length records, which we just ignore here
        because the code below assumes we have at least one byte
     */
    if (len == 0)
    {
        return HTTPS_PARTIAL;
    }

    c = buf;
    end = c + len;
/*
    If we have an existing partial HTTP buffer, append to it the data in buf
    up to the first newline, or 'len' data, if no newline is in buf.
 */
    if (cp->parsebuf != NULL)
    {
        for (tmp = c; c < end && *c != '\n'; c++)
        {
            ;
        }
        /* We want c to point to 'end' or to the byte after \r\n */
        if (*c == '\n')
        {
            c++;
        }
        l = (int32) (c - tmp);
        if (l > HTTPS_BUFFER_MAX)
        {
            return HTTPS_ERROR;
        }
        cp->parsebuf = realloc(cp->parsebuf, l + cp->parsebuflen);
        memcpy(cp->parsebuf + cp->parsebuflen, tmp, l);
        cp->parsebuflen += l;
        /* Parse the data out of the saved buffer first */
        c = cp->parsebuf;
        end = c + cp->parsebuflen;
        /* We've "moved" some data from buf into parsebuf, so account for it */
        buf += l;
        len -= l;
    }

L_PARSE_LINE:
    for (tmp = c; c < end && *c != '\n'; c++)
    {
        ;
    }
    if (c < end)
    {
        if (*(c - 1) != '\r')
        {
            return HTTPS_ERROR;
        }
        /* If the \r\n started the line, we're done reading headers */
        if (*tmp == '\r' && (tmp + 1 == c))
        {
/*
            if ((c + 1) != end) {
                _psTrace("HTTP data parsing not supported, ignoring.\n");
            }
 */
            if (cp->parsebuf != NULL)
            {
                free(cp->parsebuf); cp->parsebuf = NULL;
                cp->parsebuflen = 0;
                if (len != 0)
                {
                    _psTrace("HTTP data parsing not supported, ignoring.\n");
                }
            }
            if (trace)
            {
                _psTrace("RECV COMPLETE HTTP MESSAGE\n");
            }
            return HTTPS_COMPLETE;
        }
    }
    else
    {
        /* If parsebuf is non-null, we have already saved it */
        if (cp->parsebuf == NULL && (l = (int32) (end - tmp)) > 0)
        {
            cp->parsebuflen = l;
            cp->parsebuf = malloc(cp->parsebuflen);
            psAssert(cp->parsebuf != NULL);
            memcpy(cp->parsebuf, tmp, cp->parsebuflen);
        }
        return HTTPS_PARTIAL;
    }
    *(c - 1) = '\0';    /* Replace \r with \0 just for printing */
    if (trace)
    {
        _psTraceStr("RECV PARSED: [%s]\n", (char *) tmp);
    }
    /* Finished parsing the saved buffer, now start parsing from incoming buf */
    if (cp->parsebuf != NULL)
    {
        free(cp->parsebuf); cp->parsebuf = NULL;
        cp->parsebuflen = 0;
        c = buf;
        end = c + len;
    }
    else
    {
        c++;    /* point c to the next char after \r\n */
    }
    goto L_PARSE_LINE;

    return HTTPS_ERROR;
}
Example #10
0
/*
	Main
*/
int main(int argc, char ** argv)
{
	struct sockaddr_in	inaddr;
	socklen_t		inaddrlen;
	struct timeval	timeout;
	ssl_t			*ssl;
	serverDtls_t	*dtlsCtx;
	SOCKET			sock;
	fd_set			readfd;
	unsigned char	*sslBuf, *recvfromBuf, *CAstream;
#ifdef USE_DTLS_DEBUG_TRACE	
	unsigned char   *addrstr;
#endif
#if !defined(ID_PSK) && !defined(ID_DHE_PSK)
	unsigned char   *keyValue, *certValue;
	int32           keyLen, certLen;
#endif	
	sslKeys_t		*keys;
	int32			freeBufLen, rc, val, recvLen, err, CAstreamLen;
	int32			sslBufLen, rcr, rcs, sendLen, recvfromBufLen;
	sslSessOpts_t	options;

#ifdef WIN32
	WSADATA         wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif

	rc = 0;
	ssl = NULL;
	dtlsCtx = NULL;
	sock = INVALID_SOCKET;

	/* parse input arguments */
	if (0 != process_cmd_options(argc, argv)) {
		usage();
		return 0;
	}

	if (sigsetup() < 0) {
		_psTrace("Init error creating signal handlers\n");
		return DTLS_FATAL;
	}

	if (matrixSslOpen() < 0) {
		_psTrace("Init error opening MatrixDTLS library\n");
		return DTLS_FATAL;
	}
	if (matrixSslNewKeys(&keys, NULL) < 0) {
		_psTrace("Init error allocating key structure\n");
		matrixSslClose();
		return DTLS_FATAL;
	}

	if ((rc = initClientList(MAX_CLIENTS)) < 0) {
		_psTrace("Init error opening client list\n");
		goto MATRIX_EXIT;
	}

	recvfromBufLen = matrixDtlsGetPmtu();
	if ((recvfromBuf = psMalloc(MATRIX_NO_POOL, recvfromBufLen)) == NULL) {
		rc = PS_MEM_FAIL;
		_psTrace("Init error allocating receive buffer\n");
		goto CLIENT_EXIT;
	}

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += sizeof(ECCAS);
#endif
	CAstream = psMalloc(NULL, CAstreamLen);

	CAstreamLen = 0;
#ifdef USE_RSA
	memcpy(CAstream, RSACAS, sizeof(RSACAS));
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECDHRSACAS, sizeof(ECDHRSACAS));
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECCAS, sizeof(ECCAS));
	CAstreamLen += sizeof(ECCAS);
#endif

#ifdef EXAMPLE_RSA_KEYS
	switch (g_rsaKeySize) {
		case 1024:
			certValue = (unsigned char *)RSA1024;
			certLen = sizeof(RSA1024);
			keyValue = (unsigned char *)RSA1024KEY;
			keyLen = sizeof(RSA1024KEY);
			break;
		case 2048:
			certValue = (unsigned char *)RSA2048;
			certLen = sizeof(RSA2048);
			keyValue = (unsigned char *)RSA2048KEY;
			keyLen = sizeof(RSA2048KEY);
			break;
		case 3072:
			certValue = (unsigned char *)RSA3072;
			certLen = sizeof(RSA3072);
			keyValue = (unsigned char *)RSA3072KEY;
			keyLen = sizeof(RSA3072KEY);
			break;
		case 4096:
			certValue = (unsigned char *)RSA4096;
			certLen = sizeof(RSA4096);
			keyValue = (unsigned char *)RSA4096KEY;
			keyLen = sizeof(RSA4096KEY);
			break;
		default:
			_psTraceInt("Invalid RSA key length (%d)\n", g_rsaKeySize);
			return -1;
	}

	if ((rc = matrixSslLoadRsaKeysMem(keys, (const unsigned char *)certValue,
			certLen, (const unsigned char *)keyValue, keyLen, CAstream,
			CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif


#ifdef EXAMPLE_ECDH_RSA_KEYS
	switch (g_ecdhKeySize) {
		case 256:
			certValue = (unsigned char *)ECDHRSA256;
			certLen = sizeof(ECDHRSA256);
			keyValue = (unsigned char *)ECDHRSA256KEY;
			keyLen = sizeof(ECDHRSA256KEY);
			break;
		case 521:
			certValue = (unsigned char *)ECDHRSA521;
			certLen = sizeof(ECDHRSA521);
			keyValue = (unsigned char *)ECDHRSA521KEY;
			keyLen = sizeof(ECDHRSA521KEY);
			break;
		default:
			_psTraceInt("Invalid ECDH_RSA key length (%d)\n", g_ecdhKeySize);
			return -1;
	}

	if ((rc = matrixSslLoadEcKeysMem(keys, (const unsigned char *)certValue,
				certLen, (const unsigned char *)keyValue, keyLen, CAstream,
				CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	switch (g_eccKeySize) {
		case 192:
			certValue = (unsigned char *)EC192;
			certLen = sizeof(EC192);
			keyValue = (unsigned char *)EC192KEY;
			keyLen = sizeof(EC192KEY);
			break;
		case 224:
			certValue = (unsigned char *)EC224;
			certLen = sizeof(EC224);
			keyValue = (unsigned char *)EC224KEY;
			keyLen = sizeof(EC224KEY);
			break;
		case 256:
			certValue = (unsigned char *)EC256;
			certLen = sizeof(EC256);
			keyValue = (unsigned char *)EC256KEY;
			keyLen = sizeof(EC256KEY);
			break;
		case 384:
			certValue = (unsigned char *)EC384;
			certLen = sizeof(EC384);
			keyValue = (unsigned char *)EC384KEY;
			keyLen = sizeof(EC384KEY);
			break;
		case 521:
			certValue = (unsigned char *)EC521;
			certLen = sizeof(EC521);
			keyValue = (unsigned char *)EC521KEY;
			keyLen = sizeof(EC521KEY);
			break;
		default:
			_psTraceInt("Invalid ECC key length (%d)\n", g_eccKeySize);
			return -1;
	}

	if ((rc = matrixSslLoadEcKeysMem(keys, certValue, certLen,
			keyValue, keyLen, CAstream, CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParamsMem(keys, DHPARAM2048, DHPARAM2048_SIZE)
			< 0) {
		_psTrace("Unable to load DH parameters\n");
	}
#endif /* DH_PARAMS */


	psFree(CAstream, NULL);
#else /* USE_HEADER_KEYS */
/*
	File based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	if (g_rsaKeySize == 3072)
		CAstreamLen += (int32)strlen(rsaCA3072File) + 1;
	else
		CAstreamLen += (int32)strlen(rsaCAFile) + 1;
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecdhRsaCAFile) + 1;
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecCAFile) + 1;
#endif
	CAstream = psMalloc(NULL, CAstreamLen);
	memset(CAstream, 0x0, CAstreamLen);

	CAstreamLen = 0;
#ifdef USE_RSA
	if (g_rsaKeySize == 3072) {
		memcpy(CAstream, rsaCA3072File,	strlen(rsaCA3072File));
		CAstreamLen += strlen(rsaCA3072File);
	}
	else {
		memcpy(CAstream, rsaCAFile,	strlen(rsaCAFile));
		CAstreamLen += strlen(rsaCAFile);
	}
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	memcpy(CAstream + CAstreamLen, ecdhRsaCAFile,  strlen(ecdhRsaCAFile));
	CAstreamLen += strlen(ecdhRsaCAFile);
#endif
#endif
#ifdef USE_ECC
	if (CAstreamLen > 0) {
		memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	}
	memcpy(CAstream + CAstreamLen, ecCAFile,  strlen(ecCAFile));
#endif

/* Load Identiy */
#ifdef EXAMPLE_RSA_KEYS
	if ((rc = matrixSslLoadRsaKeys(keys, rsaCertFile, rsaPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif


#ifdef EXAMPLE_ECDH_RSA_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecdhRsaCertFile, ecdhRsaPrivkeyFile,
			NULL, (char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecCertFile, ecPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParams(keys, dhParamFile) < 0) {
		_psTrace("Unable to load DH parameters\n");
	}
#endif


	psFree(CAstream);
#endif /* USE_HEADER_KEYS */


#ifdef USE_PSK_CIPHER_SUITE
	/* The first ID is considered as null-terminiated string for
	   compatibility with OpenSSL's s_client default client identity
	   "Client_identity" */

 	matrixSslLoadPsk(keys,
            	PSK_HEADER_TABLE[0].key,
            	sizeof(PSK_HEADER_TABLE[0].key),
            	PSK_HEADER_TABLE[0].id,
            	strlen((const char *)PSK_HEADER_TABLE[0].id));

	for (rc = 1; rc < PSK_HEADER_TABLE_COUNT; rc++) {
        matrixSslLoadPsk(keys,
            	PSK_HEADER_TABLE[rc].key,
            	sizeof(PSK_HEADER_TABLE[rc].key),
            	PSK_HEADER_TABLE[rc].id,
            	sizeof(PSK_HEADER_TABLE[rc].id));
    }
#endif /* PSK */


	if ((sock = newUdpSocket(NULL, DTLS_PORT, &err)) == INVALID_SOCKET) {
		_psTrace("Error creating UDP socket\n");
		goto DTLS_EXIT;
	}
	_psTraceInt("DTLS server running on port %d\n", DTLS_PORT);

/*
	Server loop
*/
	for (exitFlag = 0; exitFlag == 0;) {
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;
		FD_ZERO(&readfd);
		FD_SET(sock, &readfd);
/*
		Always just wait a second for any incoming data.  The primary loop
		mechanism reads data from one source and replies with handshake data
		if needed (that reply may be a resend if reading a repeat message).
		Individual client timeouts are then handled
*/
		val = select(sock+1, &readfd, NULL, NULL, &timeout);

		if (val > 0 && FD_ISSET(sock, &readfd)) {
			psTraceIntDtls("Select woke %d\n", val);
			/* recvfrom data must always go into generic buffer becuase we
			don't yet know who it is from */
			inaddrlen = sizeof(struct sockaddr_in);
			if ((recvLen = (int32)recvfrom(sock, recvfromBuf, recvfromBufLen, 0,
										   (struct sockaddr *)&inaddr, &inaddrlen)) < 0) {
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
						SOCKET_ERRNO != WSAECONNRESET) {
#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					_psTraceInt("recvfrom error %d.  Exiting\n", SOCKET_ERRNO);
					goto DTLS_EXIT;
				}
				continue;
				}
#ifdef USE_DTLS_DEBUG_TRACE
			/* nice for debugging */
			{
				const char *addrstr;
				addrstr = getaddrstring((struct sockaddr *)&inaddr, 1);
				psTraceIntDtls("Read %d bytes ", recvLen);
				psTraceStrDtls("from %s\n", (char*)addrstr);
				psFree(addrstr, NULL);
			}
#endif

			/* Locate the SSL context of this receive and create a new session
			if not found */
			if ((dtlsCtx = findClient(inaddr)) == NULL) {
				memset(&options, 0x0, sizeof(sslSessOpts_t));
				options.versionFlag = SSL_FLAGS_DTLS;
				options.truncHmac = -1;

				if (matrixSslNewServerSession(&ssl, keys,
						certValidator, &options) < 0) {
					rc = DTLS_FATAL; goto DTLS_EXIT;
				}
				if ((dtlsCtx = registerClient(inaddr, sock, ssl)) == NULL) {
					/* Client list is full.  Just have to ignore */
					matrixSslDeleteSession(ssl);
					continue;
				}
			}

			ssl = dtlsCtx->ssl;
			/*  Move socket data into internal buffer */
			freeBufLen = matrixSslGetReadbuf(ssl, &sslBuf);
			psAssert(freeBufLen >= recvLen);
			psAssert(freeBufLen == matrixDtlsGetPmtu());
			memcpy(sslBuf, recvfromBuf, recvLen);

			/*	Notify SSL state machine that we've received more data into the
			ssl buffer retreived with matrixSslGetReadbuf. */
			if ((rcr = matrixSslReceivedData(ssl, recvLen, &sslBuf,
					(uint32*)&freeBufLen)) < 0) {
				clearClient(dtlsCtx);
				continue;	/* Next connection */
			}
			/* Update last activity time and reset timeout*/
			psGetTime(&dtlsCtx->lastRecvTime, NULL);
			dtlsCtx->timeout = MIN_WAIT_SECS;

PROCESS_MORE_FROM_BUFFER:
			/* Process any incoming plaintext application data */
			switch (rcr) {
				case MATRIXSSL_HANDSHAKE_COMPLETE:
					/* This is a resumed handshake case which means we are
					the last to receive handshake flights and we know the
					handshake is complete.  However, the internal workings
					will not flag us officially complete until we receive
					application data from the peer so we need a local flag
					to handle this case so we are not resending our final
					flight */
					dtlsCtx->connStatus = RESUMED_HANDSHAKE_COMPLETE;
					psTraceDtls("Got HANDSHAKE_COMPLETE out of ReceivedData\n");
					break;
				case MATRIXSSL_APP_DATA:
					/* Now safe to clear the connStatus flag that was keeping
					track of the state between receiving the final flight of
					a resumed handshake and receiving application data.  The
					reciept of app data has now internally disabled flight
					resends */
					dtlsCtx->connStatus = 0;
					_psTrace("Client connected.  Received...\n");
					_psTraceStr("%s\n", (char*)sslBuf);
					break;
				case MATRIXSSL_REQUEST_SEND:
					/* Still handshaking with this particular client */
					while ((sslBufLen = matrixDtlsGetOutdata(ssl,
							&sslBuf)) > 0) {
						if ((sendLen = udpSend(dtlsCtx->fd, sslBuf, sslBufLen,
											   (struct sockaddr*)&inaddr,
											   sizeof(struct sockaddr_in),
											   dtlsCtx->timeout,
											   packet_loss_prob,
											   NULL)) < 0) {
							psTraceDtls("udpSend error.  Ignoring\n");
						}
						/* Always indicate the entire datagram was sent as
						there is no way for DTLS to handle partial records.
						Resends and timeouts will handle any problems */
						rcs = matrixDtlsSentData(ssl, sslBufLen);

						if (rcs == MATRIXSSL_REQUEST_CLOSE) {
							psTraceDtls("Got REQUEST_CLOSE out of SentData\n");
							clearClient(dtlsCtx);
							break;
						}
						if (rcs == MATRIXSSL_HANDSHAKE_COMPLETE) {
							/* This is the standard handshake case */
							_psTrace("Got HANDSHAKE_COMPLETE from SentData\n");
							break;
						}
						/* SSL_REQUEST_SEND is handled by loop logic */
					}
					break;
				case MATRIXSSL_REQUEST_RECV:
					psTraceDtls("Got REQUEST_RECV from ReceivedData\n");
					break;
				case MATRIXSSL_RECEIVED_ALERT:
					/* The first byte of the buffer is the level */
					/* The second byte is the description */
					if (*sslBuf == SSL_ALERT_LEVEL_FATAL) {
						psTraceIntDtls("Fatal alert: %d, closing connection.\n",
									*(sslBuf + 1));
						clearClient(dtlsCtx);
						continue; /* Next connection */
					}
					/* Closure alert is normal (and best) way to close */
					if (*(sslBuf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
						clearClient(dtlsCtx);
						continue; /* Next connection */
					}
					psTraceIntDtls("Warning alert: %d\n", *(sslBuf + 1));
					if ((rcr = matrixSslProcessedData(ssl, &sslBuf,
							(uint32*)&freeBufLen)) == 0) {
						continue;
					}
					goto PROCESS_MORE_FROM_BUFFER;

				default:
					continue; /* Next connection */
			}
		} else if (val < 0) {
			if (SOCKET_ERRNO != EINTR) {
				psTraceIntDtls("unhandled error %d from select", SOCKET_ERRNO);
			}
		}
/*
		Have either timed out waiting for a read or have processed a single
		recv.  Now check to see if any timeout resends are required
*/
		rc = handleResends(sock);
	}	/* Main Select Loop */


DTLS_EXIT:
	psFree(recvfromBuf, NULL);
CLIENT_EXIT:
	closeClientList();
MATRIX_EXIT:
	matrixSslDeleteKeys(keys);
	matrixSslClose();
	if (sock != INVALID_SOCKET) close(sock);
	return rc;
}

/******************************************************************************/
/*
	Work through client list and resend handshake flight if haven't heard
	from them in a while
*/
static int32 handleResends(SOCKET sock)
{
	serverDtls_t	*dtlsCtx;
	ssl_t			*ssl;
	psTime_t		now;
	unsigned char	*sslBuf;
	int16			i;
	int32			sendLen, rc;
	uint32			timeout, sslBufLen, clientCount;

	clientCount = 0; /* return code is number of active clients or < 0 on error */
	psGetTime(&now, NULL);
	for (i = 0; i < tableSize; i++) {
		dtlsCtx = &clientTable[i];
		if (dtlsCtx->ssl != NULL) {
			clientCount++;
			timeout = psDiffMsecs(dtlsCtx->lastRecvTime, now, NULL) / 1000;
			/* Haven't heard from this client in a while.  Might need resend */
			if (timeout > dtlsCtx->timeout) {
				/* if timeout is too great. clear conn */
				if (dtlsCtx->timeout >= MAX_WAIT_SECS) {
					clearClient(dtlsCtx);
					clientCount--;
					break;
				}
				/* Increase the timeout for next pass */
				dtlsCtx->timeout *= 2;

				/* If we are in a RESUMED_HANDSHAKE_COMPLETE state that means
				we are positive the handshake is complete so we don't want to
				resend no matter what.  This is an interim state before the
				internal mechaism sees an application data record and flags
				us as complete officially */
				if (dtlsCtx->connStatus == RESUMED_HANDSHAKE_COMPLETE) {
					psTraceDtls("Connected but awaiting data\n");
					continue;
				}
				ssl = dtlsCtx->ssl;
				while ((sslBufLen = matrixDtlsGetOutdata(ssl,
						&sslBuf)) > 0) {
					if ((sendLen = udpSend(dtlsCtx->fd, sslBuf, sslBufLen,
										   (struct sockaddr*)&dtlsCtx->addr,
										   sizeof(struct sockaddr_in),
										   dtlsCtx->timeout / 2,
										   packet_loss_prob,
										   NULL)) < 0) {
						psTraceDtls("udpSend error.  Ignoring\n");
					}
					/* Always indicate the entire datagram was sent as
					there is no way for DTLS to handle partial records.
					Resends and timeouts will handle any problems */
					if ((rc = matrixDtlsSentData(ssl, sslBufLen)) < 0) {
						psTraceDtls("internal error\n");
						clearClient(dtlsCtx);
						clientCount--;
						break;
					}
					if (rc == MATRIXSSL_REQUEST_CLOSE) {
						psTraceDtls("Got REQUEST_CLOSE out of SentData\n");
						clearClient(dtlsCtx);
						clientCount--;
						break;
					}
					if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
						/* This is the standard handshake case */
						psTraceDtls("Got HANDSHAKE_COMPLETE out of SentData\n");
						break;
					}
					/* SSL_REQUEST_SEND is handled by loop logic */
				}

			}
		}
	}
	return clientCount;
}
Example #11
0
/*
	Example callback to show possiblie outcomes of certificate validation.
	If this callback is not registered in matrixSslNewServerSession
	the connection will be accepted or closed based on the alert value.
 */
static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
{
#ifndef USE_ONLY_PSK_CIPHER_SUITE
	psX509Cert_t	*next;
		
	/* Did we even find a CA that issued the certificate? */
	if (alert == SSL_ALERT_UNKNOWN_CA) {
			/* Example to allow anonymous connections based on a define */
		if (ALLOW_ANON_CONNECTIONS) {
			_psTraceStr("Allowing anonymous connection for: %s.\n",
				cert->subject.commonName);
			return SSL_ALLOW_ANON_CONNECTION;
		}
		_psTrace("ERROR: No matching CA found.  Terminating connection\n");
	}

	/* Test if the server certificate didn't match the name passed to
		expectedName in matrixSslNewClientSession */
	if (alert == SSL_ALERT_CERTIFICATE_UNKNOWN) {
		_psTraceStr("ERROR: %s not found in cert subject names\n",
			ssl->expectedName);
	}
	
	if (alert == SSL_ALERT_CERTIFICATE_EXPIRED) {
#ifdef POSIX
		_psTrace("ERROR: A cert did not fall within the notBefore/notAfter window\n");
#else
		_psTrace("WARNING: Certificate date window validation not implemented\n");
		alert = 0;
#endif
	}
	
	if (alert == SSL_ALERT_ILLEGAL_PARAMETER) {
		_psTrace("ERROR: Found correct CA but X.509 extension details are wrong\n");
	}
	
	/* Key usage related problems */
	next = cert;
	while (next) {
		if (next->authStatus == PS_CERT_AUTH_FAIL_EXTENSION) {
			if (cert->authFailFlags & PS_CERT_AUTH_FAIL_KEY_USAGE_FLAG) {
				_psTrace("CA keyUsage extension doesn't allow cert signing\n");
			}
			if (cert->authFailFlags & PS_CERT_AUTH_FAIL_EKU_FLAG) {
				_psTrace("Cert extendedKeyUsage extension doesn't allow TLS\n");
			}
		}
		next = next->next;
	}
	
	if (alert == SSL_ALERT_BAD_CERTIFICATE) {
		/* Should never let a connection happen if this is set.  There was
			either a problem in the presented chain or in the final CA test */
		_psTrace("ERROR: Problem in certificate validation.  Exiting.\n");	
	}

	
	if (alert == 0) _psTraceStr("SUCCESS: Validated cert for: %s.\n",
		cert->subject.commonName);
	
#endif /* !USE_ONLY_PSK_CIPHER_SUITE */
	return alert; 
}