spaceblog

Today's OpenLDAP bug: openssl 0.9.6b, 3DES, and why your SSF doesn't work

security ssf=128”, we said. The RHEL ES 3 box’s passwd spoke PAM and pam_ldap handled the referral back to the master, and the master churned and clunked “You may pass.

The RHEL ES 2.1 box tried also, but got back “Permission denied,” with no further clues. The OpenLDAP master server mumbled in its raspy monotone “stronger confidentiality required.” What?

So we checked with openssl s_client, to see what ciphers were being negotiated. The ES3 box was choosing AES256, which happily met the requirements. However, the ES2.1 box was negotiating DES-CBC3-SHA.

Well, no problem. 3DES has 112 bits of secrecy, so let’s drop the SSF requirement. “Stronger confidentiality required!” blurted the master.

What? Surely OpenLDAP doesn’t think that we’re using single DES here? Drop the SSF to 56… BEHOLD! The password update is allowed.

OpenLDAP is calculating the SSF of a cipher by using SSL_CIPHER_get_bits(), which seems fine except that for 3DES it’s not considering the triple application – 168 bits all up but only 112 once you consider meet in the middle attacks. So one could argue that using the get_bits function is wrong… except that it works for all other ciphers, because they don’t do multiple cycles.

You could ask SSL_CIPHER_description() for the SSF, parsing the string for the Enc attribute, but for 3DES you’d get 168, which isn’t correct either. The real solution then is to special case 3DES with an SSF of 112 – but now that openssl 0.9.7 is in common use, who really cares? It’s only the few old instances of 0.9.6b lying around on legacy RHEL 2.1 boxes that are even affected, and in this bleeding edge world of Open Sores with its -funroll-loops, there’s no glory in working around it.

Ideally, the OpenSSL library itself would return the SSF of a cipher, so we wouldn’t have to rely on application writers assuming get_bits is correct all the time.

So if you want an older SSL client to connect to an OpenLDAP server, you’re going to have to sacrifice the SSF level to get basic cooperation between the client and server; but really, there are enough bugs in OpenLDAP that any attacker isn’t going to start by attempting to crack SSL.

One does pause to wonder how the replication from the master to the local slave on the ES 2.1 box worked at all though, given that they also use SSL; the SSF of the client as we know wasn’t high enough. Could it be: another OpenLDAP bug?

DOM DOM DOM!

build debs and rpms from the same source using debian source and rpmbuild

I’d found mock from a post on the scons-users list (I think… yesterday was long ago and my memory is poor), and wanted to try it out, but alas it uses the rpm python bindings, which don’t exist on Debian… or they do but they don’t exist here… anyway, I gave up.

But today I was looking to see if I could find a Debian package of the python rpm bindings, because I really want to build rpms in chroot on my Ubuntu workstation, and I found this brilliant hack on Progeny’s lsb-workers list.

barry, check it out

barry now comes with a prefilled list of archives known to your local baz, and gives you the option of checking out any listed branch into the location of your choice. The branch listing has also been cleaned up to take advantage of the TreeView, showing the chain of ancestors for any branch.

script for updating postgresql databases for encoding bugs

The PostgreSQL advisory gave us some clues how to apply the security fix without dump/initdb/reload, but this sucks on a shared hosting server with several hundred databases :-)

Here’s some perl that iterates over all your databases and applies the fix, and also fixes up template0 in the recommended way. No warranty of fitness for purpose, blah blah, public domain, blah blah.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env perl

use DBI;

my $db = DBI->connect(q/dbi:Pg:dbname=template1/);

my $databases = $db->prepare(q{
SELECT datname FROM pg_database WHERE datname <> 'template0'
});

$databases->execute()
  or die $DBI::errstr;

sub fix($) {
  my $datname = shift;

  #print "fixing $datname\n";

  my $fixdb = DBI->connect("dbi:Pg:dbname=$datname");

  $fixdb->begin_work;

  my $fixinator = $fixdb->prepare(q{
UPDATE pg_proc SET proargtypes[3] = 'internal'::regtype
WHERE pronamespace = 11 AND pronargs = 5
      AND proargtypes[2] = 'cstring'::regtype;
});

  $fixinator->execute()
    or die $DBI::errstr;

  if ($fixinator->rows == 90) {
    #print "fixed $datname ok\n";
    $fixdb->commit();
  } else {
    print "warning! $datname not fixed\n";
    $fixdb->rollback();
  }

  $fixdb->disconnect();
}

# do all but template0
while (@data = $databases->fetchrow_array()) {
  #print @data[0] . "\n";

  fix(@data[0])
}

# do template0
$db->do(q{
update pg_database set datallowconn = true where
datname = 'template0';
});
fix('template0');
$db->do("vacuum freeze");
$db->do(q{
update pg_database set datallowconn = false where
datname = 'template0';
});

$db->disconnect();