mirror of
https://github.com/certbot/certbot.git
synced 2026-01-26 07:41:33 +03:00
move configuratoin parameters into config file; add extra sanity checks
This commit is contained in:
28
server-ca/CONFIG.py
Normal file
28
server-ca/CONFIG.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# The name that the server expects to be referred to by.
|
||||
chocolate_server_name = "ca.theobroma.info"
|
||||
|
||||
# The shortest length in bits of an acceptable RSA modulus.
|
||||
min_keysize = 2048
|
||||
|
||||
# The number of bits of hashcash that a client must provide with
|
||||
# a new request.
|
||||
difficulty = 23
|
||||
|
||||
# The number of seconds that the server asks the client to wait, at
|
||||
# a time, when a request is still being processed.
|
||||
polldelay = 4
|
||||
|
||||
# The maximum number of subject names in a request.
|
||||
max_names = 20
|
||||
|
||||
# The maximum size in bytes of a CSR.
|
||||
max_csr_size = 20480
|
||||
|
||||
# The expiry times of sessions, challenges, and hashcash, in seconds.
|
||||
maximum_session_age = 100
|
||||
maximum_challenge_age = 600
|
||||
hashcash_expiry = 60*60
|
||||
|
||||
# Extra names that the CA refuses to issue for, apart from those in
|
||||
# the blacklist table in the database.
|
||||
extra_name_blacklist = ["eff.org", "www.eff.org"]
|
||||
@@ -14,6 +14,8 @@ import hashlib
|
||||
import blacklists
|
||||
# we can use temp() to get tempfiles to pass to OpenSSL subprocesses.
|
||||
|
||||
from CONFIG import min_key_size
|
||||
|
||||
forbidden_moduli = blacklists.forbidden_moduli()
|
||||
forbidden_names = blacklists.forbidden_names()
|
||||
|
||||
@@ -45,7 +47,7 @@ def goodkey(key):
|
||||
"""Does this public key comply with our CA policy?"""
|
||||
key = str(key)
|
||||
bits = modulusbits(key)
|
||||
if bits and bits >= 2000 and not blacklisted(key):
|
||||
if bits and bits >= min_key_size and not blacklisted(key):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import web, redis, time, binascii
|
||||
import web, redis, time, binascii, re
|
||||
import CSR
|
||||
import hashcash
|
||||
from CSR import M2Crypto
|
||||
@@ -8,11 +8,9 @@ from Crypto import Random
|
||||
from chocolate_protocol_pb2 import chocolatemessage
|
||||
from google.protobuf.message import DecodeError
|
||||
|
||||
MaximumSessionAge = 100 # seconds, to demonstrate session timeout
|
||||
MaximumChallengeAge = 600 # to demonstrate challenge timeout
|
||||
HashcashExpiry = 60*60
|
||||
|
||||
difficulty = 23 # bits of hashcash required with new requests
|
||||
from CONFIG import chocolate_server_name, min_keysize, difficulty, polldelay
|
||||
from CONFIG import max_names, max_csr_size, maximum_session_age
|
||||
from CONFIG import maximum_challenge_age, hashcash_expiry, extra_name_blacklist
|
||||
|
||||
try:
|
||||
chocolate_server_name = open("SERVERNAME").read().rstrip()
|
||||
@@ -36,10 +34,11 @@ def safe(what, s):
|
||||
return False
|
||||
base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
csr_ok = base64 + " =-"
|
||||
# if what == "nonce":
|
||||
# return s.isalnum()
|
||||
if what == "recipient" or what == "hostname":
|
||||
return all(c.isalnum() or c in "-." for c in s)
|
||||
# This rejects domain names which don't contain ".". Although there
|
||||
# are some of these which are valid Internet FQDNs, none of them
|
||||
# should be subjects or recipients of Chocolate signing requests.
|
||||
return re.match("^[A-Za-z0-9][A-Za-z0-9-]*(\.[A-Za-z0-9][A-Za-z0-9-]*)+$", s) is not None
|
||||
elif what == "csr":
|
||||
return all(all(c in csr_ok for c in line) for line in s.split("\n"))
|
||||
# Note that this implies CSRs must have LF for end-of-line, not CRLF
|
||||
@@ -136,7 +135,7 @@ class session(object):
|
||||
def check_hashcash(self, h):
|
||||
"""Is the hashcash string h valid for a request to this server?"""
|
||||
if hashcash.check(stamp=h, resource=chocolate_server_name, \
|
||||
bits=difficulty, check_expiration=HashcashExpiry):
|
||||
bits=difficulty, check_expiration=hashcash_expiry):
|
||||
# sessions.sadd returns True upon adding to a set and
|
||||
# False if the item was already in the set.
|
||||
return sessions.sadd("spent-hashcash", h)
|
||||
@@ -186,7 +185,7 @@ class session(object):
|
||||
if not (self.exists() and self.live()):
|
||||
# Don't need to, or can't, kill nonexistent/already dead session
|
||||
r.failure.cause = r.StaleRequest
|
||||
elif self.age() > MaximumSessionAge:
|
||||
elif self.age() > maximum_session_age:
|
||||
# TODO: Sessions in state "done" should probably not be killed by timeout
|
||||
# because they have already resulted in issuance of a cert and no further
|
||||
# issuance can occur. At least, their timeout should probably be extended
|
||||
@@ -236,6 +235,9 @@ class session(object):
|
||||
if time.time() - timestamp > 100:
|
||||
self.die(r, r.BadRequest, uri="https://ca.example.com/failures/past")
|
||||
return
|
||||
if len(csr) > max_csr_size:
|
||||
self.die(r, r.BadCSR, uri="https://ca.example.com/failures/longcsr")
|
||||
return
|
||||
if not CSR.parse(csr):
|
||||
self.die(r, r.BadCSR)
|
||||
return
|
||||
@@ -250,8 +252,11 @@ class session(object):
|
||||
if len(names) == 0:
|
||||
self.die(r, r.BadCSR)
|
||||
return
|
||||
if len(names) > max_names:
|
||||
self.die(r, r.BadCSR, uri="https://ca.example.com/failures/toomanynames")
|
||||
return
|
||||
for san in names: # includes CN as well as SANs
|
||||
if not safe("hostname", san) or not CSR.can_sign(san):
|
||||
if not safe("hostname", san) or not CSR.can_sign(san) or san in extra_name_blacklist:
|
||||
# TODO: Is there a problem including client-supplied data in the URL?
|
||||
self.die(r, r.CannotIssueThatName, uri="https://ca.example.com/failures/name?%s" % san)
|
||||
return
|
||||
@@ -262,7 +267,7 @@ class session(object):
|
||||
# do what the daemon does, and then return the challenges instead
|
||||
# of returning proceed.
|
||||
r.proceed.timestamp = int(time.time())
|
||||
r.proceed.polldelay = 4
|
||||
r.proceed.polldelay = polldelay
|
||||
|
||||
def handleexistingsession(self, m, r):
|
||||
if m.request.IsInitialized():
|
||||
@@ -278,7 +283,7 @@ class session(object):
|
||||
# If we're in makechallenge or issue, tell the client to come back later.
|
||||
if state == "makechallenge" or state == "issue":
|
||||
r.proceed.timestamp = int(time.time())
|
||||
r.proceed.polldelay = 4
|
||||
r.proceed.polldelay = polldelay
|
||||
return
|
||||
# If we're in testchallenge, tell the client about the challenges and their
|
||||
# current status.
|
||||
|
||||
Reference in New Issue
Block a user