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

Annotation 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 - (hide annotations) (download) (as text)
Sun Dec 22 04:27:52 2013 UTC (10 years, 7 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 charliebrady 1.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