static int32 initializeClient(sslConn_t *conn, testCipherSpec_t cipherSuite, sslSessionId_t *sid) { ssl_t *ssl; sslKeys_t *keys; #ifdef ENABLE_PERF_TIMING psTime_t start, end; #endif /* ENABLE_PERF_TIMING */ if (conn->keys == NULL) { if (matrixSslNewKeys(&keys) < PS_SUCCESS) { return PS_MEM_FAIL; } conn->keys = keys; if (cipherSuite.rsa && !cipherSuite.ecdh) { #if defined(MATRIX_USE_FILE_SYSTEM) && !defined(USE_HEADER_KEYS) if (matrixSslLoadRsaKeys(keys, clnCertFile, clnKeyFile, NULL, svrCAfile) < 0) { return PS_FAILURE; } #endif /* MATRIX_USE_FILE_SYSTEM && !USE_HEADER_KEYS */ #ifdef USE_HEADER_KEYS if (matrixSslLoadRsaKeysMem(keys, RSA2048, sizeof(RSA2048), RSA2048KEY, sizeof(RSA2048KEY), RSA1024CA, sizeof(RSA1024CA)) < 0) { return PS_FAILURE; } #endif /* USE_HEADER_KEYS */ } } conn->ssl = NULL; #ifdef ENABLE_PERF_TIMING conn->runningTime = 0; psGetTime(&start); #endif /* ENABLE_PERF_TIMING */ if (matrixSslNewClientSession(&ssl, conn->keys, sid, cipherSuite.cipherId, clnCertChecker, NULL, NULL, newSessionFlag) < 0) { return PS_FAILURE; } #ifdef ENABLE_PERF_TIMING psGetTime(&end); conn->runningTime += psDiffMsecs(start, end); #endif /* ENABLE_PERF_TIMING */ conn->ssl = ssl; return PS_SUCCESS; }
static int32 initializeResumedHandshake(sslConn_t *clnConn, sslConn_t *svrConn, testCipherSpec_t cipherSuite) { sslSessionId_t *sessionId; #ifdef ENABLE_PERF_TIMING psTime_t start, end; #endif /* ENABLE_PERF_TIMING */ sessionId = clnConn->ssl->sid; matrixSslDeleteSession(clnConn->ssl); #ifdef ENABLE_PERF_TIMING clnConn->runningTime = 0; psGetTime(&start); #endif /* ENABLE_PERF_TIMING */ if (matrixSslNewClientSession(&clnConn->ssl, clnConn->keys, sessionId, cipherSuite.cipherId, clnCertChecker, NULL, NULL, newSessionFlag) < 0) { return PS_FAILURE; } #ifdef ENABLE_PERF_TIMING psGetTime(&end); clnConn->runningTime += psDiffMsecs(start, end); #endif /* ENABLE_PERF_TIMING */ matrixSslDeleteSession(svrConn->ssl); #ifdef ENABLE_PERF_TIMING svrConn->runningTime = 0; psGetTime(&start); #endif /* ENABLE_PERF_TIMING */ if (matrixSslNewServerSession(&svrConn->ssl, svrConn->keys, NULL, newSessionFlag) < 0) { return PS_FAILURE; } #ifdef ENABLE_PERF_TIMING psGetTime(&end); svrConn->runningTime += psDiffMsecs(start, end); #endif /* ENABLE_PERF_TIMING */ return PS_SUCCESS; }
CAMLprim value stub_new_client_session_native(value keys, value sid, value cipherSpec, value cert_cb, value extensions, value ext_cb, value flags) { CAMLparam5(keys, sid, cipherSpec, cert_cb, extensions); CAMLxparam2(ext_cb, flags); ssl_t *ssl; int rc; rc=matrixSslNewClientSession(&ssl, sslKeys_t_val(keys), NULL, /*sslSessionId_t_val(sid), */ Int_val(cipherSpec), certCb, NULL, NULL, 0); if(rc != MATRIXSSL_REQUEST_SEND) { fprintf(stderr,"rc=%d\n",rc); caml_failwith("New client session failed"); } CAMLreturn(alloc_ssl_t(ssl)); }
/* Make a secure HTTP request to a defined IP and port Connection is made in blocking socket mode The connection is considered successful if the SSL/TLS session is negotiated successfully, a request is sent, and a HTTP response is received. */ static int32 httpsClientConnection(sslKeys_t *keys, sslSessionId_t *sid) { int32 rc, transferred, len, complete; ssl_t *ssl; unsigned char *buf; httpConn_t cp; SOCKET fd; complete = 0; memset(&cp, 0x0, sizeof(httpConn_t)); fd = socketConnect(HTTPS_IP, HTTPS_PORT, &rc); if (fd == INVALID_SOCKET || rc != PS_SUCCESS) { _psTraceInt("Connect failed: %d. Exiting\n", rc); return PS_PLATFORM_FAIL; } rc = matrixSslNewClientSession(&ssl, keys, sid, 0, certCb, NULL, NULL); if (rc != MATRIXSSL_REQUEST_SEND) { _psTraceInt("New Client Session Failed: %d. Exiting\n", rc); close(fd); return PS_ARG_FAIL; } WRITE_MORE: while ((len = matrixSslGetOutdata(ssl, &buf)) > 0) { transferred = send(fd, buf, len, 0); if (transferred <= 0) { goto L_CLOSE_ERR; } else { /* Indicate that we've written > 0 bytes of data */ if ((rc = matrixSslSentData(ssl, transferred)) < 0) { goto L_CLOSE_ERR; } if (rc == MATRIXSSL_REQUEST_CLOSE) { closeConn(ssl, fd); return MATRIXSSL_SUCCESS; } if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { /* If we sent the Finished SSL message, initiate the HTTP req */ /* (This occurs on a resumption handshake) */ if (httpWriteRequest(ssl) < 0) { goto L_CLOSE_ERR; } goto WRITE_MORE; } /* SSL_REQUEST_SEND is handled by loop logic */ } } READ_MORE: if ((len = matrixSslGetReadbuf(ssl, &buf)) <= 0) { goto L_CLOSE_ERR; } if ((transferred = recv(fd, buf, len, 0)) < 0) { goto L_CLOSE_ERR; } /* If EOF, remote socket closed. But we haven't received the HTTP response so we consider it an error in the case of an HTTP client */ if (transferred == 0) { goto L_CLOSE_ERR; } if ((rc = matrixSslReceivedData(ssl, (int32)transferred, &buf, (uint32*)&len)) < 0) { goto L_CLOSE_ERR; } PROCESS_MORE: switch (rc) { case MATRIXSSL_HANDSHAKE_COMPLETE: #ifdef REHANDSHAKE_TEST /* Test rehandshake capabilities of server. If a successful session resmption rehandshake occurs, this client will be last to send handshake data and MATRIXSSL_HANDSHAKE_COMPLETE will hit on the WRITE_MORE handler and httpWriteRequest will occur there. NOTE: If the server doesn't support session resumption it is possible to fall into an endless rehandshake loop */ if (matrixSslEncodeRehandshake(ssl, NULL, NULL, 0, 0) < 0) { goto L_CLOSE_ERR; } #else /* We got the Finished SSL message, initiate the HTTP req */ if (httpWriteRequest(ssl) < 0) { goto L_CLOSE_ERR; } #endif goto WRITE_MORE; case MATRIXSSL_APP_DATA: if ((rc = httpBasicParse(&cp, buf, len)) < 0) { closeConn(ssl, fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; return MATRIXSSL_ERROR; } if (rc == HTTPS_COMPLETE) { rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len); closeConn(ssl, fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; if (rc < 0) { return MATRIXSSL_ERROR; } else { if (rc > 0) { _psTrace("HTTP data parsing not supported, ignoring.\n"); } _psTrace("SUCCESS: Received HTTP Response\n"); return MATRIXSSL_SUCCESS; } } /* We processed a partial HTTP message */ if ((rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len)) == 0) { goto READ_MORE; } goto PROCESS_MORE; case MATRIXSSL_REQUEST_SEND: goto WRITE_MORE; case MATRIXSSL_REQUEST_RECV: goto READ_MORE; case MATRIXSSL_RECEIVED_ALERT: /* The first byte of the buffer is the level */ /* The second byte is the description */ if (*buf == SSL_ALERT_LEVEL_FATAL) { psTraceIntInfo("Fatal alert: %d, closing connection.\n", *(buf + 1)); goto L_CLOSE_ERR; } /* Closure alert is normal (and best) way to close */ if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) { closeConn(ssl, fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; return MATRIXSSL_SUCCESS; } psTraceIntInfo("Warning alert: %d\n", *(buf + 1)); if ((rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len)) == 0) { /* No more data in buffer. Might as well read for more. */ goto READ_MORE; } goto PROCESS_MORE; default: /* If rc <= 0 we fall here */ goto L_CLOSE_ERR; } L_CLOSE_ERR: _psTrace("FAIL: No HTTP Response\n"); matrixSslDeleteSession(ssl); close(fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; return MATRIXSSL_ERROR; }