Add support for chained SSL certificates.
git-svn-id: https://shellinabox.googlecode.com/svn/trunk@90 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
parent
2f6b0934ee
commit
1ea698ad72
6 changed files with 301 additions and 194 deletions
2
config.h
2
config.h
|
@ -95,7 +95,7 @@
|
|||
#define STDC_HEADERS 1
|
||||
|
||||
/* Most recent revision number in the version control system */
|
||||
#define VCS_REVISION "89"
|
||||
#define VCS_REVISION "90"
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.5"
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -2055,7 +2055,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
|
|||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
VCS_REVISION=89
|
||||
VCS_REVISION=90
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
|
|
@ -2,7 +2,7 @@ AC_PREREQ(2.57)
|
|||
|
||||
dnl This is the one location where the authoritative version number is stored
|
||||
AC_INIT(shellinabox, 2.5, markus@shellinabox.com)
|
||||
VCS_REVISION=89
|
||||
VCS_REVISION=90
|
||||
AC_SUBST(VCS_REVISION)
|
||||
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
|
||||
[Most recent revision number in the version control system])
|
||||
|
|
420
libhttp/ssl.c
420
libhttp/ssl.c
|
@ -48,10 +48,13 @@
|
|||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libhttp/ssl.h"
|
||||
|
@ -116,6 +119,8 @@ int (*SSL_set_ex_data)(SSL *, int, void *);
|
|||
int (*SSL_shutdown)(SSL *);
|
||||
int (*SSL_write)(SSL *, const void *, int);
|
||||
SSL_METHOD * (*SSLv23_server_method)(void);
|
||||
X509 * (*d2i_X509)(X509 **px, const unsigned char **in, int len);
|
||||
void (*X509_free)(X509 *a);
|
||||
#endif
|
||||
|
||||
static void sslDestroyCachedContext(void *ssl_, char *context_) {
|
||||
|
@ -235,7 +240,9 @@ static void loadSSL(void) {
|
|||
{ { &SSL_set_ex_data }, "SSL_set_ex_data" },
|
||||
{ { &SSL_shutdown }, "SSL_shutdown" },
|
||||
{ { &SSL_write }, "SSL_write" },
|
||||
{ { &SSLv23_server_method }, "SSLv23_server_method" }
|
||||
{ { &SSLv23_server_method }, "SSLv23_server_method" },
|
||||
{ { &d2i_X509 }, "d2i_X509" },
|
||||
{ { &X509_free }, "X509_free" }
|
||||
};
|
||||
for (int i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
|
||||
if (!(*symbols[i].var = loadSymbol("libssl.so", symbols[i].fn))) {
|
||||
|
@ -301,146 +308,7 @@ static void sslGenerateCertificate(const char *certificate,
|
|||
}
|
||||
free(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TLSEXT
|
||||
static int sslSNICallback(SSL *sslHndl, int *al, struct SSLSupport *ssl) {
|
||||
check(!ERR_peek_error());
|
||||
const char *name = SSL_get_servername(sslHndl,
|
||||
TLSEXT_NAMETYPE_host_name);
|
||||
if (name == NULL || !*name) {
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
struct HttpConnection *http =
|
||||
(struct HttpConnection *)SSL_get_app_data(sslHndl);
|
||||
debug("Received SNI callback for virtual host \"%s\" from \"%s:%d\"",
|
||||
name, httpGetPeerName(http), httpGetPort(http));
|
||||
char *serverName;
|
||||
check(serverName = malloc(strlen(name)+2));
|
||||
serverName[0] = '-';
|
||||
for (int i = 0;;) {
|
||||
char ch = name[i];
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
ch |= 0x20;
|
||||
} else if (ch != '\000' && ch != '.' && ch != '-' &&
|
||||
(ch < '0' ||(ch > '9' && ch < 'A') || (ch > 'Z' &&
|
||||
ch < 'a')|| ch > 'z')) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
serverName[++i] = ch;
|
||||
if (!ch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*serverName) {
|
||||
free(serverName);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
SSL_CTX *context = (SSL_CTX *)getFromTrie(&ssl->sniContexts,
|
||||
serverName+1,
|
||||
NULL);
|
||||
if (context == NULL) {
|
||||
check(context = SSL_CTX_new(SSLv23_server_method()));
|
||||
check(ssl->sniCertificatePattern);
|
||||
char *certificate = stringPrintfUnchecked(NULL,
|
||||
ssl->sniCertificatePattern,
|
||||
serverName);
|
||||
if (!SSL_CTX_use_certificate_file(context, certificate, SSL_FILETYPE_PEM)||
|
||||
!SSL_CTX_use_PrivateKey_file(context, certificate, SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_check_private_key(context)) {
|
||||
if (ssl->generateMissing) {
|
||||
sslGenerateCertificate(certificate, serverName + 1);
|
||||
if (!SSL_CTX_use_certificate_file(context, certificate,
|
||||
SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_use_PrivateKey_file(context, certificate,
|
||||
SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_check_private_key(context)) {
|
||||
goto certificate_missing;
|
||||
}
|
||||
} else {
|
||||
certificate_missing:
|
||||
warn("Could not find matching certificate \"%s\" for \"%s\"",
|
||||
certificate, serverName + 1);
|
||||
SSL_CTX_free(context);
|
||||
context = ssl->sslContext;
|
||||
}
|
||||
}
|
||||
ERR_clear_error();
|
||||
free(certificate);
|
||||
addToTrie(&ssl->sniContexts, serverName+1, (char *)context);
|
||||
}
|
||||
free(serverName);
|
||||
if (context != ssl->sslContext) {
|
||||
check(SSL_set_SSL_CTX(sslHndl, context) > 0);
|
||||
}
|
||||
check(!ERR_peek_error());
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
void sslSetCertificate(struct SSLSupport *ssl, const char *filename,
|
||||
int autoGenerateMissing) {
|
||||
#if defined(HAVE_OPENSSL)
|
||||
check(serverSupportsSSL());
|
||||
|
||||
char *defaultCertificate;
|
||||
check(defaultCertificate = strdup(filename));
|
||||
char *ptr = strchr(defaultCertificate, '%');
|
||||
if (ptr != NULL) {
|
||||
check(!strchr(ptr+1, '%'));
|
||||
check(ptr[1] == 's');
|
||||
memmove(ptr, ptr + 2, strlen(ptr)-1);
|
||||
}
|
||||
|
||||
check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method()));
|
||||
if (autoGenerateMissing) {
|
||||
if (!SSL_CTX_use_certificate_file(ssl->sslContext, defaultCertificate,
|
||||
SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_use_PrivateKey_file(ssl->sslContext, defaultCertificate,
|
||||
SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_check_private_key(ssl->sslContext)) {
|
||||
char hostname[256], buf[4096];
|
||||
check(!gethostname(hostname, sizeof(hostname)));
|
||||
struct hostent he_buf, *he;
|
||||
int h_err;
|
||||
if (gethostbyname_r(hostname, &he_buf, buf, sizeof(buf),
|
||||
&he, &h_err)) {
|
||||
sslGenerateCertificate(defaultCertificate, hostname);
|
||||
} else {
|
||||
sslGenerateCertificate(defaultCertificate, he->h_name);
|
||||
}
|
||||
} else {
|
||||
goto valid_certificate;
|
||||
}
|
||||
}
|
||||
if (!SSL_CTX_use_certificate_file(ssl->sslContext, defaultCertificate,
|
||||
SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_use_PrivateKey_file(ssl->sslContext, defaultCertificate,
|
||||
SSL_FILETYPE_PEM) ||
|
||||
!SSL_CTX_check_private_key(ssl->sslContext)) {
|
||||
fatal("Cannot read valid certificate from \"%s\". "
|
||||
"Check file permissions and file format.", defaultCertificate);
|
||||
}
|
||||
valid_certificate:
|
||||
free(defaultCertificate);
|
||||
|
||||
#ifdef HAVE_TLSEXT
|
||||
if (ptr != NULL) {
|
||||
check(ssl->sniCertificatePattern = strdup(filename));
|
||||
check(SSL_CTX_set_tlsext_servername_callback(ssl->sslContext,
|
||||
sslSNICallback));
|
||||
check(SSL_CTX_set_tlsext_servername_arg(ssl->sslContext, ssl));
|
||||
}
|
||||
#endif
|
||||
dcheck(!ERR_peek_error());
|
||||
ERR_clear_error();
|
||||
|
||||
ssl->generateMissing = autoGenerateMissing;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
static const unsigned char *sslSecureReadASCIIFileToMem(int fd) {
|
||||
size_t inc = 16384;
|
||||
size_t bufSize = inc;
|
||||
|
@ -476,8 +344,12 @@ static const unsigned char *sslSecureReadASCIIFileToMem(int fd) {
|
|||
|
||||
static const unsigned char *sslPEMtoASN1(const unsigned char *pem,
|
||||
const char *record,
|
||||
long *size) {
|
||||
*size = -1;
|
||||
long *size,
|
||||
const unsigned char **eor) {
|
||||
if (eor) {
|
||||
*eor = NULL;
|
||||
}
|
||||
*size = 0;
|
||||
char *marker;
|
||||
check((marker = stringPrintf(NULL, "-----BEGIN %s-----",record))!=NULL);
|
||||
unsigned char *ptr = (unsigned char *)strstr((char *)pem, marker);
|
||||
|
@ -490,6 +362,9 @@ static const unsigned char *sslPEMtoASN1(const unsigned char *pem,
|
|||
*marker = '\000';
|
||||
check((marker = stringPrintf(marker, "-----END %s-----",record))!=NULL);
|
||||
unsigned char *end = (unsigned char *)strstr((char *)ptr, marker);
|
||||
if (eor) {
|
||||
*eor = end + strlen(marker);
|
||||
}
|
||||
free(marker);
|
||||
if (!end) {
|
||||
return NULL;
|
||||
|
@ -539,58 +414,259 @@ static const unsigned char *sslPEMtoASN1(const unsigned char *pem,
|
|||
*size = out - ret;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void sslSetCertificateFd(struct SSLSupport *ssl, int fd) {
|
||||
#ifdef HAVE_OPENSSL
|
||||
static int sslSetCertificateFromFd(SSL_CTX *context, int fd) {
|
||||
int rc = 0;
|
||||
check(serverSupportsSSL());
|
||||
check(fd >= 0);
|
||||
check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method()));
|
||||
const unsigned char *data = sslSecureReadASCIIFileToMem(fd);
|
||||
check(!NOINTR(close(fd)));
|
||||
long dataSize = (long)strlen((const char *)data);
|
||||
long certSize, rsaSize, dsaSize, ecSize;
|
||||
const unsigned char *cert = sslPEMtoASN1(data, "CERTIFICATE", &certSize);
|
||||
const unsigned char *rsa = sslPEMtoASN1(data, "RSA PRIVATE KEY", &rsaSize);
|
||||
const unsigned char *dsa = sslPEMtoASN1(data, "DSA PRIVATE KEY", &dsaSize);
|
||||
const unsigned char *ec = sslPEMtoASN1(data, "EC PRIVATE KEY", &ecSize);
|
||||
if (!certSize || !(rsaSize > 0 || dsaSize > 0
|
||||
const unsigned char *record;
|
||||
const unsigned char *cert = sslPEMtoASN1(data, "CERTIFICATE", &certSize,
|
||||
&record);
|
||||
const unsigned char *rsa = sslPEMtoASN1(data, "RSA PRIVATE KEY",&rsaSize,
|
||||
NULL);
|
||||
const unsigned char *dsa = sslPEMtoASN1(data, "DSA PRIVATE KEY",&dsaSize,
|
||||
NULL);
|
||||
const unsigned char *ec = sslPEMtoASN1(data, "EC PRIVATE KEY", &ecSize,
|
||||
NULL);
|
||||
if (certSize && (rsaSize || dsaSize
|
||||
#ifdef EVP_PKEY_EC
|
||||
|| ecSize > 0
|
||||
|| ecSize
|
||||
#endif
|
||||
) ||
|
||||
!SSL_CTX_use_certificate_ASN1(ssl->sslContext, certSize, cert) ||
|
||||
(rsaSize > 0 &&
|
||||
!SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ssl->sslContext, rsa,
|
||||
rsaSize)) ||
|
||||
(dsaSize > 0 &&
|
||||
!SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_DSA, ssl->sslContext, dsa,
|
||||
dsaSize)) ||
|
||||
) &&
|
||||
SSL_CTX_use_certificate_ASN1(context, certSize, cert) &&
|
||||
(!rsaSize ||
|
||||
SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, context, rsa, rsaSize)) &&
|
||||
(!dsaSize ||
|
||||
SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_DSA, context, dsa, dsaSize))
|
||||
#ifdef EVP_PKEY_EC
|
||||
(ecSize > 0 &&
|
||||
!SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, ssl->sslContext, ec,
|
||||
ecSize)) ||
|
||||
&&
|
||||
(!ecSize ||
|
||||
SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, context, ec, ecSize))
|
||||
#endif
|
||||
!SSL_CTX_check_private_key(ssl->sslContext)) {
|
||||
fatal("Cannot read valid certificate from fd %d. Check file format.", fd);
|
||||
) {
|
||||
memset((char *)cert, 0, certSize);
|
||||
free((char *)cert);
|
||||
while (record) {
|
||||
cert = sslPEMtoASN1(record, "CERTIFICATE", &certSize,
|
||||
&record);
|
||||
if (cert) {
|
||||
X509 *x509;
|
||||
const unsigned char *c = cert;
|
||||
check(x509 = d2i_X509(NULL, &c, certSize));
|
||||
memset((char *)cert, 0, certSize);
|
||||
free((char *)cert);
|
||||
if (!SSL_CTX_add_extra_chain_cert(context, x509)) {
|
||||
X509_free(x509);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!record && SSL_CTX_check_private_key(context)) {
|
||||
rc = 1;
|
||||
}
|
||||
dcheck(!ERR_peek_error());
|
||||
ERR_clear_error();
|
||||
memset((char *)data, 0, dataSize);
|
||||
free((char *)data);
|
||||
} else {
|
||||
memset((char *)cert, 0, certSize);
|
||||
free((char *)cert);
|
||||
if (rsaSize > 0) {
|
||||
}
|
||||
memset((char *)data, 0, dataSize);
|
||||
free((char *)data);
|
||||
memset((char *)rsa, 0, rsaSize);
|
||||
free((char *)rsa);
|
||||
}
|
||||
if (dsaSize > 0) {
|
||||
memset((char *)dsa, 0, dsaSize);
|
||||
free((char *)dsa);
|
||||
}
|
||||
if (ecSize > 0) {
|
||||
memset((char *)ec, 0, ecSize);
|
||||
free((char *)ec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sslSetCertificateFromFile(SSL_CTX *context,
|
||||
const char *filename) {
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
int rc = sslSetCertificateFromFd(context, fd);
|
||||
NOINTR(close(fd));
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TLSEXT
|
||||
static int sslSNICallback(SSL *sslHndl, int *al, struct SSLSupport *ssl) {
|
||||
check(!ERR_peek_error());
|
||||
const char *name = SSL_get_servername(sslHndl,
|
||||
TLSEXT_NAMETYPE_host_name);
|
||||
if (name == NULL || !*name) {
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
struct HttpConnection *http =
|
||||
(struct HttpConnection *)SSL_get_app_data(sslHndl);
|
||||
debug("Received SNI callback for virtual host \"%s\" from \"%s:%d\"",
|
||||
name, httpGetPeerName(http), httpGetPort(http));
|
||||
char *serverName;
|
||||
check(serverName = malloc(strlen(name)+2));
|
||||
serverName[0] = '-';
|
||||
for (int i = 0;;) {
|
||||
char ch = name[i];
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
ch |= 0x20;
|
||||
} else if (ch != '\000' && ch != '.' && ch != '-' &&
|
||||
(ch < '0' ||(ch > '9' && ch < 'A') || (ch > 'Z' &&
|
||||
ch < 'a')|| ch > 'z')) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
serverName[++i] = ch;
|
||||
if (!ch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*serverName) {
|
||||
free(serverName);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
SSL_CTX *context = (SSL_CTX *)getFromTrie(&ssl->sniContexts,
|
||||
serverName+1,
|
||||
NULL);
|
||||
if (context == NULL) {
|
||||
check(context = SSL_CTX_new(SSLv23_server_method()));
|
||||
check(ssl->sniCertificatePattern);
|
||||
char *certificate = stringPrintfUnchecked(NULL,
|
||||
ssl->sniCertificatePattern,
|
||||
serverName);
|
||||
if (sslSetCertificateFromFile(context, certificate) < 0) {
|
||||
if (ssl->generateMissing) {
|
||||
sslGenerateCertificate(certificate, serverName + 1);
|
||||
|
||||
// No need to check the certificate. If we fail to set it, we will use
|
||||
// the default certificate, instead.
|
||||
sslSetCertificateFromFile(context, certificate);
|
||||
} else {
|
||||
warn("Could not find matching certificate \"%s\" for \"%s\"",
|
||||
certificate, serverName + 1);
|
||||
SSL_CTX_free(context);
|
||||
context = ssl->sslContext;
|
||||
}
|
||||
}
|
||||
ERR_clear_error();
|
||||
free(certificate);
|
||||
addToTrie(&ssl->sniContexts, serverName+1, (char *)context);
|
||||
}
|
||||
free(serverName);
|
||||
if (context != ssl->sslContext) {
|
||||
check(SSL_set_SSL_CTX(sslHndl, context) > 0);
|
||||
}
|
||||
check(!ERR_peek_error());
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
void sslSetCertificate(struct SSLSupport *ssl, const char *filename,
|
||||
int autoGenerateMissing) {
|
||||
#if defined(HAVE_OPENSSL)
|
||||
check(serverSupportsSSL());
|
||||
|
||||
char *defaultCertificate;
|
||||
check(defaultCertificate = strdup(filename));
|
||||
char *ptr = strchr(defaultCertificate, '%');
|
||||
if (ptr != NULL) {
|
||||
check(!strchr(ptr+1, '%'));
|
||||
check(ptr[1] == 's');
|
||||
memmove(ptr, ptr + 2, strlen(ptr)-1);
|
||||
}
|
||||
|
||||
// Try to set the default certificate. If necessary, (re-)generate it.
|
||||
check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method()));
|
||||
if (autoGenerateMissing) {
|
||||
if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) {
|
||||
char hostname[256], buf[4096];
|
||||
check(!gethostname(hostname, sizeof(hostname)));
|
||||
struct hostent he_buf, *he;
|
||||
int h_err;
|
||||
if (gethostbyname_r(hostname, &he_buf, buf, sizeof(buf),
|
||||
&he, &h_err)) {
|
||||
sslGenerateCertificate(defaultCertificate, hostname);
|
||||
} else {
|
||||
sslGenerateCertificate(defaultCertificate, he->h_name);
|
||||
}
|
||||
} else {
|
||||
goto valid_certificate;
|
||||
}
|
||||
}
|
||||
if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) {
|
||||
fatal("Cannot read valid certificate from \"%s\". "
|
||||
"Check file permissions and file format.", defaultCertificate);
|
||||
}
|
||||
valid_certificate:
|
||||
free(defaultCertificate);
|
||||
|
||||
// Enable SNI support so that we can set a different certificate, if the
|
||||
// client asked for it.
|
||||
#ifdef HAVE_TLSEXT
|
||||
if (ptr != NULL) {
|
||||
check(ssl->sniCertificatePattern = strdup(filename));
|
||||
check(SSL_CTX_set_tlsext_servername_callback(ssl->sslContext,
|
||||
sslSNICallback));
|
||||
check(SSL_CTX_set_tlsext_servername_arg(ssl->sslContext, ssl));
|
||||
}
|
||||
#endif
|
||||
dcheck(!ERR_peek_error());
|
||||
ERR_clear_error();
|
||||
|
||||
ssl->generateMissing = autoGenerateMissing;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert the file descriptor to a human-readable format. Attempts to
|
||||
// retrieve the original file name where possible.
|
||||
#ifdef HAVE_OPENSSL
|
||||
static char *sslFdToFilename(int fd) {
|
||||
char *proc, *buf;
|
||||
int len = 128;
|
||||
check(proc = stringPrintf(NULL, "/proc/self/fd/%d", fd));
|
||||
check(buf = malloc(len));
|
||||
for (;;) {
|
||||
ssize_t i;
|
||||
if ((i = readlink(proc, buf + 1, len-3)) < 0) {
|
||||
free(proc);
|
||||
free(buf);
|
||||
check(buf = stringPrintf(NULL, "fd %d", fd));
|
||||
return buf;
|
||||
} else if (i >= len-3) {
|
||||
len += 512;
|
||||
check(buf = realloc(buf, len));
|
||||
} else {
|
||||
free(proc);
|
||||
check(i >= 0 && i < len);
|
||||
buf[i+1] = '\000';
|
||||
struct stat sb;
|
||||
if (!stat(buf + 1, &sb) && S_ISREG(sb.st_mode)) {
|
||||
*buf = '"';
|
||||
buf[i + 1] = '"';
|
||||
buf[i + 2] = '\000';
|
||||
return buf;
|
||||
} else {
|
||||
free(buf);
|
||||
check(buf = stringPrintf(NULL, "fd %d", fd));
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void sslSetCertificateFd(struct SSLSupport *ssl, int fd) {
|
||||
#ifdef HAVE_OPENSSL
|
||||
check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method()));
|
||||
if (!sslSetCertificateFromFd(ssl->sslContext, fd)) {
|
||||
fatal("Cannot read valid certificate from %s. Check file format.",
|
||||
sslFdToFilename(fd));
|
||||
}
|
||||
ssl->generateMissing = 0;
|
||||
#endif
|
||||
|
|
|
@ -108,6 +108,8 @@ extern int (*x_SSL_set_ex_data)(SSL *, int, void *);
|
|||
extern int (*x_SSL_shutdown)(SSL *);
|
||||
extern int (*x_SSL_write)(SSL *, const void *, int);
|
||||
extern SSL_METHOD *(*x_SSLv23_server_method)(void);
|
||||
extern X509 * (*x_d2i_X509)(X509 **px, const unsigned char **in, int len);
|
||||
extern void (*x_X509_free)(X509 *a);
|
||||
|
||||
#define BIO_ctrl x_BIO_ctrl
|
||||
#define BIO_f_buffer x_BIO_f_buffer
|
||||
|
@ -146,6 +148,8 @@ extern SSL_METHOD *(*x_SSLv23_server_method)(void);
|
|||
#define SSL_shutdown x_SSL_shutdown
|
||||
#define SSL_write x_SSL_write
|
||||
#define SSLv23_server_method x_SSLv23_server_method
|
||||
#define d2i_X509 x_d2i_X509
|
||||
#define X509_free x_X509_free
|
||||
|
||||
#undef BIO_set_buffer_read_data
|
||||
#undef SSL_CTX_set_tlsext_servername_arg
|
||||
|
|
27
make-chained-cert.sh
Executable file
27
make-chained-cert.sh
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
tmp=/tmp/make-chained-cert.$$
|
||||
trap 'echo; tput bel; echo FAILURE; rm -rf "${tmp}"; exit 1' EXIT INT TERM QUIT
|
||||
mkdir -p "${tmp}/demoCA/newcerts"
|
||||
printf '%08x' $$ >"${tmp}/demoCA/serial"
|
||||
touch "${tmp}/demoCA/index.txt"
|
||||
cd "${tmp}"
|
||||
|
||||
openssl req -nodes -new -x509 -keyout "${tmp}/ca-key.pem" \
|
||||
-out "${tmp}/ca-cert.pem" -days 7300 \
|
||||
-subj "/CN=Demo CA/" 2>/dev/null
|
||||
|
||||
openssl x509 -in "${tmp}/ca-cert.pem" -out "${tmp}/ca-cert.crt" 2>/dev/null
|
||||
|
||||
openssl req -nodes -new -keyout /dev/stdout \
|
||||
-out "${tmp}/ssl-req.pem" -days 7300 -subj "/CN=$(hostname -f)/" \
|
||||
2>/dev/null | cat
|
||||
|
||||
openssl ca -batch -keyfile "${tmp}/ca-key.pem" -cert "${tmp}/ca-cert.crt" \
|
||||
-notext -policy policy_anything -out /dev/stdout \
|
||||
-infiles "${tmp}/ssl-req.pem" 2>/dev/null | cat
|
||||
cat "${tmp}/ca-cert.crt"
|
||||
|
||||
trap 'rm -rf "${tmp}"' EXIT INT TERM QUIT
|
||||
|
||||
exit 0
|
Loading…
Reference in a new issue