3bb40325fcb1a00af800fbca94d78eb20f29a7d8
[keymanager.git] / src / leap / keymanager / validation.py
1 # -*- coding: utf-8 -*-
2 # __init__.py
3 # Copyright (C) 2014 LEAP
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 """
19 Validation levels implementation for key managment.
20
21 See:
22     https://leap.se/en/docs/design/transitional-key-validation
23 """
24
25
26 from datetime import datetime
27
28
29 class ValidationLevel(object):
30     """
31     A validation level
32
33     Meant to be used to compare levels or get it's string representation.
34     """
35     def __init__(self, name, value):
36         self.name = name
37         self.value = value
38
39     def __cmp__(self, other):
40         return cmp(self.value, other.value)
41
42     def __str__(self):
43         return self.name
44
45     def __repr__(self):
46         return "<ValidationLevel: %s (%d)>" % (self.name, self.value)
47
48
49 class _ValidationLevels(object):
50     """
51     Handler class to manage validation levels. It should have only one global
52     instance 'ValidationLevels'.
53
54     The levels are attributes of the instance and can be used like:
55        ValidationLevels.Weak_Chain
56        ValidationLevels.get("Weak_Chain")
57     """
58     _level_names = ("Weak_Chain",
59                     "Provider_Trust",
60                     "Provider_Endorsement",
61                     "Third_Party_Endorsement",
62                     "Third_Party_Consensus",
63                     "Historically_Auditing",
64                     "Known_Key",
65                     "Fingerprint")
66
67     def __init__(self):
68         for name in self._level_names:
69             setattr(self, name,
70                     ValidationLevel(name, self._level_names.index(name)))
71
72     def get(self, name):
73         """
74         Get the ValidationLevel of a name
75
76         :param name: name of the level
77         :type name: str
78         :rtype: ValidationLevel
79         """
80         return getattr(self, name)
81
82
83 ValidationLevels = _ValidationLevels()
84
85
86 def can_upgrade(new_key, old_key):
87     """
88     :type new_key: EncryptionKey
89     :type old_key: EncryptionKey
90     :rtype: bool
91     """
92     # First contact
93     if old_key is None:
94         return True
95
96     # An update of the same key
97     if new_key.fingerprint == old_key.fingerprint:
98         return True
99
100     # Manually verified fingerprint
101     if new_key.validation == ValidationLevels.Fingerprint:
102         return True
103
104     # Expired key and higher validation level
105     if (old_key.expiry_date is not None and
106             old_key.expiry_date < datetime.now() and
107             new_key.validation >= old_key.validation):
108         return True
109
110     # No expiration date and higher validation level
111     if (old_key.expiry_date is None and
112             new_key.validation > old_key.validation):
113         return True
114
115     # Not successfully used and strict high validation level
116     if (not (old_key.sign_used and old_key.encr_used) and
117             new_key.validation > old_key.validation):
118         return True
119
120     # New key signed by the old key
121     if old_key.key_id in new_key.signatures:
122         return True
123
124     return False