cacert-webdb/pages/help/1.php

458 lines
13 KiB
PHP
Raw Normal View History

2004-10-26 07:50:08 +00:00
<pre> CERTIFICATE RETRIEVAL
STATUS OF THIS MEMO
This document is an Internet-Draft and is subject to all provisions of
Section 10 of RFC2026..
INTRODUCTION
The CERTIFICATE RETRIEVAL Service is a TCP transaction based query/response
server, running on port xxxxx, that provides directory service for internet
users to automate the task of retrieving certificates based on email
addresses or hostnames.
This service, together with a corresponding database of X.509 certificates
can be used to automate security in conjunction with the 802.1x protocol
for authentication and encryption, webmail services, and email in general
that employ s/mime to encrypt replies to authors could request a certificate
via the service rather then requiring the user to supply it up front, so as
long as you know the email address and they have signed up for a certificate
the message can be encrypted.
This method of distributing client certificates isn't intended for extremely
sensitive material, but merely to protect day to day emails that are currently
being sent as clear text. The security risk in this method isn't more likely
to succeed then signing an email and distributing the certificate in that
manner.
PROTOCOL
To access the CERTIFICATE RETRIEVAL service:
Connect to the service host on TCP service port xxxxx
(decimal).
Send a single "command line", ending with <CRLF> (ASCII CR and
LF).
Receive information in response to the command line. The server
closes its connection as soon as the output is finished.
Extention to Service:
This service could be extended to relay services that worked inline
with Certificate Authorities to cache responses and verify the
certificates were still valid using OCSP services. Using the relay
method it would be easier to include additional Certificate
Authorities, instead of issuing client software updates every time a
new Certificate Authority commenced operations, or alternatively
ceased to operate.
Due to political concerns more then technical issues relay services
should be run by impartial parties that don't have a vested interest
in competing with other Certificate Authorities so no user would be
disadvantaged.
SECURITY ISSUES
Spam:
Obviously this would open a potential method for spammers to validate
their spam lists, and sending encrypted spam which may bypass current
spam filters. This system to an extent mimics the PGP Key Exchange
service, unlike the PGP Key Exchange there will be no effort to allow
searching apart from exact email or hostnames. At time of writting
there are no documented attempts to exploit the PGP Key Exchange for
the purposes of spam. Certificate Authorities should offer a way for
their users to opt out of this method of distributing public
certificates.
Transfer:
Due to the nature of X.509 it would be highly improbable that the
certificates could be compromised if they passed via a compromised
relay, or as the information is passed via any communications medium.
After the certificate is received issuer, CRL and OCSP checks should
be performed by client software as per normal with any certificate
received by other methods.
SIMILAR SERVICES
LDAP:
LDAP can already be used in a method similar to described in this
document, however a simpler approach to security through an extremely
simple, efficient method of distributing without the need for bulky libs
and wrappers would help adoption and help increase security in general.
PGP Key Exchange:
Has much more extended capabilities although the concept is basically
the same, an easy method of distributing public keys.
OCSP/CRL:
Much simpler services only responding to requests about validity of
a certificate presented to them, will not respond with a copy of the
certificate.
COMMAND LINES AND REPLIES
A command line is normally a single name specification. Note that
the specification formats will evolve with time; the best way to
obtain the most recent documentation on name specifications is to
give the server a command line consisting of "?<CRLF>" (that is, a
question-mark alone as the name specification). The response from
the server will list all possible formats that can be used.
The responses are currently intended to be machine-readable; the
information is not meant to be passed back directly to a human user. The
following three examples illustrate the use of the service as of February
2004.
---------------------------------------------------------------------
Command line: ?
Response:
Please enter an email address or hostname, such as "www.cacert.org".
---------------------------------------------------------------------
Command line: myisp.com
Response:
No valid certificate available.
---------------------------------------------------------------------
Command line: www.cacert.org
Response:
-----BEGIN CERTIFICATE-----
MIIFiTCCA3GgAwIBAgICAjYwDQYJKoZIhvcNAQEEBQAweTEQMA4GA1UEChMHUm9v
dCBDQTEeMBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlD
QSBDZXJ0IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0
QGNhY2VydC5vcmcwHhcNMDMwNDAyMDAzNzU2WhcNMDUwNDAxMDAzNzU2WjCBmjEL
MAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UEBxMGU3lkbmV5MRAwDgYD
VQQKEwdDQSBDZXJ0MR4wHAYDVQQLExVTZXJ2ZXIgQWRtaW5pc3RyYXRpb24xFzAV
BgNVBAMTDnd3dy5jYWNlcnQub3JnMSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNh
Y2VydC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMWKlVe5/cfDZiPq
WZTUGvgLA4dbvj/cBJXZgkz6aIvKuBhZ+cXob/xc6tkL20NdXZIW6WIzaGk6SU0a
vu6grLlHumwuXrFGPNRb8HyRQrvWzgD73Est+CDfLo+Omq55UjDDH0TZoAMV3L0N
Gb/S7YZeYHNcUzAHcXTE1//LyS8bAgMBAAGjggF7MIIBdzAMBgNVHRMBAf8EAjAA
MCoGA1UdJQQjMCEGCCsGAQUFBwMBBglghkgBhvhCBAEGCisGAQQBgjcKAwMwCwYD
VR0PBAQDAgUgMB0GA1UdDgQWBBTN0mx8ONpAgO9SaMf5KcKmDjFgDjCBowYDVR0j
BIGbMIGYgBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9v
dCBDQTEeMBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlD
QSBDZXJ0IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0
QGNhY2VydC5vcmeCAQAwEQYJYIZIAYb4QgEBBAQDAgZAMFYGCWCGSAGG+EIBDQRJ
FkdUbyBnZXQgeW91ciBvd24gY2VydGlmaWNhdGUgZm9yIEZSRUUgaGVhZCBvdmVy
IHRvIGh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzANBgkqhkiG9w0BAQQFAAOCAgEAc7vb
l/zrCweRmHo8dQw7fpvX4KibbpZ5fXT9c1tn+oIUxV1erDI3r5YW6Cha8XIDhMxJ
tKPXdyAkrzEt3SrQrFy/KndMCjS1ypic2g/IhUjnB7FnH7Jc3RF+w3GX6OO38XtQ
ydcQk2qD125W7Kl6cgSXjauVz2AyjetHi0jA+SRcmnlIRafKLEDPsnc/1A6CFd4C
e8J+mrSA4FPOwf1ezAEJAlsBNiM2oIcfbWjrUR/dfaBrGweBQS/mgXxSXJWJnFQI
wNE47X3ibISAgT74p/zqdVoYBQEXe0LDNsmFU6eqc8OyLEKW3BIgfQxtGxKCLCsA
G/TjfjxGRhi1FlX9ZPvuWGfV0ks0gMa/VDM7V37LMhVViyTHNTmKuHsOa7UAz/5x
qJo/ruLuCfGF9Z8jfj0197J0LMQSr09YQ/JSDJE6IFE59/6ju7+Py+2NDRsiqo+/
qi/4SGbXakOXqJv92NHLqD/jdq8D8RIPggQ2RGG7aNQ5bpmnZk6KEJH9jD50LAs1
kU+KI/v8o94ZBz+MDhNgJpwT5R/Vvnri2iT9mIysfpCuZCZC6KJKN8rXT031ocmx
CJyaTBopnpnHwGu238IAMSpq9nPibhCb0OlqMVHdid9qPr8iZDWVhgmgDasigS5Y
lzsrd9lRVDVN5HITUCFG3Qr5xx7ltSouj/dkykg=
-----END CERTIFICATE-----
---------------------------------------------------------------------
EXAMPLE CODE
---------------------------------------------------------------------
/*
Copyright Jeremey Barrett 2004 for CAcert.org
You may create derivative works, as long as this copyright notice remains at the top
*/
/*
Example finger daemon that can return certificates from a database.
Currently only tested on debian stable.
use the following command to build program
gcc -o cacert-finger cacert-finger.c -I/usr/include/mysql -L/usr/lib \
-lmysqlclient -lz -DUSE_MYSQL
*/
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;errno.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/select.h&gt;
#include &lt;netinet/in.h&gt;
#ifdef USE_MYSQL
#include &lt;mysql.h&gt;
#endif
#ifdef USE_MYSQL
static MYSQL mysql_db;
#endif
#define DEFAULT_PORT 79
#define EMAIL_QUERY "select CRT from certs where `EMAIL`='%s' and \
`revoked`='0000-00-00 00:00:00'"
#define DOMAIN_QUERY "select CRT from domaincerts where \
`revoked`='0000-00-00 00:00:00' and `CN`='%s'"
#define WILD_DOMAIN_QUERY "select CRT from domaincerts where \
`revoked`='0000-00-00 00:00:00' and (`CN`='%s' OR `CN`='%s')"
void err_exit(void)
{
perror("");
exit(1);
}
#ifdef USE_MYSQL
void do_mysql(int client_fd, char *query)
{
MYSQL_RES *res;
MYSQL_ROW row;
char *cert;
if(!(mysql_real_connect(&mysql_db, "host", "username", "password",
"database", 0, "/var/run/mysqld/mysqld.sock", 0) != NULL))
{
printf(mysql_error(&mysql_db));
exit(1);
}
if(mysql_real_query(&mysql_db, query, strlen(query)))
goto _err_return;
res = mysql_store_result(&mysql_db);
if(mysql_num_rows(res) &gt; 0)
{
row = mysql_fetch_row(res);
if(!row[0])
goto _free_res_return;
cert = strstr(row[0], "-----BEGIN CERTIFICATE");
if(cert) {
char *response;
int response_len = strlen(cert)+2;
response = (char *)calloc(1, response_len+1);
if(!response)
goto _free_res_return;
memcpy(response, cert, response_len-2);
response[response_len-2] = '\r';
response[response_len-1] = '\n';
/* should be checked for errors, more writing */
write(client_fd, response, response_len);
free(response);
} }
_free_res_return:
mysql_free_result(res);
_err_return:
mysql_close(&mysql_db);
}
#endif
int read_line(int fd, char *buf, int size)
{
int n = 0;
int t = 0;
char *p;
char *q;
for(; t &lt; size; ) {
n = read(fd, buf+t, size-t);
if(n &lt; 0) {
switch(errno) {
case EINTR:
continue;
default:
return -1;
}
}
if(n == 0) {
return t;
}
if(t)
p = buf+t-1;
else
p = buf;
for(; *p && *p != '\n' && *p != '\r'; p++);
if(*p) {
*p = 0;
t = p-buf;
return t;
}
t += n;
}
return -1;
}
int handle_request(int fd)
{
char *buf;
int buf_size;
int len;
int i;
int email_query = 0;
char query[4096]; /* ugly */
char *email = NULL;
char *domain = NULL;
char *wildcard = NULL;
buf_size = 2048;
buf = (char *)calloc(1, buf_size);
if(!buf)
return -1;
if((len = read_line(fd, buf, buf_size-1)) &lt;= 0)
goto _free_return;
memset(buf+len, 0, buf_size-len);
if(strchr(buf, '@')) {
email_query = 1;
email = buf;
}
else {
char *p;
char *q;
p = strchr(buf, '.');
if(p) {
q = strchr(p+1, '.');
if(q) {
wildcard = (char *)calloc(1, strlen(p)+2);
if(wildcard) {
*wildcard = '*';
memcpy(wildcard+1, p, strlen(p));
}
}
}
domain = buf;
}
memset(query, 0, sizeof(query));
if(email_query) {
snprintf(query, sizeof(query)-2, EMAIL_QUERY, email);
}
else {
if(wildcard && strcmp(wildcard, domain))
snprintf(query, sizeof(query)-2, WILD_DOMAIN_QUERY, domain, wildcard);
else
snprintf(query, sizeof(query)-2, DOMAIN_QUERY, domain);
if(wildcard)
free(wildcard);
}
/* go and do MySQL stuff here */
#ifdef USE_MYSQL
do_mysql(fd, query);
#else
strcat(query, "\n");
write(fd, query, strlen(query));
#endif
_free_return:
free(buf);
return 0;
}
int main(int argc, char **argv)
{
struct sockaddr_in server_sock;
struct sockaddr_in client_sock;
int client_addr_size;
int server_fd = -1;
int client_fd = -1;
int pid;
/* take command line args, e.g. -p &lt;port&gt;, later */
if ((pid=fork()) &lt; 0)
{
perror ("Fork failed");
exit(errno);
}
if (pid)
{
exit(0);
}
server_fd = socket(PF_INET, SOCK_STREAM, 0);
if(server_fd &lt; 0)
err_exit();
memset(&server_sock, 0, sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = INADDR_ANY;
server_sock.sin_port = htons(DEFAULT_PORT);
if(bind(server_fd, (struct sockaddr *)&server_sock,
sizeof(struct sockaddr_in)) &lt; 0)
err_exit();
if(listen(server_fd, 64) &lt; 0)
err_exit();
setgid(65534);
setuid(65534);
for(;;) {
memset(&client_sock, 0, sizeof(client_sock));
client_addr_size = sizeof(client_sock);
client_fd = accept(server_fd,
(struct sockaddr *)&client_sock, &client_addr_size);
if(client_fd &lt; 0)
err_exit();
if(handle_request(client_fd) &lt; 0)
break;
close(client_fd);
client_fd = -1;
}
if(client_fd &gt;= 0)
close(client_fd);
close(server_fd);
exit(0);
}</pre>