/[smeserver]/cdrom.image/sme9/updates/storage/formats/luks.py
ViewVC logotype

Contents of /cdrom.image/sme9/updates/storage/formats/luks.py

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Sun Dec 22 04:27:52 2013 UTC (10 years, 6 months ago) by wellsi
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-python
FILE REMOVED
anaconda updates now handled via patches

1 # luks.py
2 # Device format classes for anaconda's storage configuration module.
3 #
4 # Copyright (C) 2009 Red Hat, Inc.
5 #
6 # This copyrighted material is made available to anyone wishing to use,
7 # modify, copy, or redistribute it subject to the terms and conditions of
8 # the GNU General Public License v.2, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY expressed or implied, including the implied warranties of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 # Public License for more details. You should have received a copy of the
13 # GNU General Public License along with this program; if not, write to the
14 # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 # 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
16 # source code or documentation are not subject to the GNU General Public
17 # License and may only be used or replicated with the express permission of
18 # Red Hat, Inc.
19 #
20 # Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
21 #
22
23
24
25 import os
26
27 try:
28 import volume_key
29 except ImportError:
30 volume_key = None
31
32 from ..storage_log import log_method_call
33 from ..errors import *
34 from ..devicelibs import crypto
35 from . import DeviceFormat, register_device_format
36
37 import gettext
38 _ = lambda x: gettext.ldgettext("anaconda", x)
39
40 import logging
41 log = logging.getLogger("storage")
42
43
44 class LUKS(DeviceFormat):
45 """ A LUKS device. """
46 _type = "luks"
47 _name = "LUKS"
48 _lockedName = _("Encrypted")
49 _udevTypes = ["crypto_LUKS"]
50 _formattable = True # can be formatted
51 _supported = False # is supported
52 _linuxNative = True # for clearpart
53 _packages = ["cryptsetup-luks"] # required packages
54
55 def __init__(self, *args, **kwargs):
56 """ Create a LUKS instance.
57
58 Keyword Arguments:
59
60 device -- the path to the underlying device
61 name -- the name of the mapped device
62 uuid -- this device's UUID
63 passphrase -- device passphrase (string)
64 key_file -- path to a file containing a key (string)
65 cipher -- cipher mode string
66 key_size -- key size in bits
67 exists -- indicates whether this is an existing format
68 escrow_cert -- certificate to use for key escrow
69 add_backup_passphrase -- generate a backup passphrase?
70 """
71 log_method_call(self, *args, **kwargs)
72 DeviceFormat.__init__(self, *args, **kwargs)
73 self.cipher = kwargs.get("cipher")
74 self.key_size = kwargs.get("key_size")
75 self.mapName = kwargs.get("name")
76
77 if not self.exists and not self.cipher:
78 self.cipher = "aes-xts-plain64"
79 if not self.key_size:
80 # default to the max (512 bits) for aes-xts
81 self.key_size = 512
82
83 # FIXME: these should both be lists, but managing them will be a pain
84 self.__passphrase = kwargs.get("passphrase")
85 self._key_file = kwargs.get("key_file")
86 self.escrow_cert = kwargs.get("escrow_cert")
87 self.add_backup_passphrase = kwargs.get("add_backup_passphrase", False)
88
89 if not self.mapName and self.exists and self.uuid:
90 self.mapName = "luks-%s" % self.uuid
91 elif not self.mapName and self.device:
92 self.mapName = "luks-%s" % os.path.basename(self.device)
93
94 def __str__(self):
95 s = DeviceFormat.__str__(self)
96 if self.__passphrase:
97 passphrase = "(set)"
98 else:
99 passphrase = "(not set)"
100 s += (" cipher = %(cipher)s keySize = %(keySize)s"
101 " mapName = %(mapName)s\n"
102 " keyFile = %(keyFile)s passphrase = %(passphrase)s\n"
103 " escrowCert = %(escrowCert)s addBackup = %(backup)s" %
104 {"cipher": self.cipher, "keySize": self.key_size,
105 "mapName": self.mapName, "keyFile": self._key_file,
106 "passphrase": passphrase, "escrowCert": self.escrow_cert,
107 "backup": self.add_backup_passphrase})
108 return s
109
110 def writeKS(self, f):
111 f.write(" --encrypted")
112 if self.cipher:
113 f.write(" --cipher=\"%s\"" % self.cipher)
114
115 @property
116 def dict(self):
117 d = super(LUKS, self).dict
118 d.update({"cipher": self.cipher, "keySize": self.key_size,
119 "mapName": self.mapName, "hasKey": self.hasKey,
120 "escrowCert": self.escrow_cert,
121 "backup": self.add_backup_passphrase})
122 return d
123
124 @property
125 def name(self):
126 name = self._name
127 # for existing locked devices, show "Encrypted" instead of LUKS
128 if self.hasKey or not self.exists:
129 name = self._name
130 else:
131 name = "%s (%s)" % (self._lockedName, self._name)
132 return name
133
134 def _setPassphrase(self, passphrase):
135 """ Set the passphrase used to access this device. """
136 self.__passphrase = passphrase
137
138 passphrase = property(fset=_setPassphrase)
139
140 @property
141 def hasKey(self):
142 return (self.__passphrase or
143 (self._key_file and os.access(self._key_file, os.R_OK)))
144
145 @property
146 def configured(self):
147 """ To be ready we need a key or passphrase and a map name. """
148 return self.hasKey and self.mapName
149
150 @property
151 def status(self):
152 if not self.exists or not self.mapName:
153 return False
154 return os.path.exists("/dev/mapper/%s" % self.mapName)
155
156 def probe(self):
157 """ Probe for any missing information about this format.
158
159 cipher mode, key size
160 """
161 raise NotImplementedError("probe method not defined for LUKS")
162
163 def setup(self, *args, **kwargs):
164 """ Open, or set up, the format. """
165 log_method_call(self, device=self.device, mapName=self.mapName,
166 type=self.type, status=self.status)
167 if not self.configured:
168 raise LUKSError("luks device not configured")
169
170 if self.status:
171 return
172
173 DeviceFormat.setup(self, *args, **kwargs)
174 crypto.luks_open(self.device, self.mapName,
175 passphrase=self.__passphrase,
176 key_file=self._key_file)
177
178 def teardown(self, *args, **kwargs):
179 """ Close, or tear down, the format. """
180 log_method_call(self, device=self.device,
181 type=self.type, status=self.status)
182 if not self.exists:
183 raise LUKSError("format has not been created")
184
185 if self.status:
186 log.debug("unmapping %s" % self.mapName)
187 crypto.luks_close(self.mapName)
188
189 def create(self, *args, **kwargs):
190 """ Create the format. """
191 log_method_call(self, device=self.device,
192 type=self.type, status=self.status)
193 if not self.hasKey:
194 raise LUKSError("luks device has no key/passphrase")
195
196 intf = kwargs.get("intf")
197 w = None
198 if intf:
199 w = intf.waitWindow(_("Formatting"),
200 _("Encrypting %s") % kwargs.get("device",
201 self.device))
202
203 try:
204 DeviceFormat.create(self, *args, **kwargs)
205 crypto.luks_format(self.device,
206 passphrase=self.__passphrase,
207 key_file=self._key_file,
208 cipher=self.cipher,
209 key_size=self.key_size)
210 except Exception:
211 raise
212 else:
213 self.uuid = crypto.luks_uuid(self.device)
214 self.exists = True
215 self.mapName = "luks-%s" % self.uuid
216 self.notifyKernel()
217 finally:
218 if w:
219 w.pop()
220
221 def destroy(self, *args, **kwargs):
222 """ Create the format. """
223 log_method_call(self, device=self.device,
224 type=self.type, status=self.status)
225 self.teardown()
226 DeviceFormat.destroy(self, *args, **kwargs)
227
228 @property
229 def keyFile(self):
230 """ Path to key file to be used in /etc/crypttab """
231 return self._key_file
232
233 def addKeyFromFile(self, keyfile):
234 """ Add a new key from a file.
235
236 Add the contents of the specified key file to an available key
237 slot in the LUKS header.
238 """
239 log_method_call(self, device=self.device,
240 type=self.type, status=self.status, file=keyfile)
241 if not self.exists:
242 raise LUKSError("format has not been created")
243
244 crypto.luks_add_key(self.device,
245 passphrase=self.__passphrase,
246 key_file=self._key_file,
247 new_key_file=keyfile)
248
249 def addPassphrase(self, passphrase):
250 """ Add a new passphrase.
251
252 Add the specified passphrase to an available key slot in the
253 LUKS header.
254 """
255 log_method_call(self, device=self.device,
256 type=self.type, status=self.status)
257 if not self.exists:
258 raise LUKSError("format has not been created")
259
260 crypto.luks_add_key(self.device,
261 passphrase=self.__passphrase,
262 key_file=self._key_file,
263 new_passphrase=passphrase)
264
265 def removeKeyFromFile(self, keyfile):
266 """ Remove a key contained in a file.
267
268 Remove key contained in the specified key file from the LUKS
269 header.
270 """
271 log_method_call(self, device=self.device,
272 type=self.type, status=self.status, file=keyfile)
273 if not self.exists:
274 raise LUKSError("format has not been created")
275
276 crypto.luks_remove_key(self.device,
277 passphrase=self.__passphrase,
278 key_file=self._key_file,
279 del_key_file=keyfile)
280
281
282 def removePassphrase(self, passphrase):
283 """ Remove the specified passphrase from the LUKS header. """
284 log_method_call(self, device=self.device,
285 type=self.type, status=self.status)
286 if not self.exists:
287 raise LUKSError("format has not been created")
288
289 crypto.luks_remove_key(self.device,
290 passphrase=self.__passphrase,
291 key_file=self._key_file,
292 del_passphrase=passphrase)
293
294 def _escrowVolumeIdent(self, vol):
295 """ Return an escrow packet filename prefix for a volume_key.Volume. """
296 label = vol.label
297 if label is not None:
298 label = label.replace("/", "_")
299 uuid = vol.uuid
300 if uuid is not None:
301 uuid = uuid.replace("/", "_")
302 # uuid is never None on LUKS volumes
303 if label is not None and uuid is not None:
304 volume_ident = "%s-%s" % (label, uuid)
305 elif uuid is not None:
306 volume_ident = uuid
307 elif label is not None:
308 volume_ident = label
309 else:
310 volume_ident = "_unknown"
311 return volume_ident
312
313 def escrow(self, directory, backupPassphrase):
314 log.debug("escrow: escrowVolume start for %s" % self.device)
315 if volume_key is None:
316 raise LUKSError("Missing key escrow support libraries")
317
318 vol = volume_key.Volume.open(self.device)
319 volume_ident = self._escrowVolumeIdent(vol)
320
321 ui = volume_key.UI()
322 # This callback is not expected to be used, let it always fail
323 ui.generic_cb = lambda unused_prompt, unused_echo: None
324 def known_passphrase_cb(unused_prompt, failed_attempts):
325 if failed_attempts == 0:
326 return self.__passphrase
327 return None
328 ui.passphrase_cb = known_passphrase_cb
329
330 log.debug("escrow: getting secret")
331 vol.get_secret(volume_key.SECRET_DEFAULT, ui)
332 log.debug("escrow: creating packet")
333 default_packet = vol.create_packet_assymetric_from_cert_data \
334 (volume_key.SECRET_DEFAULT, self.escrow_cert, ui)
335 log.debug("escrow: packet created")
336 with open("%s/%s-escrow" % (directory, volume_ident), "wb") as f:
337 f.write(default_packet)
338 log.debug("escrow: packet written")
339
340 if self.add_backup_passphrase:
341 log.debug("escrow: adding backup passphrase")
342 vol.add_secret(volume_key.SECRET_PASSPHRASE, backupPassphrase)
343 log.debug("escrow: creating backup packet")
344 backup_passphrase_packet = \
345 vol.create_packet_assymetric_from_cert_data \
346 (volume_key.SECRET_PASSPHRASE, self.escrow_cert, ui)
347 log.debug("escrow: backup packet created")
348 with open("%s/%s-escrow-backup-passphrase" %
349 (directory, volume_ident), "wb") as f:
350 f.write(backup_passphrase_packet)
351 log.debug("escrow: backup packet written")
352
353 log.debug("escrow: escrowVolume done for %s" % repr(self.device))
354
355
356 register_device_format(LUKS)
357

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed