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 import time
39
40 from ganeti.utils import io
41 from ganeti.utils import x509
42 from ganeti import constants
43 from ganeti import errors
44 from ganeti import pathutils
45
46
48 uuid_obj = uuid_module.UUID(uuid)
49 return uuid_obj.int
50
51
53 """Reads the SSL certificate and returns the sha1 digest.
54
55 """
56 cert_plain = io.ReadFile(cert_filename)
57 cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
58 cert_plain)
59 return cert.digest("sha1")
60
61
64 """Creates a new server SSL certificate and backups the old one.
65
66 @type new_cert: boolean
67 @param new_cert: whether a new certificate should be created
68 @type cert_filename: string
69 @param cert_filename: filename of the certificate file
70 @type serial_no: int
71 @param serial_no: serial number of the certificate
72 @type log_msg: string
73 @param log_msg: log message to be written on certificate creation
74 @type uid: int
75 @param uid: the user ID of the user who will be owner of the certificate file
76 @type gid: int
77 @param gid: the group ID of the group who will own the certificate file
78
79 """
80 cert_exists = os.path.exists(cert_filename)
81 if new_cert or not cert_exists:
82 if cert_exists:
83 io.CreateBackup(cert_filename)
84
85 logging.debug(log_msg)
86 x509.GenerateSelfSignedSslCert(cert_filename, serial_no, uid=uid, gid=gid)
87
88
91 """Creates a new server SSL certificate and backups the old one.
92
93 @type cert_filename: string
94 @param cert_filename: filename of the certificate file
95 @type signing_cert_filename: string
96 @param signing_cert_filename: name of the certificate to be used for signing
97 @type hostname: string
98 @param hostname: name of the machine whose cert is created
99
100 """
101 serial_no = int(time.time())
102 x509.GenerateSignedSslCert(cert_filename, serial_no, signing_cert_filename,
103 common_name=hostname)
104
105
107 """Verifies a SSL certificate.
108
109 @type filename: string
110 @param filename: Path to PEM file
111
112 """
113 try:
114 cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
115 io.ReadFile(filename))
116 except Exception, err:
117 return (constants.CV_ERROR,
118 "Failed to load X509 certificate %s: %s" % (filename, err))
119
120 (errcode, msg) = \
121 x509.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
122 constants.SSL_CERT_EXPIRATION_ERROR)
123
124 if msg:
125 fnamemsg = "While verifying %s: %s" % (filename, msg)
126 else:
127 fnamemsg = None
128
129 if errcode is None:
130 return (None, fnamemsg)
131 elif errcode == x509.CERT_WARNING:
132 return (constants.CV_WARNING, fnamemsg)
133 elif errcode == x509.CERT_ERROR:
134 return (constants.CV_ERROR, fnamemsg)
135
136 raise errors.ProgrammerError("Unhandled certificate error code %r" % errcode)
137
138
140 """Checks whether the certificate issuer is the same as the owner.
141
142 Note that this does not actually verify the signature, it simply
143 compares the certificates common name and the issuer's common
144 name. This is sufficient, because now that Ganeti started creating
145 non-self-signed client-certificates, it uses their hostnames
146 as common names and thus they are distinguishable by common name
147 from the server certificates.
148
149 @type cert_filename: string
150 @param cert_filename: filename of the certificate to examine
151
152 """
153 try:
154 cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
155 io.ReadFile(cert_filename))
156 except Exception, err:
157 return (constants.CV_ERROR,
158 "Failed to load X509 certificate %s: %s" % (cert_filename, err))
159
160 if cert.get_subject().CN == cert.get_issuer().CN:
161 msg = "The certificate '%s' is self-signed. Please run 'gnt-cluster" \
162 " renew-crypto --new-node-certificates' to get a properly signed" \
163 " certificate." % cert_filename
164 return (constants.CV_WARNING, msg)
165
166 return (None, None)
167