Harden It's Dangerous key management.
The previous code was theoretically subject to timing attacks, where an attacker could read the key in between the time it was saved to the file and when the chmod happened. This version prevents that by using umasks to ensure the files always have the right permissions. This version also avoids using a key that cannot be saved due to some system setup bug.
This commit is contained in:
parent
e84e1cdf12
commit
09102e0767
@ -14,10 +14,12 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os.path
|
import errno
|
||||||
import logging
|
|
||||||
import random
|
|
||||||
import itsdangerous
|
import itsdangerous
|
||||||
|
import logging
|
||||||
|
import os.path
|
||||||
|
import random
|
||||||
|
import tempfile
|
||||||
from mediagoblin import mg_globals
|
from mediagoblin import mg_globals
|
||||||
|
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
@ -25,33 +27,56 @@ _log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# Use the system (hardware-based) random number generator if it exists.
|
# Use the system (hardware-based) random number generator if it exists.
|
||||||
# -- this optimization is lifted from Django
|
# -- this optimization is lifted from Django
|
||||||
if hasattr(random, 'SystemRandom'):
|
try:
|
||||||
getrandbits = random.SystemRandom().getrandbits
|
getrandbits = random.SystemRandom().getrandbits
|
||||||
else:
|
except AttributeError:
|
||||||
getrandbits = random.getrandbits
|
getrandbits = random.getrandbits
|
||||||
|
|
||||||
|
|
||||||
__itsda_secret = None
|
__itsda_secret = None
|
||||||
|
|
||||||
|
|
||||||
|
def load_key(filename):
|
||||||
|
global __itsda_secret
|
||||||
|
key_file = open(filename)
|
||||||
|
try:
|
||||||
|
__itsda_secret = key_file.read()
|
||||||
|
finally:
|
||||||
|
key_file.close()
|
||||||
|
|
||||||
|
def create_key(key_dir, key_filepath):
|
||||||
|
global __itsda_secret
|
||||||
|
old_umask = os.umask(077)
|
||||||
|
key_file = None
|
||||||
|
try:
|
||||||
|
if not os.path.isdir(key_dir):
|
||||||
|
os.makedirs(key_dir)
|
||||||
|
_log.info("Created %s", dirname)
|
||||||
|
key = str(getrandbits(192))
|
||||||
|
key_file = tempfile.NamedTemporaryFile(dir=key_dir, suffix='.bin',
|
||||||
|
delete=False)
|
||||||
|
key_file.write(key)
|
||||||
|
key_file.flush()
|
||||||
|
os.rename(key_file.name, key_filepath)
|
||||||
|
key_file.close()
|
||||||
|
finally:
|
||||||
|
os.umask(old_umask)
|
||||||
|
if (key_file is not None) and (not key_file.closed):
|
||||||
|
key_file.close()
|
||||||
|
os.unlink(key_file.name)
|
||||||
|
__itsda_secret = key
|
||||||
|
_log.info("Saved new key for It's Dangerous")
|
||||||
|
|
||||||
def setup_crypto():
|
def setup_crypto():
|
||||||
global __itsda_secret
|
global __itsda_secret
|
||||||
dir = mg_globals.app_config["crypto_path"]
|
key_dir = mg_globals.app_config["crypto_path"]
|
||||||
if not os.path.isdir(dir):
|
key_filepath = os.path.join(key_dir, 'itsdangeroussecret.bin')
|
||||||
os.makedirs(dir)
|
try:
|
||||||
os.chmod(dir, 0700)
|
load_key(key_filepath)
|
||||||
_log.info("Created %s", dir)
|
except IOError, error:
|
||||||
name = os.path.join(dir, "itsdangeroussecret.bin")
|
if error.errno != errno.ENOENT:
|
||||||
if os.path.exists(name):
|
raise
|
||||||
__itsda_secret = file(name, "r").read()
|
create_key(key_dir, key_filepath)
|
||||||
else:
|
|
||||||
__itsda_secret = str(getrandbits(192))
|
|
||||||
f = file(name, "w")
|
|
||||||
f.write(__itsda_secret)
|
|
||||||
f.close()
|
|
||||||
os.chmod(name, 0600)
|
|
||||||
_log.info("Created %s", name)
|
|
||||||
|
|
||||||
|
|
||||||
def get_timed_signer_url(namespace):
|
def get_timed_signer_url(namespace):
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user