Skip to content

Commit 3b4b4a5

Browse files
committed
Simplify temporary file creation
Switch to using NamedTemporaryFile and converge the key and certificate writes to a single function. They were identical except for the data they were copying in, so we move that to a higher-level function instead.
1 parent 145f36e commit 3b4b4a5

File tree

2 files changed

+27
-72
lines changed

2 files changed

+27
-72
lines changed

src/sscg/__init__.py

Lines changed: 17 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -17,52 +17,10 @@
1717
DEFAULT_KEY_STRENGTH = 2048 # 2048-bit encryption
1818
DEFAULT_HASH_ALG = "sha256"
1919

20-
def write_certificate(options, cert, destination):
21-
"""
22-
Write out the certificate to a temporary file first, then atomically copy
23-
it to the destination path. This will avoid race-condition bugs with
24-
checking for file presence and then writing to it. Note: this will clobber
25-
the destination path.
26-
"""
27-
28-
# Create the temporary file in the same directory as the destination
29-
# This ensures that we can atomically move it to the final name.
30-
31-
try:
32-
(fd, fpath) = tempfile.mkstemp(dir=os.path.dirname(destination))
33-
if options.debug:
34-
print(_("Creating temporary certificate file at {}").format(fpath))
35-
f = os.fdopen(fd, "w")
36-
37-
f.write(crypto.dump_certificate(options.cert_format, cert).decode("UTF-8"))
38-
f.close()
39-
except IOError:
40-
# Something went wrong. Remove the temporary file before failing.
41-
print(_("Could not write to {0}. Error: {1}").format(
42-
fpath, sys.exc_info()[1]),
43-
file=sys.stderr)
44-
os.unlink(fpath)
45-
raise
4620

47-
# Now atomically move the temporary file into place.
48-
# We use os.rename because this is guaranteed to be atomic if it succeeds
49-
# This operation can fail on some flavors of UNIX if the source and
50-
# destination are on different filesystems, but this should not be the case.
51-
try:
52-
if options.debug:
53-
print(_("Renaming {} to {}".format(fpath, destination)))
54-
os.rename(fpath, destination)
55-
except IOError:
56-
# Something went wrong. Remove the temporary file before failing.
57-
print(_("Could not rename to {0}. Error: {1}").format(
58-
destination, sys.exc_info()[1]))
59-
os.unlink(fpath)
60-
raise
61-
62-
63-
def write_certificate_key(options, key, destination, cipher=None, passphrase=None):
21+
def write_secure_file(options, destination, data):
6422
"""
65-
Write out the certificate key to a temporary file first, then atomically
23+
Write out the certificate or key to a temporary file first, then atomically
6624
copy it to the destination path. This will avoid race-condition bugs with
6725
checking for file presence and then writing to it. Note: this will clobber
6826
the destination path.
@@ -71,34 +29,26 @@ def write_certificate_key(options, key, destination, cipher=None, passphrase=Non
7129
# Create the temporary file in the same directory as the destination
7230
# This ensures that we can atomically move it to the final name.
7331

32+
f = tempfile.NamedTemporaryFile(dir=os.path.dirname(destination),
33+
delete=False)
7434
try:
75-
(fd, fpath) = tempfile.mkstemp(dir=os.path.dirname(destination))
76-
if options.debug:
77-
print(_("Creating temporary keyfile at {}").format(fpath))
78-
79-
f = os.fdopen(fd, "w")
80-
81-
f.write(crypto.dump_privatekey(options.cert_format, key, cipher, passphrase).decode("UTF-8"))
35+
f.write(data)
36+
f.flush()
37+
except IOError as e:
8238
f.close()
83-
except IOError:
84-
# Something went wrong. Remove the temporary file before failing.
85-
print(_("Could not write to {0}. Error: {1}").format(
86-
fpath, sys.exc_info()[1]),
87-
file=sys.stderr)
88-
os.unlink(fpath)
89-
raise
39+
os.unlink(f.name)
40+
raise Exception(_("Could not write to {0}. Error: {1}").format(f.name, e))
9041

9142
# Now atomically move the temporary file into place.
9243
# We use os.rename because this is guaranteed to be atomic if it succeeds
9344
# This operation can fail on some flavors of UNIX if the source and
9445
# destination are on different filesystems, but this should not be the case.
46+
if options.debug:
47+
print(_("Renaming {} to {}").format(f.name, destination))
48+
49+
f.close()
9550
try:
96-
if options.debug:
97-
print(_("Renaming {} to {}").format(fpath, destination))
98-
os.rename(fpath, destination)
99-
except IOError:
100-
# Something went wrong. Remove the temporary file before failing.
101-
print(_("Could not rename to {0}. Error: {1}").format(
102-
destination, sys.exc_info()[1]))
103-
os.unlink(fpath)
104-
raise
51+
os.rename(f.name, destination)
52+
except IOError as e:
53+
os.unlink(f.name)
54+
raise Exception(_("Could not rename to {0}. Error: {1}").format(destination, e))

src/sscg/main.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
from OpenSSL import crypto
77
from socket import gethostname
88
from sscg import DEFAULT_CA_CERT, DEFAULT_KEY_STRENGTH, DEFAULT_LIFESPAN, \
9-
DEFAULT_CERT_FORMAT, DEFAULT_HASH_ALG, write_certificate,\
10-
write_certificate_key
9+
DEFAULT_CERT_FORMAT, DEFAULT_HASH_ALG, write_secure_file
1110
from sscg.authority import create_temp_ca
1211
from sscg.service import create_service_cert
1312

@@ -138,13 +137,19 @@ def main():
138137

139138
try:
140139
# Write out the CA Certificate
141-
write_certificate(options, ca_cert, options.ca_file)
140+
write_secure_file(options,
141+
options.ca_file,
142+
crypto.dump_certificate(options.cert_format, ca_cert))
142143

143144
# Write out the Service Certificate
144-
write_certificate(options, svc_cert, options.cert_file)
145+
write_secure_file(options,
146+
options.cert_file,
147+
crypto.dump_certificate(options.cert_format, svc_cert))
145148

146149
# Write out the Service Private Key
147-
write_certificate_key(options, svc_key, options.cert_key_file)
150+
write_secure_file(options,
151+
options.cert_key_file,
152+
crypto.dump_privatekey(options.cert_format, svc_key))
148153
except:
149154
print (_("Error writing certificate files: {}").format(sys.exc_info()[1]),
150155
file=sys.stderr)

0 commit comments

Comments
 (0)