Statistics
| Branch: | Tag: | Revision:

root / lib / utils / security.py @ f3aebf6f

History | View | Annotate | Download (4.9 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
  """Creates a new SSL certificate and backups the old one.
105

106
  @type new_cert: boolean
107
  @param new_cert: whether a new certificate should be created
108
  @type cert_filename: string
109
  @param cert_filename: filename of the certificate file
110
  @type serial_no: int
111
  @param serial_no: serial number of the certificate
112
  @type log_msg: string
113
  @param log_msg: log message to be written on certificate creation
114

115
  """
116
  cert_exists = os.path.exists(cert_filename)
117
  if new_cert or not cert_exists:
118
    if cert_exists:
119
      io.CreateBackup(cert_filename)
120

    
121
    logging.debug(log_msg)
122
    x509.GenerateSelfSignedSslCert(cert_filename, serial_no)
123

    
124

    
125
def VerifyCertificate(filename):
126
  """Verifies a SSL certificate.
127

128
  @type filename: string
129
  @param filename: Path to PEM file
130

131
  """
132
  try:
133
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
134
                                           io.ReadFile(filename))
135
  except Exception, err: # pylint: disable=W0703
136
    return (constants.CV_ERROR,
137
            "Failed to load X509 certificate %s: %s" % (filename, err))
138

    
139
  (errcode, msg) = \
140
    x509.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
141
                                constants.SSL_CERT_EXPIRATION_ERROR)
142

    
143
  if msg:
144
    fnamemsg = "While verifying %s: %s" % (filename, msg)
145
  else:
146
    fnamemsg = None
147

    
148
  if errcode is None:
149
    return (None, fnamemsg)
150
  elif errcode == x509.CERT_WARNING:
151
    return (constants.CV_WARNING, fnamemsg)
152
  elif errcode == x509.CERT_ERROR:
153
    return (constants.CV_ERROR, fnamemsg)
154

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