1#!/usr/bin/env python
2
3# Copyright (C) 2017 g10 Code GmbH
4#
5# This file is part of GPGME.
6#
7# GPGME is free software; you can redistribute it and/or modify it
8# under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# GPGME is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
15# Public License for more details.
16#
17# You should have received a copy of the GNU Lesser General Public
18# License along with this program; if not, see <https://www.gnu.org/licenses/>.
19
20from __future__ import absolute_import, print_function, unicode_literals
21
22import os
23import gpg
24import sys
25
26import support
27support.assert_gpg_version((2, 1, 14))
28
29del absolute_import, print_function, unicode_literals
30
31alpha = "Alpha <alpha@invalid.example.net>"
32bravo = "Bravo <bravo@invalid.example.net>"
33
34with support.EphemeralContext() as ctx:
35    res = ctx.create_key(alpha, certify=True)
36    key = ctx.get_key(res.fpr)
37    assert len(key.subkeys) == 1, "Expected one primary key and no subkeys"
38    assert len(key.uids) == 1, "Expected exactly one UID"
39
40    def get_uid(uid):
41        key = ctx.get_key(res.fpr)
42        for u in key.uids:
43            if u.uid == uid:
44                return u
45        return None
46
47    # sanity check
48    uid = get_uid(alpha)
49    assert uid, "UID alpha not found"
50    assert uid.revoked == 0
51
52    # add bravo
53    ctx.key_add_uid(key, bravo)
54    uid = get_uid(bravo)
55    assert uid, "UID bravo not found"
56    assert uid.revoked == 0
57
58    # revoke alpha
59    ctx.key_revoke_uid(key, alpha)
60    uid = get_uid(alpha)
61    assert uid, "UID alpha not found"
62    assert uid.revoked == 1
63    uid = get_uid(bravo)
64    assert uid, "UID bravo not found"
65    assert uid.revoked == 0
66
67    # try to revoke the last UID
68    try:
69        ctx.key_revoke_uid(key, alpha)
70        # IMHO this should fail.  issue2961.
71        # assert False, "Expected an error but got none"
72    except gpg.errors.GpgError:
73        pass
74
75    # Everything should be the same
76    uid = get_uid(alpha)
77    assert uid, "UID alpha not found"
78    assert uid.revoked == 1
79    uid = get_uid(bravo)
80    assert uid, "UID bravo not found"
81    assert uid.revoked == 0
82
83    # try to revoke a non-existent UID
84    try:
85        ctx.key_revoke_uid(key, "i don't exist")
86        # IMHO this should fail.  issue2963.
87        # assert False, "Expected an error but got none"
88    except gpg.errors.GpgError:
89        pass
90
91    # try to add an pre-existent UID
92    try:
93        ctx.key_add_uid(key, bravo)
94        assert False, "Expected an error but got none"
95    except gpg.errors.GpgError:
96        pass
97
98    # Check setting the TOFU policy.
99    with open(os.path.join(ctx.home_dir, "gpg.conf"), "a") as handle:
100        handle.write("trust-model tofu+pgp\n")
101
102    if not support.have_tofu_support(ctx, bravo):
103        print("GnuPG does not support TOFU, skipping TOFU tests.")
104        sys.exit()
105
106    for name, policy in [(name, getattr(gpg.constants.tofu.policy, name))
107                         for name in filter(lambda x: not x.startswith('__'),
108                                            dir(gpg.constants.tofu.policy))]:
109        if policy == gpg.constants.tofu.policy.NONE:
110            # We must not set the policy to NONE.
111            continue
112
113        ctx.key_tofu_policy(key, policy)
114
115        keys = list(
116            ctx.keylist(
117                key.uids[0].uid,
118                mode=(gpg.constants.keylist.mode.LOCAL |
119                      gpg.constants.keylist.mode.WITH_TOFU)))
120        assert len(keys) == 1
121
122        if policy == gpg.constants.tofu.policy.AUTO:
123            # We cannot check that it is set to AUTO.
124            continue
125
126        for uid in keys[0].uids:
127            if uid.uid == alpha:
128                # TOFU information of revoked UIDs is not updated.
129                # XXX: Is that expected?
130                continue
131            assert uid.tofu[0].policy == policy, \
132                "Expected policy {0} ({1}), got {2}".format(policy, name,
133                                                            uid.tofu[0].policy)
134