server.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 823 行 · 第 1/2 页

C
823
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//**************************************************************************** *  SSL server program listens on a port, accepts client connection, reads  * *  request and responds to it                                              * ****************************************************************************//* Generic header files */#include <stdio.h>#include <string.h>/* NSPR header files */#include "nspr.h"#include "plgetopt.h"#include "prerror.h"#include "prnetdb.h"/* NSS header files */#include "pk11func.h"#include "secitem.h"#include "ssl.h"#include "certt.h"#include "nss.h"#include "secrng.h"#include "secder.h"#include "key.h"#include "sslproto.h"/* Custom header files */#include "sslsample.h"#ifndef PORT_Sprintf#define PORT_Sprintf sprintf#endif#define REQUEST_CERT_ONCE 1#define REQUIRE_CERT_ONCE 2#define REQUEST_CERT_ALL  3#define REQUIRE_CERT_ALL  4/* Global variables */GlobalThreadMgr   threadMGR;char             *password = NULL;CERTCertificate  *cert = NULL;SECKEYPrivateKey *privKey = NULL;int               stopping;static voidUsage(const char *progName){	fprintf(stderr, "Usage: %s -n rsa_nickname -p port [-3RFrf] [-w password]\n""					[-c ciphers] [-d dbdir] \n""-3 means disable SSL v3\n""-r means request certificate on first handshake.\n""-f means require certificate on first handshake.\n""-R means request certificate on all handshakes.\n""-F means require certificate on all handshakes.\n""-c ciphers   Letter(s) chosen from the following list\n""A	  SSL2 RC4 128 WITH MD5\n""B	  SSL2 RC4 128 EXPORT40 WITH MD5\n""C	  SSL2 RC2 128 CBC WITH MD5\n""D	  SSL2 RC2 128 CBC EXPORT40 WITH MD5\n""E	  SSL2 DES 64 CBC WITH MD5\n""F	  SSL2 DES 192 EDE3 CBC WITH MD5\n""\n""a	  SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHA\n""b	  SSL3 FORTEZZA DMS WITH RC4 128 SHA\n""c	  SSL3 RSA WITH RC4 128 MD5\n""d	  SSL3 RSA WITH 3DES EDE CBC SHA\n""e	  SSL3 RSA WITH DES CBC SHA\n""f	  SSL3 RSA EXPORT WITH RC4 40 MD5\n""g	  SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n""h	  SSL3 FORTEZZA DMS WITH NULL SHA\n""i	  SSL3 RSA WITH NULL MD5\n""j	  SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n""k	  SSL3 RSA FIPS WITH DES CBC SHA\n""l	  SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n""m	  SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n",	progName);	exit(1);}/* Function:  readDataFromSocket() * * Purpose:  Parse an HTTP request by reading data from a GET or POST. * */SECStatusreadDataFromSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char **fileName){	char  *post;	int    numBytes = 0;	int    newln    = 0;  /* # of consecutive newlns */	/* Read data while it comes in from the socket. */	while (PR_TRUE) {		buffer->index = 0;		newln = 0;		/* Read the buffer. */		numBytes = PR_Read(sslSocket, &buffer->data[buffer->index], 		                   buffer->remaining);		if (numBytes <= 0) {			errWarn("PR_Read");			return SECFailure;		}		buffer->dataEnd = buffer->dataStart + numBytes;		/* Parse the input, starting at the beginning of the buffer.		 * Stop when we detect two consecutive \n's (or \r\n's) 		 * as this signifies the end of the GET or POST portion.		 * The posted data follows.		 */		while (buffer->index < buffer->dataEnd && newln < 2) {			int octet = buffer->data[buffer->index++];			if (octet == '\n') {				newln++;			} else if (octet != '\r') {				newln = 0;			}		}		/* Came to the end of the buffer, or second newline.		 * If we didn't get an empty line ("\r\n\r\n"), then keep on reading.		 */		if (newln < 2) 			continue;		/* we're at the end of the HTTP request.		 * If the request is a POST, then there will be one more		 * line of data.		 * This parsing is a hack, but ok for SSL test purposes.		 */		post = PORT_Strstr(buffer->data, "POST ");		if (!post || *post != 'P') 			break;		/* It's a post, so look for the next and final CR/LF. */		/* We should parse content length here, but ... */		while (buffer->index < buffer->dataEnd && newln < 3) {			int octet = buffer->data[buffer->index++];			if (octet == '\n') {				newln++;			}		}		if (newln == 3)			break;	}	/* Have either (a) a complete get, (b) a complete post, (c) EOF */	/*  Execute a "GET " operation. */	if (buffer->index > 0 && PORT_Strncmp(buffer->data, "GET ", 4) == 0) {		int fnLength;		/* File name is the part after "GET ". */		fnLength = strcspn(buffer->data + 5, " \r\n");		*fileName = (char *)PORT_Alloc(fnLength + 1);		PORT_Strncpy(*fileName, buffer->data + 5, fnLength);		(*fileName)[fnLength] = '\0';	}	return SECSuccess;}/* Function:  authenticateSocket() * * Purpose:  Configure a socket for SSL. * * */PRFileDesc * setupSSLSocket(PRFileDesc *tcpSocket, int requestCert){	PRFileDesc *sslSocket;	SSLKEAType  certKEA;	int         certErr = 0;	SECStatus   secStatus;	/* Set the appropriate flags. */	sslSocket = SSL_ImportFD(NULL, tcpSocket);	if (sslSocket == NULL) {		errWarn("SSL_ImportFD");		goto loser;	}   	secStatus = SSL_Enable(sslSocket, SSL_SECURITY, PR_TRUE);	if (secStatus != SECSuccess) {		errWarn("SSL_Enable SSL_SECURITY");		goto loser;	}	secStatus = SSL_Enable(sslSocket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);	if (secStatus != SECSuccess) {		errWarn("SSL_Enable:SSL_HANDSHAKE_AS_SERVER");		goto loser;	}	secStatus = SSL_Enable(sslSocket, SSL_REQUEST_CERTIFICATE, 	                       (requestCert >= REQUEST_CERT_ONCE));	if (secStatus != SECSuccess) {		errWarn("SSL_Enable:SSL_REQUEST_CERTIFICATE");		goto loser;	}	secStatus = SSL_Enable(sslSocket, SSL_REQUIRE_CERTIFICATE, 	                       (requestCert == REQUIRE_CERT_ONCE));	if (secStatus != SECSuccess) {		errWarn("SSL_Enable:SSL_REQUIRE_CERTIFICATE");		goto loser;	}	/* Set the appropriate callback routines. */	secStatus = SSL_AuthCertificateHook(sslSocket, myAuthCertificate, 	                                    CERT_GetDefaultCertDB());	if (secStatus != SECSuccess) {		errWarn("SSL_AuthCertificateHook");		goto loser;	}	secStatus = SSL_BadCertHook(sslSocket, 	                            (SSLBadCertHandler)myBadCertHandler, &certErr);	if (secStatus != SECSuccess) {		errWarn("SSL_BadCertHook");		goto loser;	}	secStatus = SSL_HandshakeCallback(sslSocket,	                                 (SSLHandshakeCallback)myHandshakeCallback,									  NULL);	if (secStatus != SECSuccess) {		errWarn("SSL_HandshakeCallback");		goto loser;	}	secStatus = SSL_SetPKCS11PinArg(sslSocket, password);	if (secStatus != SECSuccess) {		errWarn("SSL_HandshakeCallback");		goto loser;	}	certKEA = NSS_FindCertKEAType(cert);	secStatus = SSL_ConfigSecureServer(sslSocket, cert, privKey, certKEA);	if (secStatus != SECSuccess) {		errWarn("SSL_ConfigSecureServer");		goto loser;	}	return sslSocket;loser:	PR_Close(tcpSocket);	return NULL;}/* Function:  authenticateSocket() * * Purpose:  Perform client authentication on the socket. * */SECStatusauthenticateSocket(PRFileDesc *sslSocket, PRBool requireCert){	CERTCertificate *cert;	SECStatus secStatus;	/* Returns NULL if client authentication is not enabled or if the	 * client had no certificate. */	cert = SSL_PeerCertificate(sslSocket);	if (cert) {		/* Client had a certificate, so authentication is through. */		CERT_DestroyCertificate(cert);		return SECSuccess;	}	/* Request client to authenticate itself. */	secStatus = SSL_Enable(sslSocket, SSL_REQUEST_CERTIFICATE, PR_TRUE);	if (secStatus != SECSuccess) {		errWarn("SSL_Enable:SSL_REQUEST_CERTIFICATE");		return SECFailure;	}	/* If desired, require client to authenticate itself.  Note	 * SSL_REQUEST_CERTIFICATE must also be on, as above.  */	secStatus = SSL_Enable(sslSocket, SSL_REQUIRE_CERTIFICATE, requireCert);	if (secStatus != SECSuccess) {		errWarn("SSL_Enable:SSL_REQUIRE_CERTIFICATE");		return SECFailure;	}	/* Having changed socket configuration parameters, redo handshake. */	secStatus = SSL_RedoHandshake(sslSocket);	if (secStatus != SECSuccess) {		errWarn("SSL_RedoHandshake");		return SECFailure;	}	/* Force the handshake to complete before moving on. */	secStatus = SSL_ForceHandshake(sslSocket);	if (secStatus != SECSuccess) {		errWarn("SSL_ForceHandshake");		return SECFailure;	}	return SECSuccess;}/* Function:  writeDataToSocket * * Purpose:  Write the client's request back to the socket.  If the client *           requested a file, dump it to the socket. * */SECStatuswriteDataToSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char *fileName){	int headerLength;	int numBytes;	char messageBuffer[120];	PRFileDesc *local_file_fd = NULL;	char header[] = "<html><body><h1>Sample SSL server</h1><br><br>";	char filehd[] = "<h2>The file you requested:</h2><br>";	char reqhd[]  = "<h2>This is your request:</h2><br>";	char link[]   = "Try getting a <a HREF=\"../testfile\">file</a><br>";	char footer[] = "<br><h2>End of request.</h2><br></body></html>";	headerLength = PORT_Strlen(defaultHeader);	/* Write a header to the socket. */	numBytes = PR_Write(sslSocket, header, PORT_Strlen(header));	if (numBytes < 0) {		errWarn("PR_Write");		goto loser;	}	if (fileName) {		PRFileInfo  info;		PRStatus    prStatus;		/* Try to open the local file named.			 * If successful, then write it to the client.		 */		prStatus = PR_GetFileInfo(fileName, &info);		if (prStatus != PR_SUCCESS ||		    info.type != PR_FILE_FILE ||		    info.size < 0) {			PORT_Free(fileName);			/* Maybe a GET not sent from client.c? */			goto writerequest;			return SECSuccess;		}		local_file_fd = PR_Open(fileName, PR_RDONLY, 0);		if (local_file_fd == NULL) {			PORT_Free(fileName);			goto writerequest;		}		/* Write a header to the socket. */		numBytes = PR_Write(sslSocket, filehd, PORT_Strlen(filehd));		if (numBytes < 0) {			errWarn("PR_Write");			goto loser;		}		/* Transmit the local file prepended by the default header		 * across the socket.		 */		numBytes = PR_TransmitFile(sslSocket, local_file_fd, 		                           defaultHeader, headerLength,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?