Skip to content

Commit f5d29ea

Browse files
committed
Implement OPT_X_TLS_PEERCERT
LDAP_OPT_X_TLS_PEERCERT requires a non-NULL berval. Its bv_val must be de-allocated with ber_memfree(). Signed-off-by: Christian Heimes <cheimes@redhat.com>
1 parent 0f75996 commit f5d29ea

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

Modules/options.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value)
5959
case LDAP_OPT_API_FEATURE_INFO:
6060
#ifdef HAVE_SASL
6161
case LDAP_OPT_X_SASL_SSF:
62+
#endif
63+
#ifdef LDAP_OPT_X_TLS_PEERCERT
64+
case LDAP_OPT_X_TLS_PEERCERT:
6265
#endif
6366
/* Read-only options */
6467
PyErr_SetString(PyExc_ValueError, "read-only option");
@@ -250,14 +253,16 @@ LDAP_get_option(LDAPObject *self, int option)
250253
{
251254
int res;
252255
int intval;
253-
struct berval *bv;
254256
struct timeval *tv;
255257
LDAPAPIInfo apiinfo;
256258
LDAPControl **lcs;
257259
char *strval;
258260
#if HAVE_SASL
259261
/* unsigned long */
260262
ber_len_t blen;
263+
#endif
264+
#ifdef LDAP_OPT_X_TLS_PEERCERT
265+
struct berval bv = {0, 0};
261266
#endif
262267
PyObject *extensions, *v;
263268
Py_ssize_t i, num_extensions;
@@ -428,18 +433,20 @@ LDAP_get_option(LDAPObject *self, int option)
428433
return v;
429434
#ifdef LDAP_OPT_X_TLS_PEERCERT
430435
case LDAP_OPT_X_TLS_PEERCERT:
431-
#endif
432-
/* Berval-valued options */
433436
res = LDAP_int_get_option(self, option, &bv);
434-
if (res != LDAP_OPT_SUCCESS)
437+
if (res != LDAP_OPT_SUCCESS) {
435438
return option_error(res, "ldap_get_option");
436-
if (bv == NULL) {
437-
Py_INCREF(Py_None);
438-
return Py_None;
439439
}
440-
v = LDAPberval_to_object(bv);
441-
ldap_memfree(bv);
442-
return v;
440+
if (bv.bv_len == 0) {
441+
Py_RETURN_NONE;
442+
} else {
443+
v = LDAPberval_to_object(&bv);
444+
/* bv_val memory is allocated with ber_memalloc_x()
445+
* context allocation/dealloc is a private API. */
446+
ber_memfree(bv.bv_val);
447+
return v;
448+
}
449+
#endif
443450
default:
444451
PyErr_Format(PyExc_ValueError, "unknown option %d", option);
445452
return NULL;

Tests/t_ldapobject.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
from slapdtest import requires_ldapi, requires_sasl, requires_tls
2121
from slapdtest import requires_init_fd
2222

23+
try:
24+
from ssl import PEM_cert_to_DER_cert
25+
except ImportError:
26+
PEM_cert_to_DER_cert = None
27+
2328

2429
LDIF_TEMPLATE = """dn: %(suffix)s
2530
objectClass: dcObject
@@ -416,9 +421,38 @@ def test_multiple_starttls(self):
416421
l.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
417422
l.start_tls_s()
418423
l.simple_bind_s(self.server.root_dn, self.server.root_pw)
419-
self.assertEqual(l.get_option(ldap.OPT_X_TLS_PEERCERT), b"eg")
420424
self.assertEqual(l.whoami_s(), 'dn:' + self.server.root_dn)
421425

426+
@requires_tls()
427+
@unittest.skipUnless(
428+
hasattr(ldap, "OPT_X_TLS_PEERCERT"),
429+
reason="Requires OPT_X_TLS_PEERCERT"
430+
)
431+
def test_get_tls_peercert(self):
432+
l = self.ldap_object_class(self.server.ldap_uri)
433+
peercert = l.get_option(ldap.OPT_X_TLS_PEERCERT)
434+
self.assertEqual(peercert, None)
435+
with self.assertRaises(ValueError):
436+
l.set_option(ldap.OPT_X_TLS_PEERCERT, b"")
437+
438+
l.set_option(ldap.OPT_X_TLS_CACERTFILE, self.server.cafile)
439+
l.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
440+
l.start_tls_s()
441+
442+
peercert = l.get_option(ldap.OPT_X_TLS_PEERCERT)
443+
self.assertTrue(peercert)
444+
self.assertIsInstance(peercert, bytes)
445+
446+
if PEM_cert_to_DER_cert is not None:
447+
with open(self.server.servercert) as f:
448+
server_pem = f.read()
449+
# remove text
450+
begin = server_pem.find("-----BEGIN CERTIFICATE-----")
451+
server_pem = server_pem[begin:-1]
452+
453+
server_der = PEM_cert_to_DER_cert(server_pem)
454+
self.assertEqual(server_der, peercert)
455+
422456
def test_dse(self):
423457
dse = self._ldap_conn.read_rootdse_s()
424458
self.assertIsInstance(dse, dict)

0 commit comments

Comments
 (0)