1<?php
2
3/**
4 +-------------------------------------------------------------------------+
5 | Key class for the Enigma Plugin                                         |
6 |                                                                         |
7 | Copyright (C) The Roundcube Dev Team                                    |
8 |                                                                         |
9 | Licensed under the GNU General Public License version 3 or              |
10 | any later version with exceptions for skins & plugins.                  |
11 | See the README file for a full license statement.                       |
12 +-------------------------------------------------------------------------+
13 | Author: Aleksander Machniak <alec@alec.pl>                              |
14 +-------------------------------------------------------------------------+
15*/
16
17class enigma_key
18{
19    public $id;
20    public $name;
21    public $users   = [];
22    public $subkeys = [];
23    public $reference;
24    public $password;
25
26    const TYPE_UNKNOWN = 0;
27    const TYPE_KEYPAIR = 1;
28    const TYPE_PUBLIC  = 2;
29
30    const CAN_ENCRYPT      = 1;
31    const CAN_SIGN         = 2;
32    const CAN_CERTIFY      = 4;
33    const CAN_AUTHENTICATE = 8;
34
35
36    /**
37     * Keys list sorting callback for usort()
38     */
39    static function cmp($a, $b)
40    {
41        return strcmp($a->name, $b->name);
42    }
43
44    /**
45     * Returns key type
46     *
47     * @return int One of self::TYPE_* constant values
48     */
49    function get_type()
50    {
51        if (!empty($this->subkeys[0]) && $this->subkeys[0]->has_private) {
52            return enigma_key::TYPE_KEYPAIR;
53        }
54        else if (!empty($this->subkeys[0])) {
55            return enigma_key::TYPE_PUBLIC;
56        }
57
58        return enigma_key::TYPE_UNKNOWN;
59    }
60
61    /**
62     * Returns true if all subkeys are revoked
63     *
64     * @return bool
65     */
66    function is_revoked()
67    {
68        foreach ($this->subkeys as $subkey) {
69            if (!$subkey->revoked) {
70                return false;
71            }
72        }
73
74        return !empty($this->subkeys);
75    }
76
77    /**
78     * Returns true if any user ID is valid
79     *
80     * @return bool
81     */
82    function is_valid()
83    {
84        foreach ($this->users as $user) {
85            if ($user->valid) {
86                return true;
87            }
88        }
89
90        return false;
91    }
92
93    /**
94     * Returns true if any of subkeys is a private key
95     *
96     * @return bool
97     */
98    function is_private()
99    {
100        foreach ($this->subkeys as $subkey) {
101            if ($subkey->has_private) {
102                return true;
103            }
104        }
105
106        return false;
107    }
108
109    /**
110     * Get key ID by user email
111     *
112     * @param string $email Email address
113     * @param int    $mode  Key mode (see self::CAN_* constants)
114     *
115     * @return enigma_subkey|null Subkey object
116     */
117    function find_subkey($email, $mode)
118    {
119        foreach ($this->users as $user) {
120            if (strcasecmp($user->email, $email) === 0 && $user->valid && !$user->revoked) {
121                foreach ($this->subkeys as $subkey) {
122                    if (!$subkey->revoked && !$subkey->is_expired()) {
123                        if ($subkey->usage & $mode) {
124                            return $subkey;
125                        }
126                    }
127                }
128            }
129        }
130    }
131
132    /**
133     * Converts long ID or Fingerprint to short ID
134     * Crypt_GPG uses internal, but e.g. Thunderbird's Enigmail displays short ID
135     *
136     * @param string $id Key ID or fingerprint
137     *
138     * @return string Key short ID
139     */
140    static function format_id($id)
141    {
142        // E.g. 04622F2089E037A5 => 89E037A5
143
144        return substr($id, -8);
145    }
146
147    /**
148     * Formats fingerprint string
149     *
150     * @param string $fingerprint Key fingerprint
151     *
152     * @return string Formatted fingerprint (with spaces)
153     */
154    static function format_fingerprint($fingerprint)
155    {
156        if (!$fingerprint) {
157            return '';
158        }
159
160        $result = '';
161        for ($i=0; $i<40; $i++) {
162            if ($i % 4 == 0) {
163                $result .= ' ';
164            }
165            $result .= $fingerprint[$i];
166        }
167
168        return $result;
169    }
170}
171