Backing out bug 468087 and bug 456001

This commit is contained in:
Honza Bambas 2009-01-12 21:47:31 +01:00
parent 562d6fde05
commit f4b909ff36
4 changed files with 66 additions and 272 deletions

View File

@ -309,7 +309,6 @@ user_pref("layout.debug.enable_data_xbl", true);
user_pref("browser.EULA.override", true);
user_pref("javascript.options.jit.content", true);
user_pref("gfx.color_management.force_srgb", true);
user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
"""
@ -397,47 +396,33 @@ def fillCertificateDB(profileDir):
sslTunnelConfig.write("forward:127.0.0.1:8888\n")
sslTunnelConfig.write("listen:*:4443:pgo server certificate\n")
# Configure automatic certificate and bind custom certificates, client authentication
# Generate automatic certificate and bond custom certificates
locations = readLocations()
locations.pop(0)
for loc in locations:
if loc.scheme == "https" and "nocert" not in loc.options:
customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
for option in loc.options:
match = customCertRE.match(option)
if match:
customcert = match.group("nickname");
sslTunnelConfig.write("listen:%s:%s:4443:%s\n" %
(loc.host, loc.port, customcert))
match = clientAuthRE.match(option)
if match:
clientauth = match.group("clientauth");
sslTunnelConfig.write("clientauth:%s:%s:4443:%s\n" %
(loc.host, loc.port, clientauth))
sslTunnelConfig.write("listen:%s:%s:4443:%s\n" % (loc.host, loc.port, customcert))
break
sslTunnelConfig.close()
# Pre-create the certification database for the profile
certutil = DIST_BIN + "/certutil" + BIN_SUFFIX
pk12util = DIST_BIN + "/pk12util" + BIN_SUFFIX
status = Process(certutil, ["-N", "-d", profileDir, "-f", pwfilePath], environment()).wait()
if status != 0:
return status
# Walk the cert directory and add custom CAs and client certs
# Walk the cert directory and add custom CAs as trusted
files = os.listdir(CERTS_DIR)
for item in files:
root, ext = os.path.splitext(item)
if ext == ".ca":
Process(certutil, ["-A", "-i", os.path.join(CERTS_DIR, item),
"-d", profileDir, "-f", pwfilePath, "-n", root, "-t", "CT,,"],
environment()).wait()
if ext == ".client":
Process(pk12util, ["-i", os.path.join(CERTS_DIR, item), "-w", pwfilePath,
"-d", profileDir], environment()).wait()
Process(certutil, ["-A", "-i", os.path.join(CERTS_DIR, item), "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", "CT,,"], environment())
os.unlink(pwfilePath)
return 0

View File

@ -46,21 +46,11 @@ include $(DEPTH)/config/autoconf.mk
_PROFILE_DIR = $(DEPTH)/_profile/pgo
_CERTS_DIR = $(_PROFILE_DIR)/certs
# Following files will be added as trusted Certificate Authorities
# to the PGO profile.
# Extension of those files MUST BE '.ca'.
# Extension of files must be '.ca'
_CERT_AUTHORITIES = \
pgoca.ca \
$(NULL)
# Following files will be added as user/client certificates
# to the PGO profile to be used for client authentication.
# Extension of those files MUST BE '.client'.
_CLIENT_CERTS = \
mochitest.client \
$(NULL)
_SERV_FILES = \
pgoca.p12 \
cert8.db \
@ -70,5 +60,5 @@ _SERV_FILES = \
include $(topsrcdir)/config/rules.mk
libs:: $(_SERV_FILES) $(_CERT_AUTHORITIES) $(_CLIENT_CERTS)
libs:: $(_SERV_FILES) $(_CERT_AUTHORITIES)
$(INSTALL) $^ $(_CERTS_DIR)

View File

@ -111,8 +111,6 @@ https://sub1.test2.example.com:443 privileged
https://sub2.test1.example.com:443 privileged
https://sub2.test2.example.com:443 privileged
https://nocert.example.com:443 privileged,nocert
https://requestclientcert.example.com:443 privileged,clientauth=request
https://requireclientcert.example.com:443 privileged,clientauth=require
#
# These are subdomains of <ält.example.org>.

View File

@ -20,8 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.com>
* Honza Bambas <honzab@firemni.cz>
* Ted Mielczarek <ted.mielczarek@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -37,16 +36,6 @@
*
* ***** END LICENSE BLOCK ***** */
/*
* WARNING: DO NOT USE THIS CODE IN PRODUCTION SYSTEMS. It is highly likely to
* be plagued with the usual problems endemic to C (buffer overflows
* and the like). We don't especially care here (but would accept
* patches!) because this is only intended for use in our test
* harnesses in controlled situations where input is guaranteed not to
* be malicious.
*/
#include <assert.h>
#include <stdio.h>
#include <string>
#include <vector>
@ -66,18 +55,11 @@
using std::string;
using std::vector;
enum client_auth_option {
caNone = 0,
caRequire = 1,
caRequest = 2
};
// Structs for passing data into jobs on the thread pool
typedef struct {
PRInt32 listen_port;
string cert_nickname;
PLHashTable* host_cert_table;
PLHashTable* host_clientauth_table;
} server_info_t;
typedef struct {
@ -86,37 +68,6 @@ typedef struct {
server_info_t* server_info;
} connection_info_t;
const PRInt32 BUF_SIZE = 16384;
const PRInt32 BUF_MARGIN = 1024;
const PRInt32 BUF_TOTAL = BUF_SIZE + BUF_MARGIN;
struct relayBuffer
{
char *buffer, *bufferhead, *buffertail, *bufferend;
relayBuffer()
{
// Leave 1024 bytes more for request line manipulations
bufferhead = buffertail = buffer = new char[BUF_TOTAL];
bufferend = buffer + BUF_SIZE;
}
~relayBuffer()
{
delete [] buffer;
}
void compact() {
if (buffertail == bufferhead)
buffertail = bufferhead = buffer;
}
bool empty() { return bufferhead == buffertail; }
size_t free() { return bufferend - buffertail; }
size_t margin() { return free() + BUF_MARGIN; }
size_t present() { return buffertail - bufferhead; }
};
// A couple of stack classes for managing NSS/NSPR resources
class AutoCert {
public:
@ -160,6 +111,7 @@ private:
const PRInt32 INITIAL_THREADS = 1;
const PRInt32 MAX_THREADS = 5;
const PRInt32 DEFAULT_STACKSIZE = (512 * 1024);
const PRInt32 BUF_SIZE = 4096;
// global data
string nssconfigdir;
@ -171,19 +123,7 @@ PRCondVar* shutdown_condvar = NULL;
// Not really used, unless something fails to start
bool shutdown_server = false;
bool do_http_proxy = false;
bool any_host_spec_config = false;
PR_CALLBACK PRIntn ClientAuthValueComparator(const void *v1, const void *v2)
{
int a = *static_cast<const client_auth_option*>(v1) -
*static_cast<const client_auth_option*>(v2);
if (a == 0)
return 0;
if (a > 0)
return 1;
else // (a < 0)
return -1;
}
bool any_host_cert_mapping = false;
/*
* Signal the main thread that the application should shut down.
@ -196,18 +136,17 @@ void SignalShutdown()
}
bool ReadConnectRequest(server_info_t* server_info,
relayBuffer& buffer, PRInt32* result, string& certificate,
client_auth_option* clientauth, string& host)
char* bufferhead, char* buffertail, PRInt32* result, string* certificate)
{
if (buffer.present() < 4)
if (buffertail - bufferhead < 4)
return false;
if (strncmp(buffer.buffertail-4, "\r\n\r\n", 4))
if (strncmp(buffertail-4, "\r\n\r\n", 4))
return false;
*result = 400;
char* token;
token = strtok(buffer.bufferhead, " ");
token = strtok(bufferhead, " ");
if (!token)
return true;
if (strcmp(token, "CONNECT"))
@ -216,16 +155,7 @@ bool ReadConnectRequest(server_info_t* server_info,
token = strtok(NULL, " ");
void* c = PL_HashTableLookup(server_info->host_cert_table, token);
if (c)
certificate = static_cast<char*>(c);
host = "https://";
host += token;
c = PL_HashTableLookup(server_info->host_clientauth_table, token);
if (c)
*clientauth = *static_cast<client_auth_option*>(c);
else
*clientauth = caNone;
*certificate = (char*)c;
token = strtok(NULL, "/");
if (strcmp(token, "HTTP"))
@ -235,7 +165,7 @@ bool ReadConnectRequest(server_info_t* server_info,
return true;
}
bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, string &certificate, client_auth_option clientAuth)
bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, string &certificate)
{
const char* certnick = certificate.empty() ?
si->cert_nickname.c_str() : certificate.c_str();
@ -269,57 +199,11 @@ bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, string &cer
SSL_OptionSet(ssl_socket, SSL_SECURITY, PR_TRUE);
SSL_OptionSet(ssl_socket, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE);
SSL_OptionSet(ssl_socket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
if (clientAuth != caNone)
{
SSL_OptionSet(ssl_socket, SSL_REQUEST_CERTIFICATE, PR_TRUE);
SSL_OptionSet(ssl_socket, SSL_REQUIRE_CERTIFICATE, clientAuth == caRequire);
}
SSL_ResetHandshake(ssl_socket, PR_TRUE);
return true;
}
/**
* This function prefixes Request-URI path with a full scheme-host-port
* string.
*/
bool AdjustRequestURI(relayBuffer& buffer, string *host)
{
assert(buffer.margin());
// Cannot use strnchr so add a null char at the end. There is always some space left
// because we preserve a margin.
buffer.buffertail[1] = '\0';
char *token, *path;
path = strchr(buffer.bufferhead, ' ') + 1;
if (!path)
return false;
// If the path doesn't start with a slash don't change it, it is probably '*' or a full
// path already. Return true, we are done with this request adjustment.
if (*path != '/')
return true;
token = strchr(path, ' ') + 1;
if (!token)
return false;
if (strncmp(token, "HTTP/", 5))
return false;
size_t hostlength = host->length();
assert(hostlength <= buffer.margin());
memmove(path + hostlength, path, buffer.buffertail - path);
memcpy(path, host->c_str(), hostlength);
buffer.buffertail += hostlength;
return true;
}
bool ConnectSocket(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
{
PRStatus stat = PR_Connect(fd, addr, timeout);
@ -351,20 +235,47 @@ void HandleConnection(void* data)
bool client_error = false;
bool connect_accepted = !do_http_proxy;
bool ssl_updated = !do_http_proxy;
bool expect_request_start = do_http_proxy;
string certificateToUse;
client_auth_option clientAuth;
string fullHost;
if (other_sock)
{
PRInt32 numberOfSockets = 1;
relayBuffer buffers[2];
struct relayBuffer
{
char *buffer, *bufferhead, *buffertail, *bufferend;
relayBuffer()
{
bufferhead = buffertail = buffer = new char[BUF_SIZE];
bufferend = buffer + BUF_SIZE;
}
~relayBuffer()
{
delete [] buffer;
}
bool empty()
{
return bufferhead == buffertail;
}
PRInt32 free()
{
return bufferend - buffertail;
}
PRInt32 present()
{
return buffertail - bufferhead;
}
void compact()
{
if (buffertail == bufferhead)
buffertail = bufferhead = buffer;
}
} buffers[2];
if (!do_http_proxy)
{
if (!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, caNone))
if (!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse))
client_error = true;
else if (!ConnectSocket(other_sock, &remote_addr, connect_timeout))
client_error = true;
@ -428,8 +339,8 @@ void HandleConnection(void* data)
// We have to accept and handle the initial CONNECT request here
PRInt32 response;
if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s],
&response, certificateToUse, &clientAuth, fullHost))
if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s].bufferhead, buffers[s].buffertail,
&response, &certificateToUse))
{
// Clean the request as it would be read
buffers[s].bufferhead = buffers[s].buffertail = buffers[s].buffer;
@ -462,12 +373,7 @@ void HandleConnection(void* data)
in_flags &= ~PR_POLL_READ;
if (ssl_updated)
{
if (s == 0 && expect_request_start)
expect_request_start = !AdjustRequestURI(buffers[s], &fullHost);
in_flags2 |= PR_POLL_WRITE;
}
}
} // PR_POLL_READ handling
@ -492,7 +398,7 @@ void HandleConnection(void* data)
{
// Proxy response has just been writen, update to ssl
ssl_updated = true;
if (!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, clientAuth))
if (!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse))
{
client_error = true;
break;
@ -622,10 +528,10 @@ int processConfigLine(char* configLine)
fprintf(stderr, "Invalid remote IP address: %s\n", ipstring);
return 1;
}
char* serverportstring = strtok(NULL, ":");
int port = atoi(serverportstring);
char* portstring = strtok(NULL, ":");
int port = atoi(portstring);
if (port <= 0) {
fprintf(stderr, "Invalid remote port: %s\n", serverportstring);
fprintf(stderr, "Invalid remote port: %s\n", portstring);
return 1;
}
remote_addr.inet.port = PR_htons(port);
@ -640,16 +546,16 @@ int processConfigLine(char* configLine)
char* hostportstring = NULL;
if (strcmp(hostname, "*"))
{
any_host_spec_config = true;
any_host_cert_mapping = true;
hostportstring = strtok(NULL, ":");
}
char* serverportstring = strtok(NULL, ":");
char* portstring = strtok(NULL, ":");
char* certnick = strtok(NULL, ":");
int port = atoi(serverportstring);
int port = atoi(portstring);
if (port <= 0) {
fprintf(stderr, "Invalid port specified: %s\n", serverportstring);
fprintf(stderr, "Invalid port specified: %s\n", portstring);
return 1;
}
@ -663,11 +569,7 @@ int processConfigLine(char* configLine)
strcat(hostname_copy, hostportstring);
strcpy(certnick_copy, certnick);
PLHashEntry* entry = PL_HashTableAdd(existingServer->host_cert_table, hostname_copy, certnick_copy);
if (!entry) {
fprintf(stderr, "Out of memory");
return 1;
}
PL_HashTableAdd(existingServer->host_cert_table, hostname_copy, certnick_copy);
}
else
{
@ -680,78 +582,12 @@ int processConfigLine(char* configLine)
fprintf(stderr, "Internal, could not create hash table\n");
return 1;
}
server.host_clientauth_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, ClientAuthValueComparator, NULL, NULL);
if (!server.host_clientauth_table)
{
fprintf(stderr, "Internal, could not create hash table\n");
return 1;
}
servers.push_back(server);
}
return 0;
}
if (!strcmp(keyword, "clientauth"))
{
char* hostname = strtok(NULL, ":");
char* hostportstring = strtok(NULL, ":");
char* serverportstring = strtok(NULL, ":");
int port = atoi(serverportstring);
if (port <= 0) {
fprintf(stderr, "Invalid port specified: %s\n", serverportstring);
return 1;
}
if (server_info_t* existingServer = findServerInfo(port))
{
char* authoptionstring = strtok(NULL, ":");
client_auth_option* authoption = new client_auth_option;
if (!authoption) {
fprintf(stderr, "Out of memory");
return 1;
}
if (!strcmp(authoptionstring, "require"))
*authoption = caRequire;
else if (!strcmp(authoptionstring, "request"))
*authoption = caRequest;
else if (!strcmp(authoptionstring, "none"))
*authoption = caNone;
else
{
fprintf(stderr, "Incorrect client auth option modifier for host '%s'", hostname);
return 1;
}
any_host_spec_config = true;
char *hostname_copy = new char[strlen(hostname)+strlen(hostportstring)+2];
if (!hostname_copy) {
fprintf(stderr, "Out of memory");
return 1;
}
strcpy(hostname_copy, hostname);
strcat(hostname_copy, ":");
strcat(hostname_copy, hostportstring);
PLHashEntry* entry = PL_HashTableAdd(existingServer->host_clientauth_table, hostname_copy, authoption);
if (!entry) {
fprintf(stderr, "Out of memory");
return 1;
}
}
else
{
fprintf(stderr, "Server on port %d for client authentication option is not defined, use 'listen' option first", port);
return 1;
}
return 0;
}
// Configure the NSS certificate database directory
if (!strcmp(keyword, "certdbdir"))
{
@ -797,28 +633,21 @@ int parseConfigFile(const char* filePath)
return 1;
}
if (any_host_spec_config && !do_http_proxy)
if (any_host_cert_mapping && !do_http_proxy)
{
printf("Warning: any host-specific configurations are ignored, add httpproxy:1 to allow them\n");
printf("Warning: any host-specific certificate configurations are ignored, add httpproxy:1 to allow them\n");
}
return 0;
}
PRIntn freeHostCertHashItems(PLHashEntry *he, PRIntn i, void *arg)
PRIntn freeHashItems(PLHashEntry *he, PRIntn i, void *arg)
{
delete [] (char*)he->key;
delete [] (char*)he->value;
return HT_ENUMERATE_REMOVE;
}
PRIntn freeClientAuthHashItems(PLHashEntry *he, PRIntn i, void *arg)
{
delete [] (char*)he->key;
delete (client_auth_option*)he->value;
return HT_ENUMERATE_REMOVE;
}
int main(int argc, char** argv)
{
char* configFilePath;
@ -845,15 +674,9 @@ int main(int argc, char** argv)
" listen:*:5678:server cert 2\n\n"
" # Accept connections on port 4443 and authenticate using\n"
" # 'a different cert' when target host is 'my.host.name:443'.\n"
" # This only works in httpproxy mode and has higher priority\n"
" # than the previous option.\n"
" listen:my.host.name:443:4443:a different cert\n\n"
" # To make a specific host require or just request a client certificate\n"
" # to authenticate use following options. This can only be used\n"
" # in httpproxy mode and after the 'listen' option has been specified.\n"
" # You also have to specify the tunnel listen port.\n"
" clientauth:requesting-client-cert.host.com:443:4443:request\n"
" clientauth:requiring-client-cert.host.com:443:4443:require\n",
" # This works only in httpproxy mode and has higher priority\n"
" # then the previews option.\n"
" listen:my.host.name:443:4443:a different cert\n",
configFilePath);
return 1;
}
@ -941,10 +764,8 @@ int main(int argc, char** argv)
for (vector<server_info_t>::iterator it = servers.begin();
it != servers.end(); it++)
{
PL_HashTableEnumerateEntries(it->host_cert_table, freeHostCertHashItems, NULL);
PL_HashTableEnumerateEntries(it->host_clientauth_table, freeClientAuthHashItems, NULL);
PL_HashTableEnumerateEntries(it->host_cert_table, freeHashItems, NULL);
PL_HashTableDestroy(it->host_cert_table);
PL_HashTableDestroy(it->host_clientauth_table);
}
PR_Cleanup();