1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-01-26 06:46:13 +01:00

use python-m2crypto for actually secure SSL

This commit is contained in:
Ludwig Nussel 2009-10-02 11:25:59 +00:00
parent eab1349dff
commit f8545f8dcf
4 changed files with 98 additions and 5 deletions

5
NEWS
View File

@ -1,5 +1,8 @@
0.123
- IMPORTANT: ssl certificate checks are actually performed now to
prevent man-in-the-middle-attacks. python-m2crypto is needed to
make this work. Certificate checks can be turned off per server
via 'sslcertck = 0' in .oscrc.
- 'osc list' option -D now only limits non-'new' requests. In state 'new' all are shown.
- suggest 'osc list' --bugowner option. Not implemented.
- implemented 'osc ls .' to take proj/pack name from current directory.

View File

@ -7,6 +7,14 @@ import sys
import signal
from osc import oscerr
from urllib2 import URLError, HTTPError
from oschttps import NoSecureSSLError
try:
from M2Crypto.SSL.Checker import SSLVerificationError
from M2Crypto.SSL import SSLError as SSLError
except:
SSLError = None
SSLVerificationError = None
try:
# import as RPMError because the class "error" is too generic
from rpm import error as RPMError
@ -138,6 +146,18 @@ def run(prg):
print >>sys.stderr, e
return 1
except SSLError, e:
print >>sys.stderr, "SSL Error:", e
return 1
except SSLVerificationError, e:
print >>sys.stderr, "Certificate Verification Error:", e
return 1
except NoSecureSSLError, e:
print >>sys.stderr, e
return 1
except OSError, e:
print >>sys.stderr, e
return 1

View File

@ -35,6 +35,7 @@ The configuration dictionary could look like this:
"""
import OscConfigParser
from osc import oscerr
from oschttps import NoSecureSSLError
GENERIC_KEYRING = False
GNOME_KEYRING = False
@ -72,6 +73,7 @@ DEFAULTS = { 'apiurl': 'https://api.opensuse.org',
'build-memory' : '',# required for VM builds
'build-swap' : '', # optional for VM builds
'sslcertck': '1',
'debug': '0',
'http_debug': '0',
'traceback': '0',
@ -269,13 +271,51 @@ def get_apiurl_usr(apiurl):
% (apiurl, config['user'])
return config['user']
def verify_cb(ok, store):
# XXX: this is not really smart. It only detects one error.
# Potentially in the chain which is not that useful to the user.
# We should do this after the ssl handshake.
if(not ok):
err = store.get_error()
cert = store.get_current_cert()
print "*** Certificate verify failed (depth=%s) ***" % store.get_error_depth()
print "Subject: ", cert.get_subject()
print "Issuer: ", cert.get_issuer()
print "Fingerprint: ", cert.get_fingerprint()
print "Valid: ", cert.get_not_before(), "-", cert.get_not_before()
try:
import M2Crypto.Err
reason = M2Crypto.Err.get_x509_verify_error(err)
print "Reason: ", reason
except:
pass
while True:
r = raw_input("continue anyways (y/p/N)? ")
if r == 'y':
return 1
elif r == 'p':
print cert.as_text()
else:
break
return ok
def init_basicauth(config):
"""initialize urllib2 with the credentials for Basic Authentication"""
from osc.core import __version__
import os, urllib2
import os
import cookielib
if config['api_host_options'][config['apiurl']]['sslcertck'] != '0':
try:
from M2Crypto import m2urllib2, SSL
except:
raise NoSecureSSLError("M2Crypto is needed to access %s in a secure way.\nPlease install python-m2crypto." % config['apiurl'])
import urllib2
global cookiejar
# HTTPS proxy is not supported by urllib2. It only leads to an error
@ -308,7 +348,24 @@ def init_basicauth(config):
#print 'Unable to create cookiejar file: \'%s\'. Using RAM-based cookies.' % cookie_file
cookiejar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar), authhandler)
if config['api_host_options'][config['apiurl']]['sslcertck'] != '0':
cafile = capath = None
if 'capath' in config['api_host_options'][config['apiurl']]:
capath = config['api_host_options'][config['apiurl']]['capath']
if 'cafile' in config['api_host_options'][config['apiurl']]:
cafile = config['api_host_options'][config['apiurl']]['cafile']
if not cafile and not capath:
capath = '/etc/ssl/certs'
ctx = SSL.Context('sslv3')
ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9, callback=verify_cb)
if ctx.load_verify_locations(capath=capath, cafile=cafile) != 1: raise Exception('No CA certificates found')
opener = m2urllib2.build_opener(ctx, urllib2.HTTPCookieProcessor(cookiejar), authhandler)
else:
import sys;
print >>sys.stderr, "WARNING: SSL certificate checks disabled. Connection is insecure!\n"
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar), authhandler)
urllib2.install_opener(opener)
opener.addheaders = [('User-agent', 'osc/%s' % __version__)]
@ -565,8 +622,14 @@ def get_config(override_conffile = None,
api_host_options[apiurl] = { 'user': user,
'pass': password,
'http_headers': http_headers}
if cp.has_option(url, 'email'):
api_host_options[apiurl]['email'] = cp.get(url, 'email')
optional = ('email', 'sslcertck', 'cafile', 'capath')
for key in optional:
if cp.has_option(url, key):
api_host_options[apiurl][key] = cp.get(url, key)
if not 'sslcertck' in api_host_options[apiurl]:
api_host_options[apiurl]['sslcertck'] = 1
# add the auth data we collected to the config dict
config['api_host_options'] = api_host_options

7
osc/oschttps.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/python
class NoSecureSSLError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg