Skip to content

Commit

Permalink
Stability fixes for the Botan TLS implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Etienne Cimon authored and s-ludwig committed Sep 13, 2015
1 parent 4864b6f commit 9f599f2
Showing 1 changed file with 63 additions and 24 deletions.
87 changes: 63 additions & 24 deletions source/vibe/stream/botan.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import botan.cert.x509.x509path;
import botan.tls.blocking;
import botan.tls.channel;
import botan.tls.credentials_manager;
import botan.tls.exceptn;
import botan.tls.server;
import botan.tls.session_manager;
import botan.tls.server_info;
Expand Down Expand Up @@ -80,10 +81,10 @@ class BotanTLSStream : TLSStream/*, Buffered*/
TLSServerInformation server_info = TLSServerInformation(peer_name, peer_address.port);
m_tlsChannel = TLSBlockingChannel(&onRead, &onWrite, &onAlert, &onHandhsakeComplete, m_ctx.m_sessionManager, m_ctx.m_credentials, m_ctx.m_policy, m_ctx.m_rng, server_info, m_ctx.m_offer_version, m_ctx.m_clientOffers.dup);

scope(exit)
processException();

m_tlsChannel.doHandshake();
try m_tlsChannel.doHandshake();
catch (Exception e) {
m_ex = e;
}
}

// This constructor is used by the TLS Context for both server and client streams
Expand All @@ -107,13 +108,19 @@ class BotanTLSStream : TLSStream/*, Buffered*/
m_tlsChannel = TLSBlockingChannel.init;
throw new Exception("Cannot load BotanTLSSteam from a connected TLS session");
}
scope(exit)
processException();

m_tlsChannel.doHandshake();


try m_tlsChannel.doHandshake();
catch (Exception e) {
m_ex = e;
}
}


~this() {
try m_tlsChannel.destroy();
catch (Exception e) {
}
}

void flush()
{
processException();
Expand All @@ -126,7 +133,7 @@ class BotanTLSStream : TLSStream/*, Buffered*/
return;

processException();
scope(exit)
scope(success)
processException();

m_tlsChannel.close();
Expand All @@ -138,23 +145,23 @@ class BotanTLSStream : TLSStream/*, Buffered*/
void read(ubyte[] dst)
{
processException();
scope(exit)
scope(success)
processException();
m_tlsChannel.read(dst);
}

ubyte[] readChunk(ubyte[] buf)
{
processException();
scope(exit)
scope(success)
processException();
return m_tlsChannel.readBuf(buf);
}

void write(in ubyte[] src)
{
processException();
scope(exit)
scope(success)
processException();
m_tlsChannel.write(src);
}
Expand All @@ -169,10 +176,14 @@ class BotanTLSStream : TLSStream/*, Buffered*/
{
size_t ret = m_tlsChannel.pending();
if (ret > 0) return ret;
if (m_stream.empty) return 0;
return 1; // can't we do better?
if (m_tlsChannel.isClosed() || m_ex !is null) return 0;
try m_tlsChannel.readBuf(null); // force an exchange
catch (Exception e) { return 0; }
ret = m_tlsChannel.pending();
//logDebug("Least size returned: ", ret);
return ret > 0 ? ret : m_stream.empty ? 0 : 1;
}

@property bool dataAvailableForRead()
{
processException();
Expand Down Expand Up @@ -262,6 +273,7 @@ class BotanTLSContext : TLSContext {
TLSALPNCallback m_serverCb;
Vector!string m_clientOffers;
bool m_is_datagram;
bool m_certChecked;
}

this(TLSContextKind kind,
Expand Down Expand Up @@ -293,7 +305,7 @@ class BotanTLSContext : TLSContext {
}
m_policy = policy;
}

/// The kind of TLS context (client/server)
@property TLSContextKind kind() const {
return m_kind;
Expand Down Expand Up @@ -331,6 +343,8 @@ class BotanTLSContext : TLSContext {
*/
TLSStream createStream(Stream underlying, TLSStreamState state, string peer_name = null, NetworkAddress peer_address = NetworkAddress.init)
{
if (!m_certChecked)
checkCert();
return new BotanTLSStream(underlying, this, state, peer_name, peer_address);
}

Expand Down Expand Up @@ -412,6 +426,7 @@ class BotanTLSContext : TLSContext {
/// Sets a certificate file to use for authenticating to the remote peer
void useCertificateChainFile(string path) {
if (auto credentials = cast(CustomTLSCredentials)m_credentials) {
m_certChecked = false;
credentials.m_server_cert = X509Certificate(path);
return;
}
Expand Down Expand Up @@ -483,6 +498,28 @@ class BotanTLSContext : TLSContext {
// We cannot use anything else than a Botan stream, and any null value with serverSNI is a failure
throw new Exception("Could not find specified hostname");
}

private void checkCert() {
m_certChecked = true;
if (m_kind == TLSContextKind.client) return;
if (auto creds = cast(CustomTLSCredentials) m_credentials) {
auto sigs = m_policy.allowedSignatureMethods();
import botan.asn1.oids : OIDS;
import vibe.core.log : logDebug;
auto sig_algo = OIDS.lookup(creds.m_server_cert.signatureAlgorithm().oid());
import std.range : front;
import std.algorithm.iteration : splitter;
string sig_algo_str = sig_algo.splitter("/").front.to!string;
logDebug("Certificate algorithm: %s", sig_algo_str);
bool found;
foreach (sig; sigs[]) {
if (sig == sig_algo_str) {
found = true; break;
}
}
assert(found, "Server Certificate uses a signing algorithm that is not accepted in the server policy.");
}
}
}

/**
Expand Down Expand Up @@ -773,32 +810,34 @@ private CustomTLSCredentials createCreds()
import botan.codec.hex;
import botan.utils.types;
scope rng = new AutoSeededRNG();
PrivateKey ca_key = RSAPrivateKey(rng, 1024);
auto ca_key = RSAPrivateKey(rng, 1024);
scope(exit) ca_key.destroy();

X509CertOptions ca_opts;
ca_opts.common_name = "Test CA";
ca_opts.country = "US";
ca_opts.CAKey(1);

X509Certificate ca_cert = x509self.createSelfSignedCert(ca_opts, ca_key, "SHA-256", rng);
X509Certificate ca_cert = x509self.createSelfSignedCert(ca_opts, *ca_key, "SHA-256", rng);

PrivateKey server_key = RSAPrivateKey(rng, 1024);
auto server_key = RSAPrivateKey(rng, 1024);

X509CertOptions server_opts;
server_opts.common_name = "localhost";
server_opts.country = "US";

PKCS10Request req = x509self.createCertReq(server_opts, server_key, "SHA-256", rng);
PKCS10Request req = x509self.createCertReq(server_opts, *server_key, "SHA-256", rng);

X509CA ca = X509CA(ca_cert, ca_key, "SHA-256");
X509CA ca = X509CA(ca_cert, *ca_key, "SHA-256");

auto now = Clock.currTime(UTC());
X509Time start_time = X509Time(now);
X509Time end_time = X509Time(now + 365.days);

X509Certificate server_cert = ca.signRequest(req, rng, start_time, end_time);

return new CustomTLSCredentials(server_cert, ca_cert, server_key);
return new CustomTLSCredentials(server_cert, ca_cert, server_key.release());

}

private {
Expand Down

0 comments on commit 9f599f2

Please sign in to comment.