2 * sigcheck.c - routines to check OpenPGP signatures
4 * Copyright 2012 Jonathan McDowell <noodles@earth.li>
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <https://www.gnu.org/licenses/>.
21 #include "build-config.h"
22 #include "decodekey.h"
24 #include "keystructs.h"
30 #include <nettle/md5.h>
31 #include <nettle/ripemd160.h>
32 #include <nettle/sha.h>
39 int check_packet_sighash(struct openpgp_publickey *key,
40 struct openpgp_packet *packet,
41 struct openpgp_packet *sig)
45 size_t siglen, unhashedlen;
46 struct sha1_ctx sha1_context;
47 struct sha1x_ctx sha1x_context;
48 struct md5_ctx md5_context;
50 struct ripemd160_ctx ripemd160_context;
51 struct sha224_ctx sha224_context;
52 struct sha256_ctx sha256_context;
53 struct sha384_ctx sha384_context;
54 struct sha512_ctx sha512_context;
57 uint8_t packetheader[5];
66 switch (sig->data[0]) {
70 keyheader[1] = key->publickey->length >> 8;
71 keyheader[2] = key->publickey->length & 0xFF;
72 hashdata[0] = keyheader;
74 hashdata[1] = key->publickey->data;
75 hashlen[1] = key->publickey->length;
78 hashtype = sig->data[16];
81 if (packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
82 packetheader[0] = 0x99;
83 packetheader[1] = packet->length >> 8;
84 packetheader[2] = packet->length & 0xFF;
85 hashdata[chunks] = packetheader;
90 // TODO: Things other than UIDS/subkeys?
91 hashdata[chunks] = packet->data;
92 hashlen[chunks] = packet->length;
96 hashdata[chunks] = &sig->data[2];
99 sighash = &sig->data[17];
103 keyheader[1] = key->publickey->length >> 8;
104 keyheader[2] = key->publickey->length & 0xFF;
105 hashdata[0] = keyheader;
107 hashdata[1] = key->publickey->data;
108 hashlen[1] = key->publickey->length;
111 hashtype = sig->data[3];
113 /* Check to see if this is an X509 based signature */
114 if (sig->data[2] == 0 || sig->data[2] == 100) {
118 res = parse_subpackets(&sig->data[4],
119 sig->length - 4, &len,
121 if (res != ONAK_E_OK) {
122 /* If it parses badly, reject it */
126 /* No unhashed data */
127 sig->data[4 + len] == 0 &&
128 sig->data[5 + len] == 0 &&
129 /* Dummy 0 checksum */
130 sig->data[6 + len] == 0 &&
131 sig->data[7 + len] == 0 &&
133 sig->data[8 + len] == 0 &&
134 sig->data[9 + len] == 1 &&
135 sig->data[10 + len] == 1) {
136 get_keyid(key, &keyid);
137 logthing(LOGTHING_DEBUG,
138 "Skipping X509 signature on 0x%016"
145 if (packet != NULL) {
146 if (packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
147 packetheader[0] = 0x99;
148 packetheader[1] = packet->length >> 8;
149 packetheader[2] = packet->length & 0xFF;
150 hashdata[chunks] = packetheader;
153 } else if (packet->tag == OPENPGP_PACKET_UID ||
154 packet->tag == OPENPGP_PACKET_UAT) {
155 packetheader[0] = (packet->tag ==
156 OPENPGP_PACKET_UID) ? 0xB4 : 0xD1;
157 packetheader[1] = packet->length >> 24;
158 packetheader[2] = (packet->length >> 16) & 0xFF;
159 packetheader[3] = (packet->length >> 8) & 0xFF;
160 packetheader[4] = packet->length & 0xFF;
161 hashdata[chunks] = packetheader;
165 hashdata[chunks] = packet->data;
166 hashlen[chunks] = packet->length;
170 hashdata[chunks] = sig->data;
171 hashlen[chunks] = siglen = (sig->data[4] << 8) +
173 if (siglen > sig->length) {
174 /* Signature data exceed packet length, bogus */
181 trailer[2] = siglen >> 24;
182 trailer[3] = (siglen >> 16) & 0xFF;
183 trailer[4] = (siglen >> 8) & 0xFF;
184 trailer[5] = siglen & 0xFF;
185 hashdata[chunks] = trailer;
189 unhashedlen = (sig->data[siglen] << 8) +
190 sig->data[siglen + 1];
191 sighash = &sig->data[siglen + unhashedlen + 2];
197 keyheader[3] = key->publickey->length >> 8;
198 keyheader[4] = key->publickey->length & 0xFF;
199 hashdata[0] = keyheader;
201 hashdata[1] = key->publickey->data;
202 hashlen[1] = key->publickey->length;
205 hashtype = sig->data[3];
207 if (packet != NULL) {
208 if (packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
209 packetheader[0] = 0x9A;
212 packetheader[3] = packet->length >> 8;
213 packetheader[4] = packet->length & 0xFF;
214 hashdata[chunks] = packetheader;
217 } else if (packet->tag == OPENPGP_PACKET_UID ||
218 packet->tag == OPENPGP_PACKET_UAT) {
219 packetheader[0] = (packet->tag ==
220 OPENPGP_PACKET_UID) ? 0xB4 : 0xD1;
221 packetheader[1] = packet->length >> 24;
222 packetheader[2] = (packet->length >> 16) & 0xFF;
223 packetheader[3] = (packet->length >> 8) & 0xFF;
224 packetheader[4] = packet->length & 0xFF;
225 hashdata[chunks] = packetheader;
229 hashdata[chunks] = packet->data;
230 hashlen[chunks] = packet->length;
234 hashdata[chunks] = sig->data;
235 hashlen[chunks] = siglen = (sig->data[4] << 8) +
237 if (siglen > sig->length) {
238 /* Signature data exceed packet length, bogus */
249 trailer[6] = siglen >> 24;
250 trailer[7] = (siglen >> 16) & 0xFF;
251 trailer[8] = (siglen >> 8) & 0xFF;
252 trailer[9] = siglen & 0xFF;
253 hashdata[chunks] = trailer;
254 hashlen[chunks] = 10;
257 unhashedlen = (sig->data[siglen] << 8) +
258 sig->data[siglen + 1];
259 sighash = &sig->data[siglen + unhashedlen + 2];
262 get_keyid(key, &keyid);
263 logthing(LOGTHING_ERROR,
264 "Unknown signature version %d on 0x%016" PRIX64,
265 sig->data[0], keyid);
270 case OPENPGP_HASH_MD5:
271 md5_init(&md5_context);
272 for (i = 0; i < chunks; i++) {
273 md5_update(&md5_context, hashlen[i], hashdata[i]);
275 md5_digest(&md5_context, 16, hash);
277 case OPENPGP_HASH_SHA1:
278 sha1_init(&sha1_context);
279 for (i = 0; i < chunks; i++) {
280 sha1_update(&sha1_context, hashlen[i], hashdata[i]);
282 sha1_digest(&sha1_context, 20, hash);
284 case OPENPGP_HASH_SHA1X:
285 sha1x_init(&sha1x_context);
286 for (i = 0; i < chunks; i++) {
287 sha1x_update(&sha1x_context, hashlen[i], hashdata[i]);
289 sha1x_digest(&sha1x_context, 20, hash);
292 case OPENPGP_HASH_RIPEMD160:
293 ripemd160_init(&ripemd160_context);
294 for (i = 0; i < chunks; i++) {
295 ripemd160_update(&ripemd160_context, hashlen[i],
298 ripemd160_digest(&ripemd160_context, RIPEMD160_DIGEST_SIZE,
301 case OPENPGP_HASH_SHA224:
302 sha224_init(&sha224_context);
303 for (i = 0; i < chunks; i++) {
304 sha224_update(&sha224_context, hashlen[i],
307 sha224_digest(&sha224_context, SHA224_DIGEST_SIZE, hash);
309 case OPENPGP_HASH_SHA256:
310 sha256_init(&sha256_context);
311 for (i = 0; i < chunks; i++) {
312 sha256_update(&sha256_context, hashlen[i],
315 sha256_digest(&sha256_context, SHA256_DIGEST_SIZE, hash);
317 case OPENPGP_HASH_SHA384:
318 sha384_init(&sha384_context);
319 for (i = 0; i < chunks; i++) {
320 sha384_update(&sha384_context, hashlen[i],
323 sha384_digest(&sha384_context, SHA384_DIGEST_SIZE, hash);
325 case OPENPGP_HASH_SHA512:
326 sha512_init(&sha512_context);
327 for (i = 0; i < chunks; i++) {
328 sha512_update(&sha512_context, hashlen[i],
331 sha512_digest(&sha512_context, SHA512_DIGEST_SIZE, hash);
335 get_keyid(key, &keyid);
336 logthing(LOGTHING_ERROR,
337 "Unsupported signature hash type %d on 0x%016" PRIX64,
343 logthing(LOGTHING_DEBUG, "Hash type: %d, %d chunks, "
344 "calculated: %02X%02X / actual: %02X%02X",
346 hash[0], hash[1], sighash[0], sighash[1]);
348 return (hash[0] == sighash[0] && hash[1] == sighash[1]);