1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 """Utility functions for security features of Ganeti.
31
32 """
33
34 import logging
35 import OpenSSL
36 import os
37 import uuid as uuid_module
38
39 from ganeti.utils import io
40 from ganeti.utils import x509
41 from ganeti import constants
42 from ganeti import errors
43 from ganeti import pathutils
44
45
47 uuid_obj = uuid_module.UUID(uuid)
48 return uuid_obj.int
49
50
51 -def AddNodeToCandidateCerts(node_uuid, cert_digest, candidate_certs,
52 info_fn=logging.info, warn_fn=logging.warn):
53 """Adds an entry to the candidate certificate map.
54
55 @type node_uuid: string
56 @param node_uuid: the node's UUID
57 @type cert_digest: string
58 @param cert_digest: the digest of the node's client SSL certificate
59 @type candidate_certs: dict of strings to strings
60 @param candidate_certs: map of node UUIDs to the digests of their client
61 SSL certificates, will be manipulated in this function
62 @type info_fn: function
63 @param info_fn: logging function for information messages
64 @type warn_fn: function
65 @param warn_fn: logging function for warning messages
66
67 """
68 assert candidate_certs is not None
69
70 if node_uuid in candidate_certs:
71 old_cert_digest = candidate_certs[node_uuid]
72 if old_cert_digest == cert_digest:
73 info_fn("Certificate digest for node %s already in config."
74 "Not doing anything." % node_uuid)
75 return
76 else:
77 warn_fn("Overriding differing certificate digest for node %s"
78 % node_uuid)
79 candidate_certs[node_uuid] = cert_digest
80
81
84 """Removes the entry of the given node in the certificate map.
85
86 @type node_uuid: string
87 @param node_uuid: the node's UUID
88 @type candidate_certs: dict of strings to strings
89 @param candidate_certs: map of node UUIDs to the digests of their client
90 SSL certificates, will be manipulated in this function
91 @type warn_fn: function
92 @param warn_fn: logging function for warning messages
93
94 """
95 if node_uuid not in candidate_certs:
96 warn_fn("Cannot remove certifcate for node %s, because it's not in the"
97 "candidate map." % node_uuid)
98 return
99 del candidate_certs[node_uuid]
100
101
103 """Reads the SSL certificate and returns the sha1 digest.
104
105 """
106 cert_plain = io.ReadFile(cert_filename)
107 cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
108 cert_plain)
109 return cert.digest("sha1")
110
111
114 """Creates a new SSL certificate and backups the old one.
115
116 @type new_cert: boolean
117 @param new_cert: whether a new certificate should be created
118 @type cert_filename: string
119 @param cert_filename: filename of the certificate file
120 @type serial_no: int
121 @param serial_no: serial number of the certificate
122 @type log_msg: string
123 @param log_msg: log message to be written on certificate creation
124 @type uid: int
125 @param uid: the user ID of the user who will be owner of the certificate file
126 @type gid: int
127 @param gid: the group ID of the group who will own the certificate file
128
129 """
130 cert_exists = os.path.exists(cert_filename)
131 if new_cert or not cert_exists:
132 if cert_exists:
133 io.CreateBackup(cert_filename)
134
135 logging.debug(log_msg)
136 x509.GenerateSelfSignedSslCert(cert_filename, serial_no, uid=uid, gid=gid)
137
138
140 """Verifies a SSL certificate.
141
142 @type filename: string
143 @param filename: Path to PEM file
144
145 """
146 try:
147 cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
148 io.ReadFile(filename))
149 except Exception, err:
150 return (constants.CV_ERROR,
151 "Failed to load X509 certificate %s: %s" % (filename, err))
152
153 (errcode, msg) = \
154 x509.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
155 constants.SSL_CERT_EXPIRATION_ERROR)
156
157 if msg:
158 fnamemsg = "While verifying %s: %s" % (filename, msg)
159 else:
160 fnamemsg = None
161
162 if errcode is None:
163 return (None, fnamemsg)
164 elif errcode == x509.CERT_WARNING:
165 return (constants.CV_WARNING, fnamemsg)
166 elif errcode == x509.CERT_ERROR:
167 return (constants.CV_ERROR, fnamemsg)
168
169 raise errors.ProgrammerError("Unhandled certificate error code %r" % errcode)
170