[pubcookie-dev] RFC: pubcookie and SSL certificate chains
Paul Fardy
paul.fardy at utoronto.ca
Wed Jul 19 09:52:42 PDT 2006
It seems it's uncommon to use chained certificates, but we at UT get
chained certificates from the Comodo Group. The Comodo Group used
chained certificates and now uses a cross-signed root certificate.
[Cross-signed root: will work most of the time, but it might not be
trusted by all of your clients, so a chained certificate is also used
that's signed by another root CA that, hopefully, those wary clients
will trust.]
I'd found that using SSL_CTX_use_certificate_chain_file() and adding
an "ssl_cert_chain_file" parameter to the config was the shortest
path to a patch. But it didn't feel like the right solution for two
reasons:
1) It completely supersedes the ssl_cert_file and there were (only a
few) sanity checks for that file. So the file has to exist or the
sanity checks need to patched and tracking references to
ssl_cert_file just seems to urge a refactoring that I was reluctant
to implement.
2) Because it supersedes the ssl_cert_file, it's not consistent with
the way Apache handles certificates. The OpenSSL docs advocate
use_certificate_chain_file(), but Apache is the de facto standard:
people like to have the Pubcookie configs match the Apache ssl.conf.
I've been patching use_certificate_file() into my pubcookie library
with each release (it's just a few lines), but it would obviously be
better if the distro had a good solution.
I'm proposing two new parameters:
ssl_cert_chain_file: <path-name>
ssl_cert_chain_compatibility: [apache|ssl-lib]
and compatibility should probably default to "apache", though
ssl_cert_chain_file is, for now, UT-only and "ssl-lib" would be
backward compatible.
Ultimately, Pubcookie needs to support certificate chains. I think
Apache-style is also necessary. The "ssl-lib" compatibility could be
dismissed as my problem.
Here's a patch for the keyclient. I'll be patching keyserver.c, too.
But I figured I see where the wind's blowing...
Note: the patch also includes a patch to the SSL error callback that
provides details that have been helpful, particularly when dealing
with chained certificates.
Thanks for your time,
Paul
-------------- next part --------------
--- keyclient.c 2006/06/13 17:13:39 1.1
+++ keyclient.c 2006/07/19 16:06:36
@@ -169,8 +169,13 @@
err = X509_STORE_CTX_get_error (ctx);
if (!ok) {
- fprintf (stderr, "verify error:num=%d:%s\n", err,
+ char subject[1024], issuer[1024];
+ fprintf (stderr, "verify error: SSL err %d: %s\n", err,
X509_verify_cert_error_string (err));
+ X509_NAME_oneline(X509_get_subject_name(err_cert), subject, sizeof subject);
+ X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, sizeof issuer);
+ fprintf (stderr, "verify error: detail: subject=%s\n", subject);
+ fprintf (stderr, "verify error: detail: issuer=%s\n", issuer);
/* we want to ignore any key usage problems but no other faults */
switch (ctx->error) {
@@ -206,6 +211,8 @@
char peer_cn[257];
const char *keyfile = NULL;
const char *certfile = NULL;
+ const char *certchainfile = NULL;
+ const char *certchaincompat = NULL;
const char *cafile = NULL;
const char *cadir = NULL;
int done = 0;
@@ -349,6 +356,12 @@
if (!certfile)
certfile =
libpbc_config_getstring (p, "ssl_cert_file", "server.pem");
+ if (!certchainfile)
+ certchainfile =
+ libpbc_config_getstring (p, "ssl_cert_chain_file", NULL);
+ if (!certchaincompat)
+ certchaincompat =
+ libpbc_config_getstring (p, "ssl_cert_chain_compatibility", "apache");
if (!cafile)
cafile = libpbc_config_getstring (p, "ssl_ca_file", NULL);
if (!cadir)
@@ -383,7 +396,44 @@
ctx = SSL_CTX_new (TLSv1_client_method ());
/* setup the correct certificate */
- if (!SSL_CTX_use_certificate_file (ctx, certfile, filetype)) {
+ if (certchainfile) {
+ if (strcmp(certchaincompat, "ssl-lib") == 0) {
+ if (!SSL_CTX_use_certificate_chain_file (ctx, certchainfile)) {
+ fprintf (stderr, "SSL_CTX_use_certificate_chain_file: %s\n", certchainfile);
+ ERR_print_errors_fp (stderr);
+ exit (1);
+ }
+ } else if (strcmp(certchaincompat, "apache") == 0) {
+ X509 *crt;
+ FILE *fp;
+
+ if (!SSL_CTX_use_certificate_file (ctx, certfile, filetype)) {
+ fprintf (stderr, "SSL_CTX_use_certificate_file:\n");
+ ERR_print_errors_fp (stderr);
+ exit (1);
+ }
+
+ fp = fopen(certchainfile, "r");
+ if (!fp) {
+ fprintf(stderr, "cannot read ssl_cert_chain_file \"%s\": %s\n", certchainfile, strerror(errno));
+ exit(1);
+ }
+
+ while (crt = PEM_read_X509(fp, NULL, NULL, NULL)) {
+ if (!SSL_CTX_add_extra_chain_cert(ctx, crt)) {
+ char subject[1024], issuer[1024];
+ fprintf (stderr, "Certificate Chain File: %s (using Apache compatibility)\n", certchainfile);
+ fprintf (stderr, "Failed to add certificate to certificate chain:\n", certchainfile);
+ ERR_print_errors_fp (stderr);
+ X509_NAME_oneline(X509_get_subject_name(crt), subject, sizeof subject);
+ X509_NAME_oneline(X509_get_issuer_name(crt), issuer, sizeof issuer);
+ fprintf (stderr, " detail: subject=%s\n", subject);
+ fprintf (stderr, " detail: issuer=%s\n", subject);
+ exit (1);
+ }
+ }
+ }
+ } else if (!SSL_CTX_use_certificate_file (ctx, certfile, filetype)) {
fprintf (stderr, "SSL_CTX_use_certificate_file:\n");
ERR_print_errors_fp (stderr);
exit (1);
More information about the pubcookie-dev
mailing list