/* * httpReflector.c * Release $Name: MATRIXSSL_1_8_8_OPEN $ * * Simple example program for MatrixSSL * Accepts a HTTPS request and echos the response back to the sender. */ /* * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved. * The latest version of this code is available at http://www.matrixssl.org * * This software is open source; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This General Public License does NOT permit incorporating this software * into proprietary programs. If you are unable to comply with the GPL, a * commercial license for this software may be purchased from PeerSec Networks * at http://www.peersec.com * * This program is distributed in WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * http://www.gnu.org/copyleft/gpl.html */ /******************************************************************************/ #include #include #include /******************************************************************************/ #include "sslSocket.h" #define HTTPS_PORT 4433 static char keyfile[] = "privkeySrv.pem"; static char certfile[] = "certSrv.pem"; static const char responseHdr[] = "HTTP/1.0 200 OK\r\n" "Server: PeerSec Networks MatrixSSL\r\n" "Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n" "Content-type: text/plain\r\n" "\r\n" "PeerSec Networks\n" "Successful MatrixSSL request:\n"; static const char quitString[] = "GET /quit"; static const char againString[] = "GET /again"; /******************************************************************************/ /* Helper framework for testing matrixSslReadKeysMem */ #define USE_MEM_CERTS 0 #if USE_MEM_CERTS #include static int32 getFileBin(char *fileName, unsigned char **bin, int32 *binLen); #endif /******************************************************************************/ /* This example application acts as an https server that accepts incoming client requests and reflects incoming data back to that client. */ #if VXWORKS int _httpsReflector(char *arg1) #elif WINCE int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) #else int main(int argc, char **argv) #endif { sslConn_t *cp; sslKeys_t *keys; SOCKET listenfd, fd; WSADATA wsaData; unsigned char buf[1024]; unsigned char *response, *c; int responseHdrLen, acceptAgain, flags; int bytes, status, quit, again, rc, err; #if USE_MEM_CERTS unsigned char *servBin, *servKeyBin, *caBin; int servBinLen, caBinLen, servKeyBinLen; #endif cp = NULL; /* Initialize Windows sockets (no-op on other platforms) */ WSAStartup(MAKEWORD(1,1), &wsaData); /* Initialize the MatrixSSL Library, and read in the public key (certificate) and private key. */ if (matrixSslOpen() < 0) { fprintf(stderr, "matrixSslOpen failed, exiting..."); } #if USE_MEM_CERTS /* Example of DER binary certs for matrixSslReadKeysMem */ getFileBin("certSrv.der", &servBin, &servBinLen); getFileBin("privkeySrv.der", &servKeyBin, &servKeyBinLen); getFileBin("CAcertCln.der", &caBin, &caBinLen); matrixSslReadKeysMem(&keys, servBin, servBinLen, servKeyBin, servKeyBinLen, caBin, caBinLen); free(servBin); free(servKeyBin); free(caBin); #else /* Standard PEM files */ if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0) { fprintf(stderr, "Error reading or parsing %s or %s.\n", certfile, keyfile); goto promptAndExit; } #endif /* USE_MEM_CERTS */ fprintf(stdout, "Run httpsClient or type https://127.0.0.1:%d into your local Web browser.\n", HTTPS_PORT); /* Create the listen socket */ if ((listenfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) { fprintf(stderr, "Cannot listen on port %d\n", HTTPS_PORT); goto promptAndExit; } /* Set blocking or not on the listen socket */ setSocketBlock(listenfd); /* Loop control initalization */ quit = 0; again = 0; flags = 0; acceptAgain = 1; /* Main connection loop */ while (!quit) { if (acceptAgain) { /* sslAccept creates a new server session */ /* TODO - deadlock on blocking socket accept. Should disable blocking here */ if ((fd = socketAccept(listenfd, &err)) == INVALID_SOCKET) { fprintf(stdout, "Error accepting connection: %d\n", err); continue; } if ((rc = sslAccept(&cp, fd, keys, NULL, flags)) != 0) { socketShutdown(fd); continue; } flags = 0; acceptAgain = 0; } /* Read response < 0 return indicates an error. 0 return indicates an EOF or CLOSE_NOTIFY in this situation > 0 indicates that some bytes were read. Keep reading until we see the /r/n/r/n from the GET request. We don't actually parse the request, we just echo it back. */ c = buf; readMore: if ((rc = sslRead(cp, c, sizeof(buf) - (int)(c - buf), &status)) > 0) { c += rc; if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) { goto readMore; } } else { if (rc < 0) { fprintf(stdout, "sslRead error. dropping connection.\n"); } if (rc < 0 || status == SSLSOCKET_EOF || status == SSLSOCKET_CLOSE_NOTIFY) { socketShutdown(cp->fd); sslFreeConnection(&cp); acceptAgain = 1; continue; } goto readMore; } /* Done reading. If the incoming data starts with the quitString, quit the application after this request */ if (memcmp(buf, quitString, min(c - buf, (int)strlen(quitString))) == 0) { quit++; fprintf(stdout, "Q"); } /* If the incoming data starts with the againString, we are getting a pipeline request on the same session. Don't close and wait for new connection in this case. */ if (memcmp(buf, againString, min(c - buf, (int)strlen(againString))) == 0) { again++; fprintf(stdout, "A"); } else { fprintf(stdout, "R"); again = 0; } /* Copy the canned response header and decoded data from socket as the response (reflector) */ responseHdrLen = (int)strlen(responseHdr); bytes = responseHdrLen + (int)(c - buf); response = malloc(bytes); memcpy(response, responseHdr, responseHdrLen); memcpy(response + responseHdrLen, buf, c - buf); /* Send response. < 0 return indicates an error. 0 return indicates not all data was sent and we must retry > 0 indicates that all requested bytes were sent */ writeMore: rc = sslWrite(cp, response, bytes, &status); if (rc < 0) { free(response); fprintf(stdout, "Internal sslWrite error\n"); socketShutdown(cp->fd); sslFreeConnection(&cp); continue; } else if (rc == 0) { goto writeMore; } free(response); /* If we saw an /again request, loop up and process another pipelined HTTP request. The /again request is supported in the httpsClient example code. */ if (again) { continue; } /* Send a closure alert for clean shutdown of remote SSL connection This is for good form, some implementations just close the socket */ sslWriteClosureAlert(cp); /* Close the socket and wait for next connection (new session) */ socketShutdown(cp->fd); sslFreeConnection(&cp); acceptAgain = 1; } /* Close listening socket, free remaining items */ if (cp && cp->ssl) { socketShutdown(cp->fd); sslFreeConnection(&cp); } socketShutdown(listenfd); matrixSslFreeKeys(keys); matrixSslClose(); WSACleanup(); promptAndExit: fprintf(stdout, "\n\nPress return to exit...\n"); getchar(); return 0; } #if USE_MEM_CERTS static int32 getFileBin(char *fileName, unsigned char **bin, int32 *binLen) { FILE *fp; struct stat fstat; size_t tmp = 0; *binLen = 0; *bin = NULL; if (fileName == NULL) { return -1; } if ((stat(fileName, &fstat) != 0) || (fp = fopen(fileName, "rb")) == NULL) { return -7; /* FILE_NOT_FOUND */ } *bin = malloc(fstat.st_size); if (*bin == NULL) { return -8; /* SSL_MEM_ERROR */ } while (((tmp = fread(*bin + *binLen, sizeof(char), 512, fp)) > 0) && (*binLen < fstat.st_size)) { *binLen += (int32)tmp; } fclose(fp); return 0; } #endif /******************************************************************************/