mirror of
https://github.com/openSUSE/osc.git
synced 2025-01-27 07:06:13 +01:00
use python-m2crypto for actually secure SSL
This commit is contained in:
parent
eab1349dff
commit
f8545f8dcf
5
NEWS
5
NEWS
@ -1,5 +1,8 @@
|
|||||||
|
|
||||||
0.123
|
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.
|
- 'osc list' option -D now only limits non-'new' requests. In state 'new' all are shown.
|
||||||
- suggest 'osc list' --bugowner option. Not implemented.
|
- suggest 'osc list' --bugowner option. Not implemented.
|
||||||
- implemented 'osc ls .' to take proj/pack name from current directory.
|
- implemented 'osc ls .' to take proj/pack name from current directory.
|
||||||
|
@ -7,6 +7,14 @@ import sys
|
|||||||
import signal
|
import signal
|
||||||
from osc import oscerr
|
from osc import oscerr
|
||||||
from urllib2 import URLError, HTTPError
|
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:
|
try:
|
||||||
# import as RPMError because the class "error" is too generic
|
# import as RPMError because the class "error" is too generic
|
||||||
from rpm import error as RPMError
|
from rpm import error as RPMError
|
||||||
@ -138,6 +146,18 @@ def run(prg):
|
|||||||
print >>sys.stderr, e
|
print >>sys.stderr, e
|
||||||
return 1
|
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:
|
except OSError, e:
|
||||||
print >>sys.stderr, e
|
print >>sys.stderr, e
|
||||||
return 1
|
return 1
|
||||||
|
71
osc/conf.py
71
osc/conf.py
@ -35,6 +35,7 @@ The configuration dictionary could look like this:
|
|||||||
"""
|
"""
|
||||||
import OscConfigParser
|
import OscConfigParser
|
||||||
from osc import oscerr
|
from osc import oscerr
|
||||||
|
from oschttps import NoSecureSSLError
|
||||||
|
|
||||||
GENERIC_KEYRING = False
|
GENERIC_KEYRING = False
|
||||||
GNOME_KEYRING = False
|
GNOME_KEYRING = False
|
||||||
@ -72,6 +73,7 @@ DEFAULTS = { 'apiurl': 'https://api.opensuse.org',
|
|||||||
'build-memory' : '',# required for VM builds
|
'build-memory' : '',# required for VM builds
|
||||||
'build-swap' : '', # optional for VM builds
|
'build-swap' : '', # optional for VM builds
|
||||||
|
|
||||||
|
'sslcertck': '1',
|
||||||
'debug': '0',
|
'debug': '0',
|
||||||
'http_debug': '0',
|
'http_debug': '0',
|
||||||
'traceback': '0',
|
'traceback': '0',
|
||||||
@ -269,13 +271,51 @@ def get_apiurl_usr(apiurl):
|
|||||||
% (apiurl, config['user'])
|
% (apiurl, config['user'])
|
||||||
return 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):
|
def init_basicauth(config):
|
||||||
"""initialize urllib2 with the credentials for Basic Authentication"""
|
"""initialize urllib2 with the credentials for Basic Authentication"""
|
||||||
|
|
||||||
from osc.core import __version__
|
from osc.core import __version__
|
||||||
import os, urllib2
|
import os
|
||||||
import cookielib
|
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
|
global cookiejar
|
||||||
|
|
||||||
# HTTPS proxy is not supported by urllib2. It only leads to an error
|
# 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
|
#print 'Unable to create cookiejar file: \'%s\'. Using RAM-based cookies.' % cookie_file
|
||||||
cookiejar = cookielib.CookieJar()
|
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)
|
urllib2.install_opener(opener)
|
||||||
|
|
||||||
opener.addheaders = [('User-agent', 'osc/%s' % __version__)]
|
opener.addheaders = [('User-agent', 'osc/%s' % __version__)]
|
||||||
@ -565,8 +622,14 @@ def get_config(override_conffile = None,
|
|||||||
api_host_options[apiurl] = { 'user': user,
|
api_host_options[apiurl] = { 'user': user,
|
||||||
'pass': password,
|
'pass': password,
|
||||||
'http_headers': http_headers}
|
'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
|
# add the auth data we collected to the config dict
|
||||||
config['api_host_options'] = api_host_options
|
config['api_host_options'] = api_host_options
|
||||||
|
7
osc/oschttps.py
Normal file
7
osc/oschttps.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
class NoSecureSSLError(Exception):
|
||||||
|
def __init__(self, msg):
|
||||||
|
self.msg = msg
|
||||||
|
def __str__(self):
|
||||||
|
return self.msg
|
Loading…
Reference in New Issue
Block a user