2015-04-09 19 views
6

Ho cercato di usare Python-LDAP (versione 2.4.19) sotto MacOS X 10.9.5 e Python 2.7.9Come forzo Python LDAP per convalidare/verificare un certificato SSL quando si utilizza .start_tls_s()

Voglio convalidare la mia connessione a un determinato server LDAP dopo che ho chiamato lo .start_tls_s() (o per avere il metodo raise e l'eccezione se il certificato non può essere verificato). (Vorrei anche verificare un CRL, ma è diverso).

Ecco il mio codice:

#!python 
#!/usr/bin/env python 
import ConfigParser, os, sys 
import ldap 

CACERTFILE='./ca_ldap.bad' 
## CACERTFILE='./ca_ldap.crt' 

config = ConfigParser.ConfigParser() 
config.read(os.path.expanduser('~/.ssh/creds.ini')) 
uid = config.get('LDAP', 'uid') 
pwd = config.get('LDAP', 'pwd') 
svr = config.get('LDAP', 'svr') 
bdn = config.get('LDAP', 'bdn') 

ld = ldap.initialize(svr) 
ld.protocol_version=ldap.VERSION3 
ld.set_option(ldap.OPT_DEBUG_LEVEL, 255) 
ld.set_option(ldap.OPT_PROTOCOL_VERSION, 3) 
ld.set_option(ldap.OPT_X_TLS_CACERTFILE, CACERTFILE) 
ld.set_option(ldap.OPT_X_TLS_DEMAND, True) 
ld.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD) 

## From: https://stackoverflow.com/a/7810308/149076 
## and : http://python-ldap.cvs.sourceforge.net/viewvc/python-ldap/python-ldap/Demo/initialize.py?revision=1.14&view=markup 

ld.start_tls_s() 

for each in dir(ldap): 
    if 'OPT_X_TLS' in each: 
     try: 
      print '\t*** %s: %s' % (each, ld.get_option((getattr(ldap, each)))) 
     except Exception, e: 
      print >> sys.stderr, '... Except %s: %s\n' % (each, e) 

ld.simple_bind_s(uid, pwd) 
results = ld.search_s(bdn, ldap.SCOPE_SUBTREE) 

print 'Found %s entries under %s' % (len(results), bdn) 
sys.exit() 

Come notato nei commenti che ho copiato la maggior parte di questo da https://stackoverflow.com/a/7810308/149076 e dalle http://python-ldap.cvs.sourceforge.net/viewvc/python-ldap/python-ldap/Demo/initialize.py?revision=1.14&view=markup ... anche se ho provato molte variazioni e sequenze di questo.

Come illustrato Ho due file che rappresentano un certificato cattiva e uno che dovrebbe funzionare (in realtà è preso da uno dei nostri sistemi, che è configurato per eseguire sssd (Sistema Security Services Daemon), che si presume essere il check questo

Nella copia "cattiva" ho semplicemente sostituito il primo carattere di ogni riga di chiave con la lettera 'x' supponendo che ciò possa corrompere la chiave CA e causare qualsiasi codice che tenta di verificare una catena di firme to fail

Tuttavia, sembra che il codice LDAP Python ignori questo, anche se l'ho impostato su /dev/null o un percorso completamente falso il mio codice è ancora in esecuzione, si collega ancora al server LDAP e completa ancora la mia richiesta di ricerca.

Quindi la domanda è, come ottengo questo a "fallire" come previsto (o, più in generale, come posso evitare di codice da essere vulnerabile a MITM Mallory) attacchi (?

Se si tratta di di qualsiasi di conseguenza in questa discussione, ecco la mia versione OpenSSL:

$ openssl version 
OpenSSL 0.9.8za 5 Jun 2014 

Il server LDAP è in esecuzione OpenLDAP, ma non so i dettagli circa la sua versione né configurazione

Ecco un esempio di output dal mio codice:.

*** OPT_X_TLS: 0 
    *** OPT_X_TLS_ALLOW: 0 
    *** OPT_X_TLS_CACERTDIR: None 
    *** OPT_X_TLS_CACERTFILE: /bogus/null 
    *** OPT_X_TLS_CERTFILE: None 
    *** OPT_X_TLS_CIPHER_SUITE: None 
    *** OPT_X_TLS_CRLCHECK: 0 
    *** OPT_X_TLS_CRLFILE: None 
    *** OPT_X_TLS_CRL_ALL: 1 
    *** OPT_X_TLS_CRL_NONE: {'info_version': 1, 'extensions': ('X_OPENLDAP', 'THREAD_SAFE', 'SESSION_THREAD_SAFE', 'OPERATION_THREAD_SAFE', 'X_OPENLDAP_THREAD_SAFE'), 'vendor_version': 20428, 'protocol_version': 3, 'vendor_name': 'OpenLDAP', 'api_version': 3001} 
    *** OPT_X_TLS_CRL_PEER: 3 
... Except OPT_X_TLS_CTX: unknown option 24577 

    *** OPT_X_TLS_DEMAND: 1 
    *** OPT_X_TLS_DHFILE: None 
    *** OPT_X_TLS_HARD: 3 
    *** OPT_X_TLS_KEYFILE: None 
    *** OPT_X_TLS_NEVER: {'info_version': 1, 'extensions': ('X_OPENLDAP', 'THREAD_SAFE', 'SESSION_THREAD_SAFE', 'OPERATION_THREAD_SAFE', 'X_OPENLDAP_THREAD_SAFE'), 'vendor_version': 20428, 'protocol_version': 3, 'vendor_name': 'OpenLDAP', 'api_version': 3001} 
... Except OPT_X_TLS_NEWCTX: unknown option 24591 

    *** OPT_X_TLS_PACKAGE: OpenSSL 
    *** OPT_X_TLS_PROTOCOL_MIN: 0 
    *** OPT_X_TLS_RANDOM_FILE: None 
    *** OPT_X_TLS_REQUIRE_CERT: 1 
    *** OPT_X_TLS_TRY: 0 

Found 883 entries under [... redacted ...] 
+0

* "Vorrei anche verificare un CRL, ma è diverso" * - state attenti a questo. È possibile impostare se stessi per un DoS a causa di CRL mancanti e guasti e dei risponditori OCSP. Mozilla lo ha spento per un po 'perché ha avuto un tale effetto negativo sull'esperienza utente. Le risposte graffate sarebbero probabilmente la strada da percorrere. – jww

+0

Nel mio caso questo funzionerà in un ambiente che fornisce la propria CA e gestisce i propri CRL. È tutto interno. –

+0

Potrei essere il portatore di cattive notizie ... Python-LDAP può usare OpenSSL. Ma le chiamate che in genere utilizzano o incontri per la gestione dei certificati non sono presenti. Ad esempio, ottengo 0 successi per 'cd python-ldap; grep -R -i ca_certs *; grep -R -i wrap_socket *; grep -R -i certs_reqs * '. Potresti voler raggiungere gli sviluppatori per vedere la loro posizione. Potrebbero dire qualcosa del tipo: "il codice deve essere eseguito nello stesso limite di sicurezza del server LDAP, quindi usiamo un certificato per la riservatezza, ma non verifichiamo il server o impieghiamo l'autenticazione del server perché non esiste un MitM attivo". – jww

risposta

7

Il codice funziona per me come previsto. In realtà, ho avuto esattamente il problema opposto, quando ho eseguito il tuo codice per la prima volta. E 'sempre detto "verifica certificato fallita". Aggiungendo le seguenti linee fisse questo:

# Force libldap to create a new SSL context (must be last TLS option!) 
ld.set_option(ldap.OPT_X_TLS_NEWCTX, 0) 

Ora quando uso il certificato CA sbagliato o uno che è stato modificato, come hai descritto, il risultato è questo messaggio di errore:

Traceback (most recent call last): 
    File "ldap_ssl.py", line 28, in <module> 
    ld.start_tls_s() 
    File "/Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/ldap/ldapobject.py", line 571, in start_tls_s 
    return self._ldap_call(self._l.start_tls_s) 
    File "/Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/ldap/ldapobject.py", line 106, in _ldap_call 
    result = func(*args,**kwargs) 
ldap.CONNECT_ERROR: {'info': 'error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (unable to get local issuer certificate)', 'desc': 'Connect error'} 

Quando uso il certificato CA corretto, l'output è come il tuo.


Ora la domanda interessante è: quali sono le differenze tra le nostre impostazioni e in particolare quale differenza provoca questo strano comportamento sulla vostra macchina?

La mia configurazione è:

  • Mac OS X 10.10
  • Python 2.7.6
  • python-ldap 2.4.19 (installazione manuale)
  • OpenLDAP 2.4.39 (via Homebrew)
  • OpenSSL 1.0.1l (via Homebrew)

ho un OpenLDAP locale che esegue, insta riempito con Homebrew:

brew install homebrew/dupes/openldap --with-berkeley-db 

su Yosemite python-LDAP viene buggy abbastanza quando installato con pip (vedi Python-ldap set_option not working on Yosemite), quindi ho dovuto scaricare il tarball e compilare/installare, che era fortunatamente abbastanza facile, perché ho già aveva l'installazione di OpenLDAP con gli attuali libs/intestazioni:

prima modifica la sezione [_ldap] in setup.cfg come questo:

[_ldap] 
library_dirs = /usr/local/opt/openldap/lib /usr/lib /usr/local/lib 
include_dirs = /usr/local/opt/openldap/include /usr/include/sasl /usr/include /usr/local/include 
extra_compile_args = -g -arch x86_64 
extra_objects = 
libs = ldap_r lber sasl2 ssl crypto 

Alcuni file di intestazione sono in Mac OS SDK, collegamento t directory lui (modificare il percorso in base alla versione) in/usr/include:

sudo ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/ /usr/include 

Poi compilare e installare:

python setup.py build 
sudo python setup.py install 

L'uscita del otool mostra che python-ldap è ora collegato al librerie di OpenLDAP 2.4.39 e 0.9.8 OpenSSL:

$ otool -L /Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/_ldap.so 
/Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/_ldap.so: 
    /usr/local/lib/libldap_r-2.4.2.dylib (compatibility version 13.0.0, current version 13.2.0) 
    /usr/local/lib/liblber-2.4.2.dylib (compatibility version 13.0.0, current version 13.2.0) 
    /usr/lib/libsasl2.2.dylib (compatibility version 3.0.0, current version 3.15.0) 
    /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) 
    /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) 
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0) 

Un approccio alternativo per la costruzione di python-LDAP è di installare solo le librerie OpenLDAP e le intestazioni necessarie per la costruzione: http://projects.skurfer.com/posts/2011/python_ldap_lion/

Tutti questi passaggi dovrebbero funzionare anche con Mavericks e presumo che l'utilizzo delle ultime librerie OpenLDAP e OpenSSL risolverà il problema.

+0

Sul mio Mac con MacOS 10.9.5, non ricevevo alcun avviso o errore. Su una macchina virtuale Linux in CentOS 6.5, l'ultima volta che ho controllato, sto ricevendo il comportamento che descrivi qui (almeno fino al punto in cui "solleva sempre l'eccezione"). Proverò l'impostazione 'ld.set_option (ldap.OPT_X_TLS_NEWCTX, 0)' e aggiusterò alcune delle mie librerie 'brew'. (Sto usando Python 2.7.9 come notato sopra, il mio LDAP/OpenSSL è o predefinito MacOS o caricato in azienda --- Non ho incasinato nessuno dei due. –

+0

Omikron, sei decisamente il front runner per la taglia così lontano;) –

+0

Ho aggiunto l'output di otool, sembra che la versione di OpenSSL non importi qui, perché il mio python-ldap è collegato a 0.9.8z non a 1.0.1l. – Omikron

Problemi correlati