Blame lang/python/tests/t-quick-key-signing.py

Packit d7e8d0
#!/usr/bin/env python
Packit d7e8d0
Packit d7e8d0
# Copyright (C) 2017 g10 Code GmbH
Packit d7e8d0
#
Packit d7e8d0
# This file is part of GPGME.
Packit d7e8d0
#
Packit d7e8d0
# GPGME is free software; you can redistribute it and/or modify it
Packit d7e8d0
# under the terms of the GNU General Public License as published by
Packit d7e8d0
# the Free Software Foundation; either version 2 of the License, or
Packit d7e8d0
# (at your option) any later version.
Packit d7e8d0
#
Packit d7e8d0
# GPGME is distributed in the hope that it will be useful, but WITHOUT
Packit d7e8d0
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit d7e8d0
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
Packit d7e8d0
# Public License for more details.
Packit d7e8d0
#
Packit d7e8d0
# You should have received a copy of the GNU Lesser General Public
Packit d7e8d0
# License along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit d7e8d0
Packit d7e8d0
from __future__ import absolute_import, print_function, unicode_literals
Packit d7e8d0
del absolute_import, print_function, unicode_literals
Packit d7e8d0
Packit d7e8d0
import gpg
Packit d7e8d0
import itertools
Packit d7e8d0
import time
Packit d7e8d0
Packit d7e8d0
import support
Packit d7e8d0
support.assert_gpg_version((2, 1, 1))
Packit d7e8d0
Packit d7e8d0
with support.EphemeralContext() as ctx:
Packit d7e8d0
    uid_counter = 0
Packit d7e8d0
    def make_uid():
Packit d7e8d0
        global uid_counter
Packit d7e8d0
        uid_counter += 1
Packit d7e8d0
        return "user{0}@invalid.example.org".format(uid_counter)
Packit d7e8d0
Packit d7e8d0
    def make_key():
Packit d7e8d0
        uids = [make_uid() for i in range(3)]
Packit d7e8d0
        res = ctx.create_key(uids[0], certify=True)
Packit d7e8d0
        key = ctx.get_key(res.fpr)
Packit d7e8d0
        for u in uids[1:]:
Packit d7e8d0
            ctx.key_add_uid(key, u)
Packit d7e8d0
        return key, uids
Packit d7e8d0
Packit d7e8d0
    def check_sigs(key, expected_sigs):
Packit d7e8d0
        keys = list(ctx.keylist(key.fpr, mode=(gpg.constants.keylist.mode.LOCAL
Packit d7e8d0
                                               |gpg.constants.keylist.mode.SIGS)))
Packit d7e8d0
        assert len(keys) == 1
Packit d7e8d0
        key_uids = {uid.uid: [s for s in uid.signatures] for uid in keys[0].uids}
Packit d7e8d0
        expected = list(expected_sigs)
Packit d7e8d0
Packit d7e8d0
        while key_uids and expected:
Packit d7e8d0
            uid, signing_key, func = expected[0]
Packit d7e8d0
            match = False
Packit d7e8d0
            for i, s in enumerate(key_uids[uid]):
Packit d7e8d0
                if signing_key.fpr.endswith(s.keyid):
Packit d7e8d0
                    if func:
Packit d7e8d0
                        func(s)
Packit d7e8d0
                    match = True
Packit d7e8d0
                    break
Packit d7e8d0
            if match:
Packit d7e8d0
                expected.pop(0)
Packit d7e8d0
                key_uids[uid].pop(i)
Packit d7e8d0
                if not key_uids[uid]:
Packit d7e8d0
                    del key_uids[uid]
Packit d7e8d0
Packit d7e8d0
        assert not key_uids, "Superfluous signatures: {0}".format(key_uids)
Packit d7e8d0
        assert not expected, "Missing signatures: {0}".format(expected)
Packit d7e8d0
Packit d7e8d0
    # Simplest case.  Sign without any options.
Packit d7e8d0
    key_a, uids_a = make_key()
Packit d7e8d0
    key_b, uids_b = make_key()
Packit d7e8d0
    ctx.signers = [key_a]
Packit d7e8d0
Packit d7e8d0
    def exportable_non_expiring(s):
Packit d7e8d0
        assert s.exportable
Packit d7e8d0
        assert s.expires == 0
Packit d7e8d0
Packit d7e8d0
    check_sigs(key_b, itertools.product(uids_b, [key_b], [exportable_non_expiring]))
Packit d7e8d0
    ctx.key_sign(key_b)
Packit d7e8d0
    check_sigs(key_b, itertools.product(uids_b, [key_b, key_a], [exportable_non_expiring]))
Packit d7e8d0
Packit d7e8d0
    # Create a non-exportable signature, and explicitly name all uids.
Packit d7e8d0
    key_c, uids_c = make_key()
Packit d7e8d0
    ctx.signers = [key_a, key_b]
Packit d7e8d0
Packit d7e8d0
    def non_exportable_non_expiring(s):
Packit d7e8d0
        assert s.exportable == 0
Packit d7e8d0
        assert s.expires == 0
Packit d7e8d0
Packit d7e8d0
    ctx.key_sign(key_c, local=True, uids=uids_c)
Packit d7e8d0
    check_sigs(key_c,
Packit d7e8d0
               list(itertools.product(uids_c, [key_c],
Packit d7e8d0
                                      [exportable_non_expiring]))
Packit d7e8d0
               + list(itertools.product(uids_c, [key_b, key_a],
Packit d7e8d0
                                        [non_exportable_non_expiring])))
Packit d7e8d0
Packit d7e8d0
    # Create a non-exportable, expiring signature for a single uid.
Packit d7e8d0
    key_d, uids_d = make_key()
Packit d7e8d0
    ctx.signers = [key_c]
Packit d7e8d0
    expires_in = 600
Packit d7e8d0
    slack = 10
Packit d7e8d0
Packit d7e8d0
    def non_exportable_expiring(s):
Packit d7e8d0
        assert s.exportable == 0
Packit d7e8d0
        assert abs(time.time() + expires_in - s.expires) < slack
Packit d7e8d0
Packit d7e8d0
    ctx.key_sign(key_d, local=True, expires_in=expires_in, uids=uids_d[0])
Packit d7e8d0
    check_sigs(key_d,
Packit d7e8d0
               list(itertools.product(uids_d, [key_d],
Packit d7e8d0
                                      [exportable_non_expiring]))
Packit d7e8d0
               + list(itertools.product(uids_d[:1], [key_c],
Packit d7e8d0
                                        [non_exportable_expiring])))
Packit d7e8d0
Packit d7e8d0
    # Now sign the second in the same fashion, but use a singleton list.
Packit d7e8d0
    ctx.key_sign(key_d, local=True, expires_in=expires_in, uids=uids_d[1:2])
Packit d7e8d0
    check_sigs(key_d,
Packit d7e8d0
               list(itertools.product(uids_d, [key_d],
Packit d7e8d0
                                      [exportable_non_expiring]))
Packit d7e8d0
               + list(itertools.product(uids_d[:2], [key_c],
Packit d7e8d0
                                        [non_exportable_expiring])))