error_t sslClientTest(void) { error_t error; size_t length; IpAddr ipAddr; static char_t buffer[256]; //Underlying socket Socket *socket = NULL; //SSL/TLS context TlsContext *tlsContext = NULL; //Debug message TRACE_INFO("Resolving server name...\r\n"); //Resolve SSL server name error = getHostByName(NULL, APP_SERVER_NAME, &ipAddr, 0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to resolve server name!\r\n"); //Exit immediately return error; } //Create a new socket to handle the request socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Any error to report? if(!socket) { //Debug message TRACE_INFO("Failed to open socket!\r\n"); //Exit immediately return ERROR_OPEN_FAILED; } //Start of exception handling block do { //Debug message TRACE_INFO("Connecting to SSL server %s\r\n", ipAddrToString(&ipAddr, NULL)); //Connect to the SSL server error = socketConnect(socket, &ipAddr, APP_SERVER_PORT); //Any error to report? if(error) break; //Initialize SSL/TLS context tlsContext = tlsInit(); //Initialization failed? if(!tlsContext) { //Report an error error = ERROR_OUT_OF_MEMORY; //Exit immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(tlsContext, socket); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(tlsContext, YARROW_PRNG_ALGO, &yarrowContext); //Any error to report? if(error) break; #if (APP_SET_CIPHER_SUITES == ENABLED) //Preferred cipher suite list error = tlsSetCipherSuites(tlsContext, cipherSuites, arraysize(cipherSuites)); //Any error to report? if(error) break; #endif #if (APP_SET_SERVER_NAME == ENABLED) //Set the fully qualified domain name of the server error = tlsSetServerName(tlsContext, APP_SERVER_NAME); //Any error to report? if(error) break; #endif #if (APP_SET_TRUSTED_CA_LIST == ENABLED) //Import the list of trusted CA certificates error = tlsSetTrustedCaList(tlsContext, trustedCaList, trustedCaListLength); //Any error to report? if(error) break; #endif #if (APP_SET_CLIENT_CERT == ENABLED) //Import the client's certificate error = tlsAddCertificate(tlsContext, clientCert, clientCertLength, clientPrivateKey, clientPrivateKeyLength); //Any error to report? if(error) break; #endif //Establish a secure session error = tlsConnect(tlsContext); //TLS handshake failure? if(error) break; //Format HTTP request sprintf(buffer, "GET %s HTTP/1.0\r\nHost: %s:%u\r\n\r\n", APP_REQUEST_URI, APP_SERVER_NAME, APP_SERVER_PORT); //Debug message TRACE_INFO("\r\n"); TRACE_INFO("HTTP request:\r\n%s", buffer); //Send the request error = tlsWrite(tlsContext, buffer, strlen(buffer), 0); //Any error to report? if(error) break; //Debug message TRACE_INFO("HTTP response:\r\n"); //Read the whole response while(1) { //Read data error = tlsRead(tlsContext, buffer, sizeof(buffer) - 1, &length, 0); //End of stream? if(error) break; //Properly terminate the string with a NULL character buffer[length] = '\0'; //Debug message TRACE_INFO("%s", buffer); } //Successfull processing error = NO_ERROR; //End of exception handling block } while(0); //Any error to report? if(error) { //Debug message TRACE_INFO("Failed to communicate with SSL server!\r\n"); } //Terminate TLS session tlsFree(tlsContext); //Close socket socketClose(socket); //Debug message TRACE_INFO("Connection closed...\r\n"); //Return status code return error; }
int_t main(void) { error_t error; size_t length; int_t ret; WSADATA wsaData; HOSTENT *host; SOCKADDR_IN addr; HCRYPTPROV hProvider; YarrowContext yarrowContext; char_t buffer[512]; uint8_t seed[32]; //Socket descriptor SOCKET sock = SOCKET_ERROR; //SSL/TLS context TlsContext *tlsContext = NULL; //Credentials char_t *clientCert = NULL; size_t clientCertLength = 0; char_t *clientPrivateKey = NULL; size_t clientPrivateKeyLength = 0; char_t *trustedCaList = NULL; size_t trustedCaListLength = 0; //Start-up message TRACE_INFO("******************************\r\n"); TRACE_INFO("*** CycloneSSL Client Demo ***\r\n"); TRACE_INFO("******************************\r\n"); TRACE_INFO("\r\n"); //Acquire cryptographic context ret = CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); //Any error to report? if(!ret) { //Debug message TRACE_ERROR("Error: Cannot acquire cryptographic context (%d)\r\n", GetLastError()); //Exit immediately return ERROR_FAILURE; } //Generate a random seed ret = CryptGenRandom(hProvider, sizeof(seed), seed); //Any error to report? if(!ret) { //Debug message TRACE_ERROR("Error: Failed to generate random data (%d)\r\n", GetLastError()); //Exit immediately return ERROR_FAILURE; } //Release cryptographic context CryptReleaseContext(hProvider, 0); //PRNG initialization error = yarrowInit(&yarrowContext); //Any error to report? if(error) { //Debug message TRACE_ERROR("Error: PRNG initialization failed (%d)\r\n", error); //Exit immediately return ERROR_FAILURE; } //Properly seed the PRNG error = yarrowSeed(&yarrowContext, seed, sizeof(seed)); //Any error to report? if(error) { //Debug message TRACE_ERROR("Error: Failed to seed PRNG (%d)\r\n", error); //Exit immediately return error; } //Winsock initialization ret = WSAStartup(MAKEWORD(2, 2), &wsaData); //Any error to report? if(ret) { //Debug message TRACE_ERROR("Error: Winsock initialization failed (%d)\r\n", ret); //Exit immediately return ERROR_FAILURE; } //Start of exception handling block do { //Debug message TRACE_INFO("Loading credentials...\r\n"); //Load trusted CA certificates error = readPemFile(APP_CA_CERT_BUNDLE, &trustedCaList, &trustedCaListLength); //Any error to report? if(error) break; //Load client's certificate error = readPemFile(APP_CLIENT_CERT, &clientCert, &clientCertLength); //Any error to report? if(error) break; //Load client's private key error = readPemFile(APP_CLIENT_PRIVATE_KEY, &clientPrivateKey, &clientPrivateKeyLength); //Any error to report? if(error) break; //Debug message TRACE_INFO("Trying to resolve %s...\r\n", APP_SERVER_NAME); //Resolve server name host = gethostbyname(APP_SERVER_NAME); //Failed to resolve server name? if(!host) { //Debug message TRACE_ERROR("Error: Cannot resolve server name (%d)\r\n", WSAGetLastError()); //Report an error error = ERROR_FAILURE; //Exit immediately break; } //Open a socket sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Failed to open socket? if(sock < 0) { //Debug message TRACE_ERROR("Error: Cannot open socket (%d)\r\n", WSAGetLastError()); //Report an error error = ERROR_FAILURE; //Exit immediately break; } //Destination address addr.sin_family = host->h_addrtype; memcpy(&addr.sin_addr, host->h_addr, host->h_length); addr.sin_port = htons(APP_SERVER_PORT); //Connect to the SSL server ret = connect(sock, (PSOCKADDR) &addr, sizeof(addr)); //Connection with server failed? if(ret < 0) { //Debug message TRACE_ERROR("Error: Failed to connect (%d)\r\n", WSAGetLastError()); //Report an error error = ERROR_FAILURE; //Exit immediately break; } //Initialize SSL/TLS context tlsContext = tlsInit(); //Initialization failed? if(!tlsContext) { //Report an error error = ERROR_OUT_OF_MEMORY; //Exit immediately break; } //Bind TLS to the relevant socket error = tlsSetSocket(tlsContext, sock); //Any error to report? if(error) break; //Select client operation mode error = tlsSetConnectionEnd(tlsContext, TLS_CONNECTION_END_CLIENT); //Any error to report? if(error) break; //Set the PRNG algorithm to be used error = tlsSetPrng(tlsContext, YARROW_PRNG_ALGO, &yarrowContext); //Any error to report? if(error) break; #if (APP_SET_CIPHER_SUITES == ENABLED) //Preferred cipher suite list error = tlsSetCipherSuites(tlsContext, cipherSuites, arraysize(cipherSuites)); //Any error to report? if(error) break; #endif #if (APP_SET_SERVER_NAME == ENABLED) //Set the fully qualified domain name of the server error = tlsSetServerName(tlsContext, APP_SERVER_NAME); //Any error to report? if(error) break; #endif #if (APP_SET_TRUSTED_CA_LIST == ENABLED) //Import the list of trusted CA certificates error = tlsSetTrustedCaList(tlsContext, trustedCaList, trustedCaListLength); //Any error to report? if(error) break; #endif #if (APP_SET_CLIENT_CERT == ENABLED) //Import the client's certificate error = tlsAddCertificate(tlsContext, clientCert, clientCertLength, clientPrivateKey, clientPrivateKeyLength); //Any error to report? if(error) break; #endif //Establish a secure session error = tlsConnect(tlsContext); //TLS handshake failure? if(error) break; //Format HTTP request sprintf(buffer, "GET %s HTTP/1.0\r\nHost: %s:%u\r\n\r\n", APP_REQUEST_URI, APP_SERVER_NAME, APP_SERVER_PORT); //Debug message TRACE_INFO("\r\n"); TRACE_INFO("HTTP request:\r\n%s", buffer); //Send the request error = tlsWrite(tlsContext, buffer, strlen(buffer), 0); //Any error to report? if(error) break; //Debug message TRACE_INFO("HTTP response:\r\n"); //Read the whole response while(1) { //Read data error = tlsRead(tlsContext, buffer, sizeof(buffer) - 1, &length, 0); //End of stream? if(error) break; //Properly terminate the string with a NULL character buffer[length] = '\0'; //Debug message TRACE_INFO("%s", buffer); } //Successfull processing error = NO_ERROR; //End of exception handling block } while(0); //Terminate TLS session tlsFree(tlsContext); //Close socket if necessary if(sock >= 0) closesocket(sock); //Free previously allocated resources free(trustedCaList); free(clientCert); free(clientPrivateKey); //Release PRNG context yarrowRelease(&yarrowContext); //Winsock related cleanup WSACleanup(); //Dumps all the memory blocks in the heap when a memory leak has occurred _CrtDumpMemoryLeaks(); //Wait for the user to press a key system("pause"); //Return status code return error; }