Possibilité de dropper à la volée un bad guy qui a laissé expirer sa clé.
This commit is contained in:
parent
8e3a76919c
commit
b522b4a741
1 changed files with 67 additions and 33 deletions
96
client.py
96
client.py
|
@ -52,7 +52,7 @@ NEWROLES = None
|
||||||
SERVER = None
|
SERVER = None
|
||||||
|
|
||||||
## GPG Definitions
|
## GPG Definitions
|
||||||
#: Path to gpg binary
|
#: Path du binaire gpg
|
||||||
GPG = '/usr/bin/gpg'
|
GPG = '/usr/bin/gpg'
|
||||||
|
|
||||||
#: Paramètres à fournir à gpg en fonction de l'action désirée
|
#: Paramètres à fournir à gpg en fonction de l'action désirée
|
||||||
|
@ -85,7 +85,7 @@ def gpg(command, args=None, verbose=False):
|
||||||
full_command.extend(GPG_ARGS[command])
|
full_command.extend(GPG_ARGS[command])
|
||||||
if args:
|
if args:
|
||||||
full_command.extend(args)
|
full_command.extend(args)
|
||||||
if verbose:
|
if verbose or VERB:
|
||||||
stderr = sys.stderr
|
stderr = sys.stderr
|
||||||
else:
|
else:
|
||||||
stderr = subprocess.PIPE
|
stderr = subprocess.PIPE
|
||||||
|
@ -95,7 +95,7 @@ def gpg(command, args=None, verbose=False):
|
||||||
stdout = subprocess.PIPE,
|
stdout = subprocess.PIPE,
|
||||||
stderr = stderr,
|
stderr = stderr,
|
||||||
close_fds = True)
|
close_fds = True)
|
||||||
if not verbose:
|
if not (verbose or VERB):
|
||||||
proc.stderr.close()
|
proc.stderr.close()
|
||||||
return proc.stdin, proc.stdout
|
return proc.stdin, proc.stdout
|
||||||
|
|
||||||
|
@ -315,41 +315,72 @@ def update_keys():
|
||||||
_, stdout = gpg("receive-keys", [key for _, key in keys.values() if key])
|
_, stdout = gpg("receive-keys", [key for _, key in keys.values() if key])
|
||||||
return stdout.read().decode("utf-8")
|
return stdout.read().decode("utf-8")
|
||||||
|
|
||||||
def check_keys():
|
def check_keys(recipients=None, interactive=False, drop_invalid=False):
|
||||||
"""Vérifie les clés existantes"""
|
"""Vérifie les clés, c'est-à-dire, si le mail est présent dans les identités du fingerprint,
|
||||||
if VERB:
|
et que la clé est de confiance (et non expirée/révoquée).
|
||||||
print("M : l'uid correspond au mail du fingerprint\nC : confiance OK (inclu la vérification de non expiration).\n")
|
|
||||||
|
* Si ``recipients`` est fourni, vérifie seulement ces recipients.
|
||||||
|
Renvoie la liste de ceux qu'on n'a pas droppés.
|
||||||
|
* Si ``interactive=True``, demandera confirmation pour dropper un recipient dont la clé est invalide.
|
||||||
|
* Sinon, et si ``drop_invalid=True``, droppe les recipients automatiquement.
|
||||||
|
* Si rien n'est fourni, vérifie toutes les clés et renvoie juste un booléen disant si tout va bien.
|
||||||
|
"""
|
||||||
|
if QUIET:
|
||||||
|
interactive = False
|
||||||
|
trusted_recipients = []
|
||||||
keys = all_keys()
|
keys = all_keys()
|
||||||
|
if recipients is None:
|
||||||
|
SPEAK = VERB
|
||||||
|
else:
|
||||||
|
SPEAK = False
|
||||||
|
keys = {u : val for (u, val) in keys.iteritems() if u in recipients}
|
||||||
|
if SPEAK:
|
||||||
|
print("M : le mail correspond à un uid du fingerprint\nC : confiance OK (inclut la vérification de non expiration).\n")
|
||||||
_, gpgout = gpg('list-keys')
|
_, gpgout = gpg('list-keys')
|
||||||
localring = parse_keys(gpgout)
|
localring = parse_keys(gpgout)
|
||||||
failed = False
|
for (recipient, (mail, fpr)) in keys.iteritems():
|
||||||
for (mail, fpr) in keys.values():
|
failed = u""
|
||||||
if fpr:
|
if not fpr is None:
|
||||||
if VERB:
|
if SPEAK:
|
||||||
print((u"Checking %s… " % (mail)).encode("utf-8"), end="")
|
print((u"Checking %s… " % (mail)).encode("utf-8"), end="")
|
||||||
key = localring.get(fpr, None)
|
key = localring.get(fpr, None)
|
||||||
# On vérifie qu'on possède la clé…
|
# On vérifie qu'on possède la clé…
|
||||||
if not key is None:
|
if not key is None:
|
||||||
# …qu'elle correspond au mail…
|
# …qu'elle correspond au mail…
|
||||||
if any([u"<%s>" % (mail,) in u["uid"] for u in key["uids"]]):
|
if any([u"<%s>" % (mail,) in u["uid"] for u in key["uids"]]):
|
||||||
if VERB:
|
if SPEAK:
|
||||||
print("M ", end="")
|
print("M ", end="")
|
||||||
meaning, trustvalue = GPG_TRUSTLEVELS[key["trustletter"]]
|
meaning, trustvalue = GPG_TRUSTLEVELS[key["trustletter"]]
|
||||||
# … et qu'on lui fait confiance
|
# … et qu'on lui fait confiance
|
||||||
if not trustvalue:
|
if not trustvalue:
|
||||||
print((u"--> Fail on %s:%s\nLa confiance en la clé est : %s" % (fpr, mail, meaning,)).encode("utf-8"))
|
failed = u"La confiance en la clé est : %s" % (meaning,)
|
||||||
failed = True
|
elif SPEAK:
|
||||||
elif VERB:
|
|
||||||
print("C ", end="")
|
print("C ", end="")
|
||||||
else:
|
else:
|
||||||
print((u"--> Fail on %s:%s\n!! Le fingerprint et le mail ne correspondent pas !" % (fpr, mail)).encode("utf-8"))
|
failed = u"!! Le fingerprint et le mail ne correspondent pas !"
|
||||||
failed = True
|
|
||||||
else:
|
else:
|
||||||
print((u"--> Fail on %s:%s\nPas (ou trop) de clé avec ce fingerprint." % (fpr, mail)).encode("utf-8"))
|
failed = u"Pas (ou trop) de clé avec ce fingerprint."
|
||||||
failed = True
|
if SPEAK:
|
||||||
if VERB:
|
|
||||||
print("")
|
print("")
|
||||||
return not failed
|
if failed:
|
||||||
|
if not QUIET:
|
||||||
|
print((u"--> Fail on %s:%s\n--> %s" % (mail, fpr, failed)).encode("utf-8"))
|
||||||
|
if not recipients is None:
|
||||||
|
# On cherche à savoir si on droppe ce recipient
|
||||||
|
drop = True # par défaut, on le drope
|
||||||
|
if interactive:
|
||||||
|
if not confirm(u"Abandonner le chiffrement pour cette clé ? (Si vous la conservez, il est posible que gpg crashe)"):
|
||||||
|
drop = False # sauf si on a répondu non à "abandonner ?"
|
||||||
|
elif not drop_invalid:
|
||||||
|
drop = False # ou bien si drop_invalid ne nous autorise pas à le dropper silencieusement
|
||||||
|
if not drop:
|
||||||
|
trusted_recipients.append(recipient)
|
||||||
|
else:
|
||||||
|
trusted_recipients.append(recipient)
|
||||||
|
if recipients is None:
|
||||||
|
return set(keys.keys()).issubset(trusted_recipients)
|
||||||
|
else:
|
||||||
|
return trusted_recipients
|
||||||
|
|
||||||
def get_recipients_of_roles(roles):
|
def get_recipients_of_roles(roles):
|
||||||
"""Renvoie les destinataires d'un rôle"""
|
"""Renvoie les destinataires d'un rôle"""
|
||||||
|
@ -366,11 +397,12 @@ def get_dest_of_roles(roles):
|
||||||
return [u"%s : %s (%s)" % (rec, allkeys[rec][0], allkeys[rec][1])
|
return [u"%s : %s (%s)" % (rec, allkeys[rec][0], allkeys[rec][1])
|
||||||
for rec in get_recipients_of_roles(roles) if allkeys[rec][1]]
|
for rec in get_recipients_of_roles(roles) if allkeys[rec][1]]
|
||||||
|
|
||||||
def encrypt(roles, contents):
|
def encrypt(roles, contents, interactive_trust=True, drop_invalid=False):
|
||||||
"""Chiffre ``contents`` pour les ``roles`` donnés"""
|
"""Chiffre le contenu pour les roles donnés"""
|
||||||
|
|
||||||
allkeys = all_keys()
|
allkeys = all_keys()
|
||||||
recipients = get_recipients_of_roles(roles)
|
recipients = get_recipients_of_roles(roles)
|
||||||
|
recipients = check_keys(recipients, interactive=interactive_trust, drop_invalid=drop_invalid)
|
||||||
fpr_recipients = []
|
fpr_recipients = []
|
||||||
for recipient in recipients:
|
for recipient in recipients:
|
||||||
fpr = allkeys[recipient][1]
|
fpr = allkeys[recipient][1]
|
||||||
|
@ -394,10 +426,10 @@ def decrypt(contents):
|
||||||
stdin.close()
|
stdin.close()
|
||||||
return stdout.read().decode("utf-8")
|
return stdout.read().decode("utf-8")
|
||||||
|
|
||||||
def put_password(name, roles, contents):
|
def put_password(name, roles, contents, interactive_trust=True, drop_invalid=False):
|
||||||
"""Dépose le mot de passe après l'avoir chiffré pour les
|
"""Dépose le mot de passe après l'avoir chiffré pour les
|
||||||
destinataires donnés"""
|
destinataires donnés"""
|
||||||
success, enc_pwd_or_error = encrypt(roles, contents)
|
success, enc_pwd_or_error = encrypt(roles, contents, interactive_trust, drop_invalid)
|
||||||
if NEWROLES != None:
|
if NEWROLES != None:
|
||||||
roles = NEWROLES
|
roles = NEWROLES
|
||||||
if VERB:
|
if VERB:
|
||||||
|
@ -521,7 +553,7 @@ def show_file(fname):
|
||||||
os.waitpid(proc.pid, 0)
|
os.waitpid(proc.pid, 0)
|
||||||
|
|
||||||
|
|
||||||
def edit_file(fname):
|
def edit_file(fname, interactive_trust=True, drop_invalid=False):
|
||||||
"""Modifie/Crée un fichier"""
|
"""Modifie/Crée un fichier"""
|
||||||
gotit, value = get_files([fname])[0]
|
gotit, value = get_files([fname])[0]
|
||||||
nfile = False
|
nfile = False
|
||||||
|
@ -567,14 +599,14 @@ C'est-à-dire pour les utilisateurs suivants :\n%s""" % (
|
||||||
print(u"Pas de modification effectuée".encode("utf-8"))
|
print(u"Pas de modification effectuée".encode("utf-8"))
|
||||||
else:
|
else:
|
||||||
ntexte = texte if ntexte == None else ntexte
|
ntexte = texte if ntexte == None else ntexte
|
||||||
success, message = put_password(fname, value['roles'], ntexte)
|
success, message = put_password(fname, value['roles'], ntexte, interactive_trust, drop_invalid)
|
||||||
print(message.encode("utf-8"))
|
print(message.encode("utf-8"))
|
||||||
|
|
||||||
def confirm(text):
|
def confirm(text):
|
||||||
"""Demande confirmation, sauf si on est mode ``FORCED``"""
|
"""Demande confirmation, sauf si on est mode ``FORCED``"""
|
||||||
if FORCED: return True
|
if FORCED: return True
|
||||||
while True:
|
while True:
|
||||||
out = raw_input((text + u' (O/N)').encode("utf-8")).lower()
|
out = raw_input((text + u' (o/n)').encode("utf-8")).lower()
|
||||||
if out == 'o':
|
if out == 'o':
|
||||||
return True
|
return True
|
||||||
elif out == 'n':
|
elif out == 'n':
|
||||||
|
@ -597,7 +629,7 @@ def my_update_keys():
|
||||||
"""Met à jour les clés existantes et affiche le résultat"""
|
"""Met à jour les clés existantes et affiche le résultat"""
|
||||||
print(update_keys().encode("utf-8"))
|
print(update_keys().encode("utf-8"))
|
||||||
|
|
||||||
def recrypt_files():
|
def recrypt_files(interactive_trust=False, drop_invalid=True):
|
||||||
"""Rechiffre les fichiers"""
|
"""Rechiffre les fichiers"""
|
||||||
# Ici, la signification de NEWROLES est : on ne veut rechiffrer que les fichiers qui ont au moins un de ces roles
|
# Ici, la signification de NEWROLES est : on ne veut rechiffrer que les fichiers qui ont au moins un de ces roles
|
||||||
rechiffre_roles = NEWROLES
|
rechiffre_roles = NEWROLES
|
||||||
|
@ -708,7 +740,9 @@ if __name__ == "__main__":
|
||||||
help="Lister les serveurs")
|
help="Lister les serveurs")
|
||||||
action_grp.add_argument('--recrypt-files', action='store_const', dest='action',
|
action_grp.add_argument('--recrypt-files', action='store_const', dest='action',
|
||||||
default=show_file, const=recrypt_files,
|
default=show_file, const=recrypt_files,
|
||||||
help="Rechiffrer les mots de passe. (Avec les mêmes rôles qu'avant, sert à rajouter un lecteur)")
|
help="""Rechiffrer les mots de passe.
|
||||||
|
(Avec les mêmes rôles que ceux qu'ils avant.
|
||||||
|
Cela sert à mettre à jour les recipients pour qui un password est chiffré)""")
|
||||||
|
|
||||||
parser.add_argument('--roles', nargs='?', default=None,
|
parser.add_argument('--roles', nargs='?', default=None,
|
||||||
help="""Liste de roles (séparés par des virgules).
|
help="""Liste de roles (séparés par des virgules).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue