Statistics
| Branch: | Tag: | Revision:

root / lib / utils / security.py @ 22114677

History | View | Annotate | Download (5.2 kB)

1
#
2
#
3

    
4
# Copyright (C) 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21
"""Utility functions for security features of Ganeti.
22

23
"""
24

    
25
import logging
26
import OpenSSL
27
import os
28
import uuid as uuid_module
29

    
30
from ganeti.utils import io
31
from ganeti.utils import x509
32
from ganeti import constants
33
from ganeti import errors
34
from ganeti import pathutils
35

    
36

    
37
def UuidToInt(uuid):
38
  uuid_obj = uuid_module.UUID(uuid)
39
  return uuid_obj.int # pylint: disable=E1101
40

    
41

    
42
def AddNodeToCandidateCerts(node_uuid, cert_digest, candidate_certs,
43
                            info_fn=logging.info, warn_fn=logging.warn):
44
  """Adds an entry to the candidate certificate map.
45

46
  @type node_uuid: string
47
  @param node_uuid: the node's UUID
48
  @type cert_digest: string
49
  @param cert_digest: the digest of the node's client SSL certificate
50
  @type candidate_certs: dict of strings to strings
51
  @param candidate_certs: map of node UUIDs to the digests of their client
52
      SSL certificates, will be manipulated in this function
53
  @type info_fn: function
54
  @param info_fn: logging function for information messages
55
  @type warn_fn: function
56
  @param warn_fn: logging function for warning messages
57

58
  """
59
  assert candidate_certs is not None
60

    
61
  if node_uuid in candidate_certs:
62
    old_cert_digest = candidate_certs[node_uuid]
63
    if old_cert_digest == cert_digest:
64
      info_fn("Certificate digest for node %s already in config."
65
              "Not doing anything." % node_uuid)
66
      return
67
    else:
68
      warn_fn("Overriding differing certificate digest for node %s"
69
              % node_uuid)
70
  candidate_certs[node_uuid] = cert_digest
71

    
72

    
73
def RemoveNodeFromCandidateCerts(node_uuid, candidate_certs,
74
                                 warn_fn=logging.warn):
75
  """Removes the entry of the given node in the certificate map.
76

77
  @type node_uuid: string
78
  @param node_uuid: the node's UUID
79
  @type candidate_certs: dict of strings to strings
80
  @param candidate_certs: map of node UUIDs to the digests of their client
81
      SSL certificates, will be manipulated in this function
82
  @type warn_fn: function
83
  @param warn_fn: logging function for warning messages
84

85
  """
86
  if node_uuid not in candidate_certs:
87
    warn_fn("Cannot remove certifcate for node %s, because it's not in the"
88
            "candidate map." % node_uuid)
89
    return
90
  del candidate_certs[node_uuid]
91

    
92

    
93
def GetCertificateDigest(cert_filename=pathutils.NODED_CLIENT_CERT_FILE):
94
  """Reads the SSL certificate and returns the sha1 digest.
95

96
  """
97
  cert_plain = io.ReadFile(cert_filename)
98
  cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
99
                                         cert_plain)
100
  return cert.digest("sha1")
101

    
102

    
103
def GenerateNewSslCert(new_cert, cert_filename, serial_no, log_msg,
104
                       uid=-1, gid=-1):
105
  """Creates a new SSL certificate and backups the old one.
106

107
  @type new_cert: boolean
108
  @param new_cert: whether a new certificate should be created
109
  @type cert_filename: string
110
  @param cert_filename: filename of the certificate file
111
  @type serial_no: int
112
  @param serial_no: serial number of the certificate
113
  @type log_msg: string
114
  @param log_msg: log message to be written on certificate creation
115
  @type uid: int
116
  @param uid: the user ID of the user who will be owner of the certificate file
117
  @type gid: int
118
  @param gid: the group ID of the group who will own the certificate file
119

120
  """
121
  cert_exists = os.path.exists(cert_filename)
122
  if new_cert or not cert_exists:
123
    if cert_exists:
124
      io.CreateBackup(cert_filename)
125

    
126
    logging.debug(log_msg)
127
    x509.GenerateSelfSignedSslCert(cert_filename, serial_no, uid=uid, gid=gid)
128

    
129

    
130
def VerifyCertificate(filename):
131
  """Verifies a SSL certificate.
132

133
  @type filename: string
134
  @param filename: Path to PEM file
135

136
  """
137
  try:
138
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
139
                                           io.ReadFile(filename))
140
  except Exception, err: # pylint: disable=W0703
141
    return (constants.CV_ERROR,
142
            "Failed to load X509 certificate %s: %s" % (filename, err))
143

    
144
  (errcode, msg) = \
145
    x509.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
146
                                constants.SSL_CERT_EXPIRATION_ERROR)
147

    
148
  if msg:
149
    fnamemsg = "While verifying %s: %s" % (filename, msg)
150
  else:
151
    fnamemsg = None
152

    
153
  if errcode is None:
154
    return (None, fnamemsg)
155
  elif errcode == x509.CERT_WARNING:
156
    return (constants.CV_WARNING, fnamemsg)
157
  elif errcode == x509.CERT_ERROR:
158
    return (constants.CV_ERROR, fnamemsg)
159

    
160
  raise errors.ProgrammerError("Unhandled certificate error code %r" % errcode)