Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
R
re6stnet
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Kirill Smelkov
re6stnet
Commits
8ebdd500
Commit
8ebdd500
authored
Mar 06, 2015
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Certificate revocation, with broadcast of CRL
parent
f73c51ec
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
181 additions
and
90 deletions
+181
-90
TODO
TODO
+5
-0
re6st/cache.py
re6st/cache.py
+9
-1
re6st/ovpn-client
re6st/ovpn-client
+4
-4
re6st/ovpn-server
re6st/ovpn-server
+9
-8
re6st/plib.py
re6st/plib.py
+3
-4
re6st/registry.py
re6st/registry.py
+47
-6
re6st/tunnel.py
re6st/tunnel.py
+85
-53
re6st/x509.py
re6st/x509.py
+8
-6
re6stnet
re6stnet
+11
-8
No files found.
TODO
View file @
8ebdd500
...
...
@@ -20,3 +20,8 @@
- registry: add '--home PATH' command line option so that / display an HTML
page from PATH (use new str.format for templating)
- Better UI to revoke certificates, for example with a HTML form.
Currently, one have to forge the URL manually. Examples:
wget -O /dev/null http://re6st.example.com/revoke?cn_or_serial=123
wget -O /dev/null http://re6st.example.com/revoke?cn_or_serial=4/16
re6st/cache.py
View file @
8ebdd500
...
...
@@ -4,6 +4,8 @@ from . import utils, version, x509
class
Cache
(
object
):
crl
=
()
def
__init__
(
self
,
db_path
,
registry
,
cert
,
db_size
=
200
):
self
.
_prefix
=
cert
.
prefix
self
.
_db_size
=
db_size
...
...
@@ -40,6 +42,7 @@ class Cache(object):
# when it tried to send us new parameters.
or
self
.
_prefix
==
self
.
registry_prefix
):
self
.
updateConfig
()
self
.
next_renew
=
cert
.
maybeRenew
(
self
.
_registry
,
self
.
crl
)
if
version
.
protocol
<
self
.
min_protocol
:
logging
.
critical
(
"Your version of re6stnet is too old."
" Please update."
)
...
...
@@ -64,7 +67,11 @@ class Cache(object):
cls
=
self
.
__class__
logging
.
debug
(
"Loading network parameters:"
)
for
k
,
v
in
config
:
hasattr
(
cls
,
k
)
or
setattr
(
self
,
k
,
v
)
if
k
==
'crl'
:
v
=
set
(
json
.
loads
(
v
))
elif
hasattr
(
cls
,
k
):
continue
setattr
(
self
,
k
,
v
)
logging
.
debug
(
"- %s: %r"
,
k
,
v
)
def
updateConfig
(
self
):
...
...
@@ -77,6 +84,7 @@ class Cache(object):
config
=
dict
((
str
(
k
),
v
.
decode
(
'base64'
)
if
k
in
base64
else
str
(
v
)
if
type
(
v
)
is
unicode
else
v
)
for
k
,
v
in
config
.
iteritems
())
config
[
'crl'
]
=
json
.
dumps
(
config
[
'crl'
])
except
socket
.
error
,
e
:
logging
.
warning
(
e
)
return
...
...
re6st/ovpn-client
View file @
8ebdd500
...
...
@@ -9,7 +9,7 @@ if script_type == 'up':
os
.
execlp
(
'ip'
,
'ip'
,
'link'
,
'set'
,
os
.
environ
[
'dev'
],
'up'
,
'mtu'
,
os
.
environ
[
'tun_mtu'
])
# Write into pipe external ip address received
import
time
os
.
write
(
int
(
sys
.
argv
[
1
]),
"%s %s %s %s
\
n
"
%
(
script_type
,
os
.
environ
[
'common_name'
],
time
.
time
(),
os
.
environ
[
'OPENVPN_external_ip'
]
))
if
script_type
==
'route-up'
:
import
time
os
.
write
(
int
(
sys
.
argv
[
1
]),
repr
((
os
.
environ
[
'common_name'
],
time
.
time
()
,
int
(
os
.
environ
[
'tls_serial_0'
]),
os
.
environ
[
'OPENVPN_external_ip'
])
))
re6st/ovpn-server
View file @
8ebdd500
...
...
@@ -2,15 +2,16 @@
import
os
,
sys
script_type
=
os
.
environ
[
'script_type'
]
external_ip
=
lambda
:
os
.
getenv
(
'trusted_ip'
)
or
os
.
environ
[
'trusted_ip6'
]
external_ip
=
os
.
getenv
(
'trusted_ip'
)
or
os
.
environ
[
'trusted_ip6'
]
# Write into pipe connect/disconnect events
fd
=
int
(
sys
.
argv
[
1
])
os
.
write
(
fd
,
repr
((
script_type
,
(
os
.
environ
[
'common_name'
],
os
.
environ
[
'dev'
],
int
(
os
.
environ
[
'tls_serial_0'
]),
external_ip
))))
if
script_type
==
'client-connect'
:
if
os
.
read
(
fd
,
1
)
==
'
\
0
'
:
sys
.
exit
(
1
)
# Send client its external ip address
with
open
(
sys
.
argv
[
2
],
'w'
)
as
f
:
f
.
write
(
'push "setenv-safe external_ip %s"
\
n
'
%
external_ip
())
# Write into pipe connect/disconnect events
arg1
=
sys
.
argv
[
1
]
if
arg1
!=
'None'
:
os
.
write
(
int
(
arg1
),
'%s %s %s
\
n
'
%
(
script_type
,
os
.
environ
[
'common_name'
],
external_ip
()))
f
.
write
(
'push "setenv-safe external_ip %s"
\
n
'
%
external_ip
)
re6st/plib.py
View file @
8ebdd500
...
...
@@ -25,10 +25,8 @@ def openvpn(iface, encrypt, *args, **kw):
ovpn_link_mtu_dict
=
{
'udp'
:
1481
,
'udp6'
:
1450
}
def
server
(
iface
,
max_clients
,
dh_path
,
pipe_fd
,
port
,
proto
,
encrypt
,
*
args
,
**
kw
):
client_script
=
'%s %s'
%
(
ovpn_server
,
pipe_fd
)
if
pipe_fd
is
not
None
:
args
=
(
'--client-disconnect'
,
client_script
)
+
args
def
server
(
iface
,
max_clients
,
dh_path
,
fd
,
port
,
proto
,
encrypt
,
*
args
,
**
kw
):
client_script
=
'%s %s'
%
(
ovpn_server
,
fd
)
try
:
args
=
(
'--link-mtu'
,
str
(
ovpn_link_mtu_dict
[
proto
]),
# mtu-disc ignored for udp6 due to a bug in OpenVPN
...
...
@@ -39,6 +37,7 @@ def server(iface, max_clients, dh_path, pipe_fd, port, proto, encrypt, *args, **
'--tls-server'
,
'--mode'
,
'server'
,
'--client-connect'
,
client_script
,
'--client-disconnect'
,
client_script
,
'--dh'
,
dh_path
,
'--max-clients'
,
str
(
max_clients
),
'--port'
,
str
(
port
),
...
...
re6st/registry.py
View file @
8ebdd500
...
...
@@ -25,6 +25,7 @@ from collections import defaultdict, deque
from
datetime
import
datetime
from
BaseHTTPServer
import
HTTPServer
,
BaseHTTPRequestHandler
from
email.mime.text
import
MIMEText
from
operator
import
itemgetter
from
OpenSSL
import
crypto
from
urllib
import
splittype
,
splithost
,
splitport
,
urlencode
from
.
import
ctl
,
tunnel
,
utils
,
version
,
x509
...
...
@@ -71,6 +72,20 @@ class RegistryServer(object):
"email TEXT"
,
"cert TEXT"
):
self
.
db
.
execute
(
"INSERT INTO cert VALUES ('',null,null)"
)
if
utils
.
sqliteCreateTable
(
self
.
db
,
"crl"
,
"serial INTEGER PRIMARY KEY NOT NULL"
,
# Expiration date of revoked certificate.
# TODO: purge rows with dates in the past.
"date INTEGER NOT NULL"
):
# Revoke certificates produced by previous version.
# They all have serial 0.
try
:
date
=
max
(
x509
.
notAfter
(
x
[
0
])
for
x
in
self
.
iterCert
())
except
ValueError
:
pass
else
:
if
time
.
time
()
<
date
:
self
.
db
.
execute
(
"INSERT INTO crl VALUES (0,?)"
,
(
date
,))
self
.
cert
=
x509
.
Cert
(
self
.
config
.
ca
,
self
.
config
.
key
)
# Get vpn network prefix
...
...
@@ -97,9 +112,11 @@ class RegistryServer(object):
self
.
db
.
execute
(
"INSERT OR REPLACE INTO config VALUES (?, ?)"
,
name_value
)
def
updateNetworkConfig
(
self
):
def
updateNetworkConfig
(
self
,
_it0
=
itemgetter
(
0
)
):
kw
=
{
'babel_default'
:
'max-rtt-penalty 5000 rtt-max 500 rtt-decay 125'
,
'crl'
:
map
(
_it0
,
self
.
db
.
execute
(
"SELECT serial FROM crl ORDER BY serial"
)),
'protocol'
:
version
.
protocol
,
'registry_prefix'
:
self
.
prefix
,
}
...
...
@@ -220,7 +237,7 @@ class RegistryServer(object):
def
handle_request
(
self
,
request
,
method
,
kw
,
_localhost
=
(
'127.0.0.1'
,
'::1'
)):
m
=
getattr
(
self
,
method
)
if
method
in
(
'versions'
,
'topology'
):
if
method
in
(
'
revoke'
,
'
versions'
,
'topology'
):
x_forwarded_for
=
request
.
headers
.
get
(
'X-Forwarded-For'
)
if
request
.
client_address
[
0
]
not
in
_localhost
or
\
x_forwarded_for
and
x_forwarded_for
not
in
_localhost
:
...
...
@@ -393,15 +410,16 @@ class RegistryServer(object):
@
rpc
def
renewCertificate
(
self
,
cn
):
with
self
.
lock
:
with
self
.
db
:
with
self
.
db
as
db
:
pem
=
self
.
getCert
(
cn
)
cert
=
crypto
.
load_certificate
(
crypto
.
FILETYPE_PEM
,
pem
)
if
x509
.
notAfter
(
cert
)
-
RENEW_PERIOD
<
time
.
time
():
not_after
=
None
elif
cert
.
get_serial_number
():
return
pem
else
:
elif
db
.
execute
(
"SELECT count(*) FROM crl WHERE serial=?"
,
(
cert
.
get_serial_number
(),)).
fetchone
()[
0
]:
not_after
=
cert
.
get_notAfter
()
else
:
return
pem
return
self
.
createCertificate
(
cn
,
cert
.
get_subject
(),
cert
.
get_pubkey
(),
not_after
)
...
...
@@ -452,6 +470,29 @@ class RegistryServer(object):
logging
.
info
(
"Sending bootstrap peer: %s"
,
msg
)
return
x509
.
encrypt
(
cert
,
msg
)
@
rpc
def
revoke
(
self
,
cn_or_serial
):
with
self
.
lock
:
with
self
.
db
:
q
=
self
.
db
.
execute
try
:
serial
=
int
(
cn_or_serial
)
except
ValueError
:
prefix
=
utils
.
binFromSubnet
(
cn_or_serial
)
cert
=
self
.
getCert
(
prefix
)
q
(
"UPDATE cert SET email=null, cert=null WHERE prefix=?"
,
(
prefix
,))
cert
=
crypto
.
load_certificate
(
crypto
.
FILETYPE_PEM
,
cert
)
serial
=
cert
.
get_serial_number
()
self
.
sessions
.
pop
(
prefix
,
None
)
else
:
cert
,
=
(
cert
for
cert
,
prefix
,
email
in
self
.
iterCert
()
if
cert
.
get_serial_number
()
==
serial
)
not_after
=
x509
.
notAfter
(
cert
)
if
time
.
time
()
<
not_after
:
q
(
"INSERT INTO crl VALUES (?,?)"
,
(
serial
,
not_after
))
self
.
updateNetworkConfig
()
@
rpc
def
versions
(
self
):
with
self
.
peers_lock
:
...
...
re6st/tunnel.py
View file @
8ebdd500
This diff is collapsed.
Click to expand it.
re6st/x509.py
View file @
8ebdd500
...
...
@@ -42,10 +42,12 @@ def encrypt(cert, data):
def
fingerprint
(
cert
,
alg
=
'sha1'
):
return
hashlib
.
new
(
alg
,
crypto
.
dump_certificate
(
crypto
.
FILETYPE_ASN1
,
cert
))
def
maybe_renew
(
path
,
cert
,
info
,
renew
):
def
maybe_renew
(
path
,
cert
,
info
,
renew
,
force
=
False
):
from
.registry
import
RENEW_PERIOD
while
True
:
if
cert
.
get_serial_number
():
if
force
:
force
=
False
else
:
next_renew
=
notAfter
(
cert
)
-
RENEW_PERIOD
if
time
.
time
()
<
next_renew
:
return
cert
,
next_renew
...
...
@@ -110,11 +112,10 @@ class Cert(object):
'--cert'
,
self
.
cert_path
,
'--key'
,
self
.
key_path
)
def
maybeRenew
(
self
,
registry
):
from
.registry
import
RegistryClient
registry
=
RegistryClient
(
registry
,
self
)
def
maybeRenew
(
self
,
registry
,
crl
):
self
.
cert
,
next_renew
=
maybe_renew
(
self
.
cert_path
,
self
.
cert
,
"Certificate"
,
lambda
:
registry
.
renewCertificate
(
self
.
prefix
))
"Certificate"
,
lambda
:
registry
.
renewCertificate
(
self
.
prefix
),
self
.
cert
.
get_serial_number
()
in
crl
)
self
.
ca
,
ca_renew
=
maybe_renew
(
self
.
ca_path
,
self
.
ca
,
"CA Certificate"
,
registry
.
getCa
)
return
min
(
next_renew
,
ca_renew
)
...
...
@@ -181,6 +182,7 @@ class Peer(object):
"""
_hello
=
_last
=
0
_key
=
newHmacSecret
()
serial
=
None
stop_date
=
float
(
'inf'
)
version
=
''
...
...
re6stnet
View file @
8ebdd500
...
...
@@ -2,6 +2,7 @@
import
atexit
,
errno
,
logging
,
os
,
shutil
,
signal
import
socket
,
subprocess
,
sys
,
time
,
threading
from
collections
import
deque
from
functools
import
partial
from
re6st
import
plib
,
tunnel
,
utils
,
version
,
x509
from
re6st.cache
import
Cache
from
re6st.utils
import
exit
,
ReexecException
...
...
@@ -130,7 +131,6 @@ def main():
exit
.
signal
(
0
,
signal
.
SIGINT
,
signal
.
SIGTERM
)
exit
.
signal
(
-
1
,
signal
.
SIGHUP
,
signal
.
SIGUSR2
)
next_renew
=
cert
.
maybeRenew
(
config
.
registry
)
cache
=
Cache
(
db_path
,
config
.
registry
,
cert
)
network
=
cert
.
network
...
...
@@ -249,14 +249,12 @@ def main():
control_socket
=
os
.
path
.
join
(
config
.
run
,
'babeld.sock'
)
if
config
.
client_count
and
not
config
.
client
:
tunnel_manager
=
tunnel
.
TunnelManager
(
control_socket
,
cache
,
cert
,
next_renew
,
config
.
openvpn_args
,
timeout
,
cache
,
cert
,
config
.
openvpn_args
,
timeout
,
config
.
client_count
,
config
.
iface_list
,
address
,
ip_changed
,
remote_gateway
,
config
.
disable_proto
,
config
.
neighbour
)
tunnel_interfaces
+=
tunnel_manager
.
new_iface_list
write_pipe
=
tunnel_manager
.
write_pipe
else
:
write_pipe
=
None
tunnel_manager
=
tunnel
.
BaseTunnelManager
(
cache
,
cert
,
next_renew
)
tunnel_manager
=
tunnel
.
BaseTunnelManager
(
cache
,
cert
)
cleanup
.
append
(
tunnel_manager
.
sock
.
close
)
try
:
...
...
@@ -275,6 +273,7 @@ def main():
# an public IP so Babel must be changed to set a source
# address on routes it installs.
ip
(
'addrlabel'
,
'prefix'
,
my_network
,
'label'
,
'99'
)
R
=
{}
# prepare persistent interfaces
if
config
.
client
:
address_list
=
[
x
for
x
in
utils
.
parse_address
(
config
.
client
)
...
...
@@ -288,9 +287,13 @@ def main():
elif
server_tunnels
:
required
(
'dh'
)
for
iface
,
(
port
,
proto
)
in
server_tunnels
.
iteritems
():
r
,
x
=
socket
.
socketpair
(
socket
.
AF_UNIX
,
socket
.
SOCK_DGRAM
)
cleanup
.
append
(
plib
.
server
(
iface
,
config
.
max_clients
,
config
.
dh
,
write_pipe
,
port
,
proto
,
cache
.
encrypt
,
'--ping-exit'
,
str
(
timeout
),
*
config
.
openvpn_args
).
stop
)
config
.
dh
,
x
.
fileno
(),
port
,
proto
,
cache
.
encrypt
,
'--ping-exit'
,
str
(
timeout
),
*
config
.
openvpn_args
,
preexec_fn
=
r
.
close
).
stop
)
R
[
r
]
=
partial
(
tunnel_manager
.
handleServerEvent
,
r
)
x
.
close
()
ip
(
'addr'
,
my_ip
,
'dev'
,
config
.
main_interface
)
if_rt
=
[
'ip'
,
'-6'
,
'route'
,
'del'
,
...
...
@@ -371,7 +374,7 @@ def main():
select_list
=
[
forwarder
.
select
]
if
forwarder
else
[]
select_list
+=
tunnel_manager
.
select
,
utils
.
select
while
True
:
args
=
{}
,
{},
[]
args
=
R
.
copy
()
,
{},
[]
for
s
in
select_list
:
s
(
*
args
)
finally
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment