Statistics
| Branch: | Tag: | Revision:

root / lib / utils / security.py @ a6c43c02

History | View | Annotate | Download (4.7 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

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

    
35

    
36
def AddNodeToCandidateCerts(node_uuid, cert_digest, candidate_certs,
37
                            info_fn=logging.info, warn_fn=logging.warn):
38
  """Adds an entry to the candidate certificate map.
39

40
  @type node_uuid: string
41
  @param node_uuid: the node's UUID
42
  @type cert_digest: string
43
  @param cert_digest: the digest of the node's client SSL certificate
44
  @type candidate_certs: dict of strings to strings
45
  @param candidate_certs: map of node UUIDs to the digests of their client
46
      SSL certificates, will be manipulated in this function
47
  @type info_fn: function
48
  @param info_fn: logging function for information messages
49
  @type warn_fn: function
50
  @param warn_fn: logging function for warning messages
51

52
  """
53
  assert candidate_certs is not None
54

    
55
  if node_uuid in candidate_certs:
56
    old_cert_digest = candidate_certs[node_uuid]
57
    if old_cert_digest == cert_digest:
58
      info_fn("Certificate digest for node %s already in config."
59
              "Not doing anything." % node_uuid)
60
      return
61
    else:
62
      warn_fn("Overriding differing certificate digest for node %s"
63
              % node_uuid)
64
  candidate_certs[node_uuid] = cert_digest
65

    
66

    
67
def RemoveNodeFromCandidateCerts(node_uuid, candidate_certs,
68
                                 warn_fn=logging.warn):
69
  """Removes the entry of the given node in the certificate map.
70

71
  @type node_uuid: string
72
  @param node_uuid: the node's UUID
73
  @type candidate_certs: dict of strings to strings
74
  @param candidate_certs: map of node UUIDs to the digests of their client
75
      SSL certificates, will be manipulated in this function
76
  @type warn_fn: function
77
  @param warn_fn: logging function for warning messages
78

79
  """
80
  if node_uuid not in candidate_certs:
81
    warn_fn("Cannot remove certifcate for node %s, because it's not in the"
82
            "candidate map." % node_uuid)
83
    return
84
  del candidate_certs[node_uuid]
85

    
86

    
87
def GetCertificateDigest(cert_filename=pathutils.NODED_CLIENT_CERT_FILE):
88
  """Reads the SSL certificate and returns the sha1 digest.
89

90
  """
91
  cert_plain = io.ReadFile(cert_filename)
92
  cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
93
                                         cert_plain)
94
  return cert.digest("sha1")
95

    
96

    
97
def GenerateNewSslCert(new_cert, cert_filename, log_msg):
98
  """Creates a new SSL certificate and backups the old one.
99

100
  @type new_cert: boolean
101
  @param new_cert: whether a new certificate should be created
102
  @type cert_filename: string
103
  @param cert_filename: filename of the certificate file
104
  @type log_msg: string
105
  @param log_msg: log message to be written on certificate creation
106

107
  """
108
  cert_exists = os.path.exists(cert_filename)
109
  if new_cert or not cert_exists:
110
    if cert_exists:
111
      io.CreateBackup(cert_filename)
112

    
113
    logging.debug(log_msg)
114
    x509.GenerateSelfSignedSslCert(cert_filename)
115

    
116

    
117
def VerifyCertificate(filename):
118
  """Verifies a SSL certificate.
119

120
  @type filename: string
121
  @param filename: Path to PEM file
122

123
  """
124
  try:
125
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
126
                                           io.ReadFile(filename))
127
  except Exception, err: # pylint: disable=W0703
128
    return (constants.CV_ERROR,
129
            "Failed to load X509 certificate %s: %s" % (filename, err))
130

    
131
  (errcode, msg) = \
132
    x509.VerifyX509Certificate(cert, constants.SSL_CERT_EXPIRATION_WARN,
133
                                constants.SSL_CERT_EXPIRATION_ERROR)
134

    
135
  if msg:
136
    fnamemsg = "While verifying %s: %s" % (filename, msg)
137
  else:
138
    fnamemsg = None
139

    
140
  if errcode is None:
141
    return (None, fnamemsg)
142
  elif errcode == x509.CERT_WARNING:
143
    return (constants.CV_WARNING, fnamemsg)
144
  elif errcode == x509.CERT_ERROR:
145
    return (constants.CV_ERROR, fnamemsg)
146

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