/src/gnupg/kbx/keybox-search.c
Line | Count | Source |
1 | | /* keybox-search.c - Search operations |
2 | | * Copyright (C) 2001, 2002, 2003, 2004, 2012, |
3 | | * 2013 Free Software Foundation, Inc. |
4 | | * |
5 | | * This file is part of GnuPG. |
6 | | * |
7 | | * GnuPG is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 3 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * GnuPG is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include <config.h> |
22 | | #include <stdlib.h> |
23 | | #include <stdio.h> |
24 | | #include <string.h> |
25 | | #include <assert.h> |
26 | | #include <errno.h> |
27 | | |
28 | | #include "keybox-defs.h" |
29 | | #include <gcrypt.h> |
30 | | #include "../common/host2net.h" |
31 | | #include "../common/mbox-util.h" |
32 | | |
33 | 0 | #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ |
34 | 0 | *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) |
35 | 0 | #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) |
36 | | |
37 | | |
38 | | struct sn_array_s { |
39 | | int snlen; |
40 | | unsigned char *sn; |
41 | | }; |
42 | | |
43 | | |
44 | 0 | #define get32(a) buf32_to_ulong ((a)) |
45 | 0 | #define get16(a) buf16_to_ulong ((a)) |
46 | | |
47 | | |
48 | | static inline unsigned int |
49 | | blob_get_blob_flags (KEYBOXBLOB blob) |
50 | 0 | { |
51 | 0 | const unsigned char *buffer; |
52 | 0 | size_t length; |
53 | |
|
54 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
55 | 0 | if (length < 8) |
56 | 0 | return 0; /* oops */ |
57 | | |
58 | 0 | return get16 (buffer + 6); |
59 | 0 | } |
60 | | |
61 | | |
62 | | /* Return the first keyid from the blob. Returns true if |
63 | | available. */ |
64 | | static int |
65 | | blob_get_first_keyid (KEYBOXBLOB blob, u32 *kid) |
66 | 0 | { |
67 | 0 | const unsigned char *buffer; |
68 | 0 | size_t length, nkeys, keyinfolen; |
69 | 0 | int fpr32; |
70 | |
|
71 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
72 | 0 | if (length < 48) |
73 | 0 | return 0; /* blob too short */ |
74 | 0 | fpr32 = buffer[5] == 2; |
75 | 0 | if (fpr32 && length < 56) |
76 | 0 | return 0; /* blob to short */ |
77 | | |
78 | 0 | nkeys = get16 (buffer + 16); |
79 | 0 | keyinfolen = get16 (buffer + 18); |
80 | 0 | if (!nkeys || keyinfolen < (fpr32?56:28)) |
81 | 0 | return 0; /* invalid blob */ |
82 | | |
83 | 0 | if (fpr32 && (get16 (buffer + 20 + 32) & 0x80)) |
84 | 0 | { |
85 | | /* 32 byte fingerprint. */ |
86 | 0 | kid[0] = get32 (buffer + 20); |
87 | 0 | kid[1] = get32 (buffer + 20 + 4); |
88 | 0 | } |
89 | 0 | else /* 20 byte fingerprint. */ |
90 | 0 | { |
91 | 0 | kid[0] = get32 (buffer + 20 + 12); |
92 | 0 | kid[1] = get32 (buffer + 20 + 16); |
93 | 0 | } |
94 | |
|
95 | 0 | return 1; |
96 | 0 | } |
97 | | |
98 | | |
99 | | /* Return information on the flag WHAT within the blob BUFFER,LENGTH. |
100 | | Return the offset and the length (in bytes) of the flag in |
101 | | FLAGOFF,FLAG_SIZE. */ |
102 | | gpg_err_code_t |
103 | | _keybox_get_flag_location (const unsigned char *buffer, size_t length, |
104 | | int what, size_t *flag_off, size_t *flag_size) |
105 | 0 | { |
106 | 0 | size_t pos; |
107 | 0 | size_t nkeys, keyinfolen; |
108 | 0 | size_t nuids, uidinfolen; |
109 | 0 | size_t nserial; |
110 | 0 | size_t nsigs, siginfolen, siginfooff; |
111 | |
|
112 | 0 | switch (what) |
113 | 0 | { |
114 | 0 | case KEYBOX_FLAG_BLOB: |
115 | 0 | if (length < 8) |
116 | 0 | return GPG_ERR_INV_OBJ; |
117 | 0 | *flag_off = 6; |
118 | 0 | *flag_size = 2; |
119 | 0 | break; |
120 | | |
121 | 0 | case KEYBOX_FLAG_OWNERTRUST: |
122 | 0 | case KEYBOX_FLAG_VALIDITY: |
123 | 0 | case KEYBOX_FLAG_CREATED_AT: |
124 | 0 | case KEYBOX_FLAG_SIG_INFO: |
125 | 0 | if (length < 20) |
126 | 0 | return GPG_ERR_INV_OBJ; |
127 | | /* Key info. */ |
128 | 0 | nkeys = get16 (buffer + 16); |
129 | 0 | keyinfolen = get16 (buffer + 18 ); |
130 | 0 | if (keyinfolen < 28) |
131 | 0 | return GPG_ERR_INV_OBJ; |
132 | 0 | pos = 20 + keyinfolen*nkeys; |
133 | 0 | if (pos+2 > length) |
134 | 0 | return GPG_ERR_INV_OBJ; /* Out of bounds. */ |
135 | | /* Serial number. */ |
136 | 0 | nserial = get16 (buffer+pos); |
137 | 0 | pos += 2 + nserial; |
138 | 0 | if (pos+4 > length) |
139 | 0 | return GPG_ERR_INV_OBJ; /* Out of bounds. */ |
140 | | /* User IDs. */ |
141 | 0 | nuids = get16 (buffer + pos); pos += 2; |
142 | 0 | uidinfolen = get16 (buffer + pos); pos += 2; |
143 | 0 | if (uidinfolen < 12 ) |
144 | 0 | return GPG_ERR_INV_OBJ; |
145 | 0 | pos += uidinfolen*nuids; |
146 | 0 | if (pos+4 > length) |
147 | 0 | return GPG_ERR_INV_OBJ ; /* Out of bounds. */ |
148 | | /* Signature info. */ |
149 | 0 | siginfooff = pos; |
150 | 0 | nsigs = get16 (buffer + pos); pos += 2; |
151 | 0 | siginfolen = get16 (buffer + pos); pos += 2; |
152 | 0 | if (siginfolen < 4 ) |
153 | 0 | return GPG_ERR_INV_OBJ; |
154 | 0 | pos += siginfolen*nsigs; |
155 | 0 | if (pos+1+1+2+4+4+4+4 > length) |
156 | 0 | return GPG_ERR_INV_OBJ ; /* Out of bounds. */ |
157 | 0 | *flag_size = 1; |
158 | 0 | *flag_off = pos; |
159 | 0 | switch (what) |
160 | 0 | { |
161 | 0 | case KEYBOX_FLAG_VALIDITY: |
162 | 0 | *flag_off += 1; |
163 | 0 | break; |
164 | 0 | case KEYBOX_FLAG_CREATED_AT: |
165 | 0 | *flag_size = 4; |
166 | 0 | *flag_off += 1+2+4+4+4; |
167 | 0 | break; |
168 | 0 | case KEYBOX_FLAG_SIG_INFO: |
169 | 0 | *flag_size = siginfolen * nsigs; |
170 | 0 | *flag_off = siginfooff; |
171 | 0 | break; |
172 | 0 | default: |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | break; |
176 | | |
177 | 0 | default: |
178 | 0 | return GPG_ERR_INV_FLAG; |
179 | 0 | } |
180 | 0 | return 0; |
181 | 0 | } |
182 | | |
183 | | |
184 | | |
185 | | /* Return one of the flags WHAT in VALUE from the blob BUFFER of |
186 | | LENGTH bytes. Return 0 on success or an raw error code. */ |
187 | | static gpg_err_code_t |
188 | | get_flag_from_image (const unsigned char *buffer, size_t length, |
189 | | int what, unsigned int *value) |
190 | 0 | { |
191 | 0 | gpg_err_code_t ec; |
192 | 0 | size_t pos, size; |
193 | |
|
194 | 0 | *value = 0; |
195 | 0 | ec = _keybox_get_flag_location (buffer, length, what, &pos, &size); |
196 | 0 | if (!ec) |
197 | 0 | switch (size) |
198 | 0 | { |
199 | 0 | case 1: *value = buffer[pos]; break; |
200 | 0 | case 2: *value = get16 (buffer + pos); break; |
201 | 0 | case 4: *value = get32 (buffer + pos); break; |
202 | 0 | default: ec = GPG_ERR_BUG; break; |
203 | 0 | } |
204 | | |
205 | 0 | return ec; |
206 | 0 | } |
207 | | |
208 | | |
209 | | static int |
210 | | blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen) |
211 | 0 | { |
212 | 0 | const unsigned char *buffer; |
213 | 0 | size_t length; |
214 | 0 | size_t pos, off; |
215 | 0 | size_t nkeys, keyinfolen; |
216 | 0 | size_t nserial; |
217 | |
|
218 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
219 | 0 | if (length < 40) |
220 | 0 | return 0; /* blob too short */ |
221 | | |
222 | | /*keys*/ |
223 | 0 | nkeys = get16 (buffer + 16); |
224 | 0 | keyinfolen = get16 (buffer + 18 ); |
225 | 0 | if (keyinfolen < 28) |
226 | 0 | return 0; /* invalid blob */ |
227 | 0 | pos = 20 + keyinfolen*nkeys; |
228 | 0 | if (pos+2 > length) |
229 | 0 | return 0; /* out of bounds */ |
230 | | |
231 | | /*serial*/ |
232 | 0 | nserial = get16 (buffer+pos); |
233 | 0 | off = pos + 2; |
234 | 0 | if (off+nserial > length) |
235 | 0 | return 0; /* out of bounds */ |
236 | | |
237 | 0 | return nserial == snlen && !memcmp (buffer+off, sn, snlen); |
238 | 0 | } |
239 | | |
240 | | |
241 | | /* Returns 0 if not found or the number of the key which was found. |
242 | | For X.509 this is always 1, for OpenPGP this is 1 for the primary |
243 | | key and 2 and more for the subkeys. */ |
244 | | static int |
245 | | blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen) |
246 | 0 | { |
247 | 0 | const unsigned char *buffer; |
248 | 0 | size_t length; |
249 | 0 | size_t pos, off; |
250 | 0 | size_t nkeys, keyinfolen; |
251 | 0 | int idx, fpr32, storedfprlen; |
252 | |
|
253 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
254 | 0 | if (length < 40) |
255 | 0 | return 0; /* blob too short */ |
256 | 0 | fpr32 = buffer[5] == 2; |
257 | | |
258 | | /*keys*/ |
259 | 0 | nkeys = get16 (buffer + 16); |
260 | 0 | keyinfolen = get16 (buffer + 18 ); |
261 | 0 | if (keyinfolen < (fpr32?56:28)) |
262 | 0 | return 0; /* invalid blob */ |
263 | 0 | pos = 20; |
264 | 0 | if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length) |
265 | 0 | return 0; /* out of bounds */ |
266 | | |
267 | 0 | for (idx=0; idx < nkeys; idx++) |
268 | 0 | { |
269 | 0 | off = pos + idx*keyinfolen; |
270 | 0 | if (fpr32) |
271 | 0 | storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20; |
272 | 0 | else |
273 | 0 | storedfprlen = 20; |
274 | 0 | if (storedfprlen == fprlen |
275 | 0 | && !memcmp (buffer + off, fpr, storedfprlen)) |
276 | 0 | return idx+1; /* found */ |
277 | 0 | } |
278 | 0 | return 0; /* not found */ |
279 | 0 | } |
280 | | |
281 | | |
282 | | /* Helper for has_short_kid and has_long_kid. This function is called |
283 | | * with FPROFF 12 and FPRLEN 4 or with FPROFF 12 and FPRLEN 8. */ |
284 | | static int |
285 | | blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr, |
286 | | int fproff, int fprlen) |
287 | 0 | { |
288 | 0 | const unsigned char *buffer; |
289 | 0 | size_t length; |
290 | 0 | size_t pos, off; |
291 | 0 | size_t nkeys, keyinfolen; |
292 | 0 | int idx; |
293 | 0 | int fpr32; /* Set if this blob stores all fingerprints as 32 bytes. */ |
294 | |
|
295 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
296 | 0 | if (length < 40) |
297 | 0 | return 0; /* blob too short */ |
298 | 0 | fpr32 = buffer[5] == 2; |
299 | | |
300 | | /*keys*/ |
301 | 0 | nkeys = get16 (buffer + 16); |
302 | 0 | keyinfolen = get16 (buffer + 18 ); |
303 | 0 | if (keyinfolen < (fpr32?56:28)) |
304 | 0 | return 0; /* invalid blob */ |
305 | 0 | pos = 20; |
306 | 0 | if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length) |
307 | 0 | return 0; /* out of bounds */ |
308 | | |
309 | 0 | for (idx=0; idx < nkeys; idx++) |
310 | 0 | { |
311 | 0 | off = pos + idx*keyinfolen; |
312 | 0 | if (!fpr32) |
313 | 0 | { |
314 | | /* Blob has only 20 fingerprints - use the FPROFF. */ |
315 | 0 | if (!memcmp (buffer + off + fproff, fpr, fprlen)) |
316 | 0 | return idx+1; /* found */ |
317 | 0 | } |
318 | 0 | else if ((buffer[off + 32 + 1] & 0x80)) |
319 | 0 | { |
320 | | /* This (sub)key has a 32 byte fpr -> use 0 as offset. */ |
321 | 0 | if (!memcmp (buffer + off, fpr, fprlen)) |
322 | 0 | return idx+1; /* found */ |
323 | 0 | } |
324 | 0 | else |
325 | 0 | { |
326 | | /* This (sub)key has a 20 byte fpr -> use the FPROFF */ |
327 | 0 | if (!memcmp (buffer + off + fproff, fpr, fprlen)) |
328 | 0 | return idx+1; /* found */ |
329 | 0 | } |
330 | 0 | } |
331 | 0 | return 0; /* not found */ |
332 | 0 | } |
333 | | |
334 | | |
335 | | /* Returns true if found. */ |
336 | | static int |
337 | | blob_cmp_ubid (KEYBOXBLOB blob, const unsigned char *ubid) |
338 | 0 | { |
339 | 0 | const unsigned char *buffer; |
340 | 0 | size_t length; |
341 | 0 | size_t pos; |
342 | 0 | size_t nkeys, keyinfolen; |
343 | 0 | int fpr32; |
344 | |
|
345 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
346 | 0 | if (length < 40) |
347 | 0 | return 0; /* blob too short */ |
348 | 0 | fpr32 = buffer[5] == 2; |
349 | | |
350 | | /*keys*/ |
351 | 0 | nkeys = get16 (buffer + 16); |
352 | 0 | keyinfolen = get16 (buffer + 18 ); |
353 | 0 | if (!nkeys || keyinfolen < (fpr32?56:28)) |
354 | 0 | return 0; /* invalid blob */ |
355 | 0 | pos = 20; |
356 | 0 | if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length) |
357 | 0 | return 0; /* out of bounds */ |
358 | | |
359 | 0 | if (!memcmp (buffer + pos, ubid, UBID_LEN)) |
360 | 0 | return 1; /* found */ |
361 | 0 | return 0; /* not found */ |
362 | 0 | } |
363 | | |
364 | | |
365 | | static int |
366 | | blob_cmp_name (KEYBOXBLOB blob, int idx, |
367 | | const char *name, size_t namelen, int substr, int x509) |
368 | 0 | { |
369 | 0 | const unsigned char *buffer; |
370 | 0 | size_t length; |
371 | 0 | size_t pos, off, len; |
372 | 0 | size_t nkeys, keyinfolen; |
373 | 0 | size_t nuids, uidinfolen; |
374 | 0 | size_t nserial; |
375 | |
|
376 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
377 | 0 | if (length < 40) |
378 | 0 | return 0; /* blob too short */ |
379 | | |
380 | | /*keys*/ |
381 | 0 | nkeys = get16 (buffer + 16); |
382 | 0 | keyinfolen = get16 (buffer + 18 ); |
383 | 0 | if (keyinfolen < 28) |
384 | 0 | return 0; /* invalid blob */ |
385 | 0 | pos = 20 + keyinfolen*nkeys; |
386 | 0 | if ((uint64_t)pos+2 > (uint64_t)length) |
387 | 0 | return 0; /* out of bounds */ |
388 | | |
389 | | /*serial*/ |
390 | 0 | nserial = get16 (buffer+pos); |
391 | 0 | pos += 2 + nserial; |
392 | 0 | if (pos+4 > length) |
393 | 0 | return 0; /* out of bounds */ |
394 | | |
395 | | /* user ids*/ |
396 | 0 | nuids = get16 (buffer + pos); pos += 2; |
397 | 0 | uidinfolen = get16 (buffer + pos); pos += 2; |
398 | 0 | if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */) |
399 | 0 | return 0; /* invalid blob */ |
400 | 0 | if (pos + uidinfolen*nuids > length) |
401 | 0 | return 0; /* out of bounds */ |
402 | | |
403 | 0 | if (idx < 0) |
404 | 0 | { /* Compare all names. Note that for X.509 we start with index 1 |
405 | | so to skip the issuer at index 0. */ |
406 | 0 | for (idx = !!x509; idx < nuids; idx++) |
407 | 0 | { |
408 | 0 | size_t mypos = pos; |
409 | |
|
410 | 0 | mypos += idx*uidinfolen; |
411 | 0 | off = get32 (buffer+mypos); |
412 | 0 | len = get32 (buffer+mypos+4); |
413 | 0 | if ((uint64_t)off+(uint64_t)len > (uint64_t)length) |
414 | 0 | return 0; /* error: better stop here out of bounds */ |
415 | 0 | if (len < 1) |
416 | 0 | continue; /* empty name */ |
417 | 0 | if (substr) |
418 | 0 | { |
419 | 0 | if (ascii_memcasemem (buffer+off, len, name, namelen)) |
420 | 0 | return idx+1; /* found */ |
421 | 0 | } |
422 | 0 | else |
423 | 0 | { |
424 | 0 | if (len == namelen && !memcmp (buffer+off, name, len)) |
425 | 0 | return idx+1; /* found */ |
426 | 0 | } |
427 | 0 | } |
428 | 0 | } |
429 | 0 | else |
430 | 0 | { |
431 | 0 | if (idx > nuids) |
432 | 0 | return 0; /* no user ID with that idx */ |
433 | 0 | pos += idx*uidinfolen; |
434 | 0 | off = get32 (buffer+pos); |
435 | 0 | len = get32 (buffer+pos+4); |
436 | 0 | if (off+len > length) |
437 | 0 | return 0; /* out of bounds */ |
438 | 0 | if (len < 1) |
439 | 0 | return 0; /* empty name */ |
440 | | |
441 | 0 | if (substr) |
442 | 0 | { |
443 | 0 | if (ascii_memcasemem (buffer+off, len, name, namelen)) |
444 | 0 | return idx+1; /* found */ |
445 | 0 | } |
446 | 0 | else |
447 | 0 | { |
448 | 0 | if (len == namelen && !memcmp (buffer+off, name, len)) |
449 | 0 | return idx+1; /* found */ |
450 | 0 | } |
451 | 0 | } |
452 | 0 | return 0; /* not found */ |
453 | 0 | } |
454 | | |
455 | | |
456 | | /* Compare all email addresses of the subject. With SUBSTR given as |
457 | | True a substring search is done in the mail address. The X509 flag |
458 | | indicated whether the search is done on an X.509 blob. */ |
459 | | static int |
460 | | blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr, |
461 | | int x509) |
462 | 0 | { |
463 | 0 | const unsigned char *buffer; |
464 | 0 | size_t length; |
465 | 0 | size_t pos, off, len; |
466 | 0 | size_t nkeys, keyinfolen; |
467 | 0 | size_t nuids, uidinfolen; |
468 | 0 | size_t nserial; |
469 | 0 | int idx; |
470 | | |
471 | | /* fixme: this code is common to blob_cmp_mail */ |
472 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
473 | 0 | if (length < 40) |
474 | 0 | return 0; /* blob too short */ |
475 | | |
476 | | /*keys*/ |
477 | 0 | nkeys = get16 (buffer + 16); |
478 | 0 | keyinfolen = get16 (buffer + 18 ); |
479 | 0 | if (keyinfolen < 28) |
480 | 0 | return 0; /* invalid blob */ |
481 | 0 | pos = 20 + keyinfolen*nkeys; |
482 | 0 | if (pos+2 > length) |
483 | 0 | return 0; /* out of bounds */ |
484 | | |
485 | | /*serial*/ |
486 | 0 | nserial = get16 (buffer+pos); |
487 | 0 | pos += 2 + nserial; |
488 | 0 | if (pos+4 > length) |
489 | 0 | return 0; /* out of bounds */ |
490 | | |
491 | | /* user ids*/ |
492 | 0 | nuids = get16 (buffer + pos); pos += 2; |
493 | 0 | uidinfolen = get16 (buffer + pos); pos += 2; |
494 | 0 | if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */) |
495 | 0 | return 0; /* invalid blob */ |
496 | 0 | if (pos + uidinfolen*nuids > length) |
497 | 0 | return 0; /* out of bounds */ |
498 | | |
499 | 0 | if (namelen < 1) |
500 | 0 | return 0; |
501 | | |
502 | | /* Note that for X.509 we start at index 1 because index 0 is used |
503 | | for the issuer name. */ |
504 | 0 | for (idx=!!x509 ;idx < nuids; idx++) |
505 | 0 | { |
506 | 0 | size_t mypos = pos; |
507 | 0 | size_t mylen; |
508 | |
|
509 | 0 | mypos += idx*uidinfolen; |
510 | 0 | off = get32 (buffer+mypos); |
511 | 0 | len = get32 (buffer+mypos+4); |
512 | 0 | if ((uint64_t)off+(uint64_t)len > (uint64_t)length) |
513 | 0 | return 0; /* error: better stop here - out of bounds */ |
514 | 0 | if (x509) |
515 | 0 | { |
516 | 0 | if (len < 2 || buffer[off] != '<') |
517 | 0 | continue; /* empty name or trailing 0 not stored */ |
518 | 0 | len--; /* one back */ |
519 | 0 | if ( len < 3 || buffer[off+len] != '>') |
520 | 0 | continue; /* not a proper email address */ |
521 | 0 | off++; |
522 | 0 | len--; |
523 | 0 | } |
524 | 0 | else /* OpenPGP. */ |
525 | 0 | { |
526 | | /* We need to forward to the mailbox part. */ |
527 | 0 | mypos = off; |
528 | 0 | mylen = len; |
529 | 0 | for ( ; len && buffer[off] != '<'; len--, off++) |
530 | 0 | ; |
531 | 0 | if (len < 2 || buffer[off] != '<') |
532 | 0 | { |
533 | | /* Mailbox not explicitly given or too short. Restore |
534 | | OFF and LEN and check whether the entire string |
535 | | resembles a mailbox without the angle brackets. */ |
536 | 0 | off = mypos; |
537 | 0 | len = mylen; |
538 | 0 | if (!is_valid_mailbox_mem (buffer+off, len)) |
539 | 0 | continue; /* Not a mail address. */ |
540 | 0 | } |
541 | 0 | else /* Seems to be standard user id with mail address. */ |
542 | 0 | { |
543 | 0 | off++; /* Point to first char of the mail address. */ |
544 | 0 | len--; |
545 | | /* Search closing '>'. */ |
546 | 0 | for (mypos=off; len && buffer[mypos] != '>'; len--, mypos++) |
547 | 0 | ; |
548 | 0 | if (!len || buffer[mypos] != '>' || off == mypos) |
549 | 0 | continue; /* Not a proper mail address. */ |
550 | 0 | len = mypos - off; |
551 | 0 | } |
552 | |
|
553 | 0 | } |
554 | | |
555 | 0 | if (substr) |
556 | 0 | { |
557 | 0 | if (ascii_memcasemem (buffer+off, len, name, namelen)) |
558 | 0 | return idx+1; /* found */ |
559 | 0 | } |
560 | 0 | else |
561 | 0 | { |
562 | 0 | if (len == namelen && !ascii_memcasecmp (buffer+off, name, len)) |
563 | 0 | return idx+1; /* found */ |
564 | 0 | } |
565 | 0 | } |
566 | 0 | return 0; /* not found */ |
567 | 0 | } |
568 | | |
569 | | |
570 | | /* Return true if the key in BLOB matches the 20 bytes keygrip GRIP. |
571 | | * We don't have the keygrips as meta data, thus we need to parse the |
572 | | * certificate. Fixme: We might want to return proper error codes |
573 | | * instead of failing a search for invalid certificates etc. */ |
574 | | static int |
575 | | blob_openpgp_has_grip (KEYBOXBLOB blob, const unsigned char *grip) |
576 | 0 | { |
577 | 0 | int rc = 0; |
578 | 0 | const unsigned char *buffer; |
579 | 0 | size_t length; |
580 | 0 | size_t cert_off, cert_len; |
581 | 0 | struct _keybox_openpgp_info info; |
582 | 0 | struct _keybox_openpgp_key_info *k; |
583 | |
|
584 | 0 | buffer = _keybox_get_blob_image (blob, &length); |
585 | 0 | if (length < 40) |
586 | 0 | return 0; /* Too short. */ |
587 | 0 | cert_off = get32 (buffer+8); |
588 | 0 | cert_len = get32 (buffer+12); |
589 | 0 | if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length) |
590 | 0 | return 0; /* Too short. */ |
591 | | |
592 | 0 | if (_keybox_parse_openpgp (buffer + cert_off, cert_len, 0, NULL, &info)) |
593 | 0 | return 0; /* Parse error. */ |
594 | | |
595 | 0 | if (!memcmp (info.primary.grip, grip, 20)) |
596 | 0 | { |
597 | 0 | rc = 1; |
598 | 0 | goto leave; |
599 | 0 | } |
600 | | |
601 | 0 | if (info.nsubkeys) |
602 | 0 | { |
603 | 0 | k = &info.subkeys; |
604 | 0 | do |
605 | 0 | { |
606 | 0 | if (!memcmp (k->grip, grip, 20)) |
607 | 0 | { |
608 | 0 | rc = 1; |
609 | 0 | goto leave; |
610 | 0 | } |
611 | 0 | k = k->next; |
612 | 0 | } |
613 | 0 | while (k); |
614 | 0 | } |
615 | | |
616 | 0 | leave: |
617 | 0 | _keybox_destroy_openpgp_info (&info); |
618 | 0 | return rc; |
619 | 0 | } |
620 | | |
621 | | |
622 | | #ifdef KEYBOX_WITH_X509 |
623 | | /* Return true if the key in BLOB matches the 20 bytes keygrip GRIP. |
624 | | We don't have the keygrips as meta data, thus we need to parse the |
625 | | certificate. Fixme: We might want to return proper error codes |
626 | | instead of failing a search for invalid certificates etc. */ |
627 | | static int |
628 | | blob_x509_has_grip (KEYBOXBLOB blob, const unsigned char *grip) |
629 | | { |
630 | | int rc; |
631 | | const unsigned char *buffer; |
632 | | size_t length; |
633 | | size_t cert_off, cert_len; |
634 | | ksba_reader_t reader = NULL; |
635 | | ksba_cert_t cert = NULL; |
636 | | ksba_sexp_t p = NULL; |
637 | | gcry_sexp_t s_pkey; |
638 | | unsigned char array[20]; |
639 | | unsigned char *rcp; |
640 | | size_t n; |
641 | | |
642 | | buffer = _keybox_get_blob_image (blob, &length); |
643 | | if (length < 40) |
644 | | return 0; /* Too short. */ |
645 | | cert_off = get32 (buffer+8); |
646 | | cert_len = get32 (buffer+12); |
647 | | if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length) |
648 | | return 0; /* Too short. */ |
649 | | |
650 | | rc = ksba_reader_new (&reader); |
651 | | if (rc) |
652 | | return 0; /* Problem with ksba. */ |
653 | | rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len); |
654 | | if (rc) |
655 | | goto failed; |
656 | | rc = ksba_cert_new (&cert); |
657 | | if (rc) |
658 | | goto failed; |
659 | | rc = ksba_cert_read_der (cert, reader); |
660 | | if (rc) |
661 | | goto failed; |
662 | | p = ksba_cert_get_public_key (cert); |
663 | | if (!p) |
664 | | goto failed; |
665 | | n = gcry_sexp_canon_len (p, 0, NULL, NULL); |
666 | | if (!n) |
667 | | goto failed; |
668 | | rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n); |
669 | | if (rc) |
670 | | { |
671 | | gcry_sexp_release (s_pkey); |
672 | | goto failed; |
673 | | } |
674 | | rcp = gcry_pk_get_keygrip (s_pkey, array); |
675 | | gcry_sexp_release (s_pkey); |
676 | | if (!rcp) |
677 | | goto failed; /* Can't calculate keygrip. */ |
678 | | |
679 | | xfree (p); |
680 | | ksba_cert_release (cert); |
681 | | ksba_reader_release (reader); |
682 | | return !memcmp (array, grip, 20); |
683 | | failed: |
684 | | xfree (p); |
685 | | ksba_cert_release (cert); |
686 | | ksba_reader_release (reader); |
687 | | return 0; |
688 | | } |
689 | | #endif /*KEYBOX_WITH_X509*/ |
690 | | |
691 | | |
692 | | |
693 | | /* |
694 | | The has_foo functions are used as helpers for search |
695 | | */ |
696 | | static inline int |
697 | | has_short_kid (KEYBOXBLOB blob, u32 lkid) |
698 | 0 | { |
699 | 0 | size_t length; |
700 | 0 | unsigned char buf[4]; |
701 | |
|
702 | 0 | _keybox_get_blob_image (blob, &length); |
703 | 0 | if (length < 48) |
704 | 0 | return 0; /* blob too short */ |
705 | | |
706 | 0 | buf[0] = lkid >> 24; |
707 | 0 | buf[1] = lkid >> 16; |
708 | 0 | buf[2] = lkid >> 8; |
709 | 0 | buf[3] = lkid; |
710 | |
|
711 | 0 | return blob_cmp_fpr_part (blob, buf, 16, 4); |
712 | 0 | } |
713 | | |
714 | | static inline int |
715 | | has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid) |
716 | 0 | { |
717 | 0 | size_t length; |
718 | 0 | unsigned char buf[8]; |
719 | |
|
720 | 0 | _keybox_get_blob_image (blob, &length); |
721 | 0 | if (length < 48) |
722 | 0 | return 0; /* blob too short */ |
723 | | |
724 | 0 | buf[0] = mkid >> 24; |
725 | 0 | buf[1] = mkid >> 16; |
726 | 0 | buf[2] = mkid >> 8; |
727 | 0 | buf[3] = mkid; |
728 | 0 | buf[4] = lkid >> 24; |
729 | 0 | buf[5] = lkid >> 16; |
730 | 0 | buf[6] = lkid >> 8; |
731 | 0 | buf[7] = lkid; |
732 | |
|
733 | 0 | return blob_cmp_fpr_part (blob, buf, 12, 8); |
734 | 0 | } |
735 | | |
736 | | static inline int |
737 | | has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen) |
738 | 0 | { |
739 | 0 | return blob_cmp_fpr (blob, fpr, fprlen); |
740 | 0 | } |
741 | | |
742 | | static inline int |
743 | | has_keygrip (KEYBOXBLOB blob, const unsigned char *grip) |
744 | 0 | { |
745 | 0 | if (blob_get_type (blob) == KEYBOX_BLOBTYPE_PGP) |
746 | 0 | return blob_openpgp_has_grip (blob, grip); |
747 | | #ifdef KEYBOX_WITH_X509 |
748 | | if (blob_get_type (blob) == KEYBOX_BLOBTYPE_X509) |
749 | | return blob_x509_has_grip (blob, grip); |
750 | | #endif |
751 | 0 | return 0; |
752 | 0 | } |
753 | | |
754 | | |
755 | | /* The UBID is the primary fingerprint. For OpenPGP v5 keys only the |
756 | | * leftmost 20 bytes (UBID_LEN) are used. */ |
757 | | static inline int |
758 | | has_ubid (KEYBOXBLOB blob, const unsigned char *ubid) |
759 | 0 | { |
760 | 0 | return blob_cmp_ubid (blob, ubid); |
761 | 0 | } |
762 | | |
763 | | |
764 | | static inline int |
765 | | has_issuer (KEYBOXBLOB blob, const char *name) |
766 | 0 | { |
767 | 0 | size_t namelen; |
768 | |
|
769 | 0 | return_val_if_fail (name, 0); |
770 | | |
771 | 0 | if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509) |
772 | 0 | return 0; |
773 | | |
774 | 0 | namelen = strlen (name); |
775 | 0 | return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1); |
776 | 0 | } |
777 | | |
778 | | static inline int |
779 | | has_issuer_sn (KEYBOXBLOB blob, const char *name, |
780 | | const unsigned char *sn, int snlen) |
781 | 0 | { |
782 | 0 | size_t namelen; |
783 | |
|
784 | 0 | return_val_if_fail (name, 0); |
785 | 0 | return_val_if_fail (sn, 0); |
786 | | |
787 | 0 | if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509) |
788 | 0 | return 0; |
789 | | |
790 | 0 | namelen = strlen (name); |
791 | |
|
792 | 0 | return (blob_cmp_sn (blob, sn, snlen) |
793 | 0 | && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1)); |
794 | 0 | } |
795 | | |
796 | | static inline int |
797 | | has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen) |
798 | 0 | { |
799 | 0 | return_val_if_fail (sn, 0); |
800 | | |
801 | 0 | if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509) |
802 | 0 | return 0; |
803 | 0 | return blob_cmp_sn (blob, sn, snlen); |
804 | 0 | } |
805 | | |
806 | | static inline int |
807 | | has_subject (KEYBOXBLOB blob, const char *name) |
808 | 0 | { |
809 | 0 | size_t namelen; |
810 | |
|
811 | 0 | return_val_if_fail (name, 0); |
812 | | |
813 | 0 | if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509) |
814 | 0 | return 0; |
815 | | |
816 | 0 | namelen = strlen (name); |
817 | 0 | return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0, 1); |
818 | 0 | } |
819 | | |
820 | | |
821 | | static inline int |
822 | | has_username (KEYBOXBLOB blob, const char *name, int substr) |
823 | 0 | { |
824 | 0 | size_t namelen; |
825 | 0 | int btype; |
826 | |
|
827 | 0 | return_val_if_fail (name, 0); |
828 | | |
829 | 0 | btype = blob_get_type (blob); |
830 | 0 | if (btype != KEYBOX_BLOBTYPE_PGP && btype != KEYBOX_BLOBTYPE_X509) |
831 | 0 | return 0; |
832 | | |
833 | 0 | namelen = strlen (name); |
834 | 0 | return blob_cmp_name (blob, -1 /* all subject/user names */, name, |
835 | 0 | namelen, substr, (btype == KEYBOX_BLOBTYPE_X509)); |
836 | 0 | } |
837 | | |
838 | | |
839 | | static inline int |
840 | | has_mail (KEYBOXBLOB blob, const char *name, int substr) |
841 | 0 | { |
842 | 0 | size_t namelen; |
843 | 0 | int btype; |
844 | |
|
845 | 0 | return_val_if_fail (name, 0); |
846 | | |
847 | 0 | btype = blob_get_type (blob); |
848 | 0 | if (btype != KEYBOX_BLOBTYPE_PGP && btype != KEYBOX_BLOBTYPE_X509) |
849 | 0 | return 0; |
850 | | |
851 | 0 | if (btype == KEYBOX_BLOBTYPE_PGP && *name == '<') |
852 | 0 | name++; /* Hack to remove the leading '<' for gpg. */ |
853 | |
|
854 | 0 | namelen = strlen (name); |
855 | 0 | if (namelen && name[namelen-1] == '>') |
856 | 0 | namelen--; |
857 | 0 | return blob_cmp_mail (blob, name, namelen, substr, |
858 | 0 | (btype == KEYBOX_BLOBTYPE_X509)); |
859 | 0 | } |
860 | | |
861 | | |
862 | | static void |
863 | | release_sn_array (struct sn_array_s *array, size_t size) |
864 | 0 | { |
865 | 0 | size_t n; |
866 | |
|
867 | 0 | for (n=0; n < size; n++) |
868 | 0 | xfree (array[n].sn); |
869 | 0 | xfree (array); |
870 | 0 | } |
871 | | |
872 | | |
873 | | |
874 | | /* |
875 | | * |
876 | | * The search API |
877 | | * |
878 | | */ |
879 | | |
880 | | gpg_error_t |
881 | | keybox_search_reset (KEYBOX_HANDLE hd) |
882 | 1.33M | { |
883 | 1.33M | if (!hd) |
884 | 0 | return gpg_error (GPG_ERR_INV_VALUE); |
885 | | |
886 | 1.33M | if (hd->found.blob) |
887 | 0 | { |
888 | 0 | _keybox_release_blob (hd->found.blob); |
889 | 0 | hd->found.blob = NULL; |
890 | 0 | } |
891 | | |
892 | 1.33M | if (hd->fp) |
893 | 28.7k | { |
894 | 28.7k | if (es_fseeko (hd->fp, 0, SEEK_SET)) |
895 | 0 | { |
896 | | /* Ooops. Seek did not work. Close so that the search will |
897 | | * open the file again. */ |
898 | 0 | _keybox_ll_close (hd->fp); |
899 | 0 | hd->fp = NULL; |
900 | 0 | } |
901 | 28.7k | } |
902 | 1.33M | hd->error = 0; |
903 | 1.33M | hd->eof = 0; |
904 | 1.33M | return 0; |
905 | 1.33M | } |
906 | | |
907 | | |
908 | | /* Note: When in ephemeral mode the search function does visit all |
909 | | blobs but in standard mode, blobs flagged as ephemeral are ignored. |
910 | | If WANT_BLOBTYPE is not 0 only blobs of this type are considered. |
911 | | The value at R_SKIPPED is updated by the number of skipped long |
912 | | records (counts PGP and X.509). */ |
913 | | gpg_error_t |
914 | | keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc, |
915 | | keybox_blobtype_t want_blobtype, |
916 | | size_t *r_descindex, unsigned long *r_skipped) |
917 | 5.09k | { |
918 | 5.09k | gpg_error_t rc; |
919 | 5.09k | size_t n; |
920 | 5.09k | int need_words, any_skip; |
921 | 5.09k | KEYBOXBLOB blob = NULL; |
922 | 5.09k | struct sn_array_s *sn_array = NULL; |
923 | 5.09k | int pk_no, uid_no; |
924 | 5.09k | off_t lastfoundoff; |
925 | | |
926 | 5.09k | if (!hd) |
927 | 0 | return gpg_error (GPG_ERR_INV_VALUE); |
928 | | |
929 | | /* Clear last found result but record the offset of the last found |
930 | | * blob which we may need later. */ |
931 | 5.09k | if (hd->found.blob) |
932 | 0 | { |
933 | 0 | lastfoundoff = _keybox_get_blob_fileoffset (hd->found.blob); |
934 | 0 | _keybox_release_blob (hd->found.blob); |
935 | 0 | hd->found.blob = NULL; |
936 | 0 | } |
937 | 5.09k | else |
938 | 5.09k | lastfoundoff = 0; |
939 | | |
940 | 5.09k | if (hd->error) |
941 | 0 | return hd->error; /* still in error state */ |
942 | 5.09k | if (hd->eof) |
943 | 0 | return -1; /* still EOF */ |
944 | | |
945 | | /* figure out what information we need */ |
946 | 5.09k | need_words = any_skip = 0; |
947 | 10.1k | for (n=0; n < ndesc; n++) |
948 | 5.09k | { |
949 | 5.09k | switch (desc[n].mode) |
950 | 5.09k | { |
951 | 0 | case KEYDB_SEARCH_MODE_WORDS: |
952 | 0 | need_words = 1; |
953 | 0 | break; |
954 | 4.80k | case KEYDB_SEARCH_MODE_FIRST: |
955 | | /* always restart the search in this mode */ |
956 | 4.80k | keybox_search_reset (hd); |
957 | 4.80k | lastfoundoff = 0; |
958 | 4.80k | break; |
959 | 298 | default: |
960 | 298 | break; |
961 | 5.09k | } |
962 | 5.09k | if (desc[n].skipfnc) |
963 | 0 | any_skip = 1; |
964 | 5.09k | if (desc[n].snhex && !sn_array) |
965 | 0 | { |
966 | 0 | sn_array = xtrycalloc (ndesc, sizeof *sn_array); |
967 | 0 | if (!sn_array) |
968 | 0 | return (hd->error = gpg_error_from_syserror ()); |
969 | 0 | } |
970 | 5.09k | } |
971 | | |
972 | 5.09k | (void)need_words; /* Not yet implemented. */ |
973 | | |
974 | 5.09k | if (!hd->fp) |
975 | 5.04k | { |
976 | 5.04k | rc = _keybox_ll_open (&hd->fp, hd->kb->fname, 0); |
977 | 5.04k | if (rc) |
978 | 0 | { |
979 | 0 | xfree (sn_array); |
980 | 0 | return rc; |
981 | 0 | } |
982 | | /* log_debug ("%s: re-opened file\n", __func__); */ |
983 | 5.04k | if (ndesc && desc[0].mode != KEYDB_SEARCH_MODE_FIRST && lastfoundoff) |
984 | 0 | { |
985 | | /* Search mode is not first and the last search operation |
986 | | * returned a blob which also was not the first one. We now |
987 | | * need to skip over that blob and hope that the file has |
988 | | * not changed. */ |
989 | 0 | if (es_fseeko (hd->fp, lastfoundoff, SEEK_SET)) |
990 | 0 | { |
991 | 0 | rc = gpg_error_from_syserror (); |
992 | 0 | log_debug ("%s: seeking to last found offset failed: %s\n", |
993 | 0 | __func__, gpg_strerror (rc)); |
994 | 0 | xfree (sn_array); |
995 | 0 | return gpg_error (GPG_ERR_NOTHING_FOUND); |
996 | 0 | } |
997 | | /* log_debug ("%s: re-opened file and sought to last offset\n", */ |
998 | | /* __func__); */ |
999 | 0 | rc = _keybox_read_blob (NULL, hd->fp, NULL); |
1000 | 0 | if (rc) |
1001 | 0 | { |
1002 | 0 | log_debug ("%s: skipping last found blob failed: %s\n", |
1003 | 0 | __func__, gpg_strerror (rc)); |
1004 | 0 | xfree (sn_array); |
1005 | 0 | return gpg_error (GPG_ERR_NOTHING_FOUND); |
1006 | 0 | } |
1007 | 0 | } |
1008 | 5.04k | } |
1009 | | |
1010 | | /* Kludge: We need to convert an SN given as hexstring to its binary |
1011 | | representation - in some cases we are not able to store it in the |
1012 | | search descriptor, because due to the way we use it, it is not |
1013 | | possible to free allocated memory. */ |
1014 | 5.09k | if (sn_array) |
1015 | 0 | { |
1016 | 0 | const unsigned char *s; |
1017 | 0 | int i, odd; |
1018 | 0 | size_t snlen; |
1019 | |
|
1020 | 0 | for (n=0; n < ndesc; n++) |
1021 | 0 | { |
1022 | 0 | if (!desc[n].sn) |
1023 | 0 | ; |
1024 | 0 | else if (desc[n].snhex) |
1025 | 0 | { |
1026 | 0 | unsigned char *sn; |
1027 | |
|
1028 | 0 | s = desc[n].sn; |
1029 | 0 | for (i=0; *s && *s != '/' && i < desc[n].snlen; s++, i++) |
1030 | 0 | ; |
1031 | 0 | odd = (i & 1); |
1032 | 0 | snlen = (i+1)/2; |
1033 | 0 | sn_array[n].sn = xtrymalloc (snlen); |
1034 | 0 | if (!sn_array[n].sn) |
1035 | 0 | { |
1036 | 0 | hd->error = gpg_error_from_syserror (); |
1037 | 0 | release_sn_array (sn_array, n); |
1038 | 0 | return hd->error; |
1039 | 0 | } |
1040 | 0 | sn_array[n].snlen = snlen; |
1041 | 0 | sn = sn_array[n].sn; |
1042 | 0 | s = desc[n].sn; |
1043 | 0 | if (odd) |
1044 | 0 | { |
1045 | 0 | *sn++ = xtoi_1 (s); |
1046 | 0 | s++; |
1047 | 0 | } |
1048 | 0 | for (; *s && *s != '/'; s += 2) |
1049 | 0 | *sn++ = xtoi_2 (s); |
1050 | 0 | } |
1051 | 0 | else |
1052 | 0 | { |
1053 | 0 | const unsigned char *sn; |
1054 | |
|
1055 | 0 | sn = desc[n].sn; |
1056 | 0 | snlen = desc[n].snlen; |
1057 | 0 | sn_array[n].sn = xtrymalloc (snlen); |
1058 | 0 | if (!sn_array[n].sn) |
1059 | 0 | { |
1060 | 0 | hd->error = gpg_error_from_syserror (); |
1061 | 0 | release_sn_array (sn_array, n); |
1062 | 0 | return hd->error; |
1063 | 0 | } |
1064 | 0 | sn_array[n].snlen = snlen; |
1065 | 0 | memcpy (sn_array[n].sn, sn, snlen); |
1066 | 0 | } |
1067 | 0 | } |
1068 | 0 | } |
1069 | | |
1070 | | |
1071 | 5.09k | pk_no = uid_no = 0; |
1072 | 5.09k | for (;;) |
1073 | 10.1k | { |
1074 | 10.1k | unsigned int blobflags; |
1075 | 10.1k | int blobtype; |
1076 | | |
1077 | 10.1k | _keybox_release_blob (blob); blob = NULL; |
1078 | 10.1k | rc = _keybox_read_blob (&blob, hd->fp, NULL); |
1079 | 10.1k | if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE |
1080 | 0 | && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX) |
1081 | 0 | { |
1082 | 0 | ++*r_skipped; |
1083 | 0 | continue; /* Skip too large records. */ |
1084 | 0 | } |
1085 | | |
1086 | 10.1k | if (rc) |
1087 | 5.09k | break; |
1088 | | |
1089 | 5.09k | blobtype = blob_get_type (blob); |
1090 | 5.09k | if (blobtype == KEYBOX_BLOBTYPE_HEADER) |
1091 | 5.09k | continue; |
1092 | 0 | if (want_blobtype && blobtype != want_blobtype) |
1093 | 0 | continue; |
1094 | | |
1095 | 0 | blobflags = blob_get_blob_flags (blob); |
1096 | 0 | if (!hd->ephemeral && (blobflags & 2)) |
1097 | 0 | continue; /* Not in ephemeral mode but blob is flagged ephemeral. */ |
1098 | | |
1099 | 0 | for (n=0; n < ndesc; n++) |
1100 | 0 | { |
1101 | 0 | switch (desc[n].mode) |
1102 | 0 | { |
1103 | 0 | case KEYDB_SEARCH_MODE_NONE: |
1104 | 0 | never_reached (); |
1105 | 0 | break; |
1106 | 0 | case KEYDB_SEARCH_MODE_EXACT: |
1107 | 0 | uid_no = has_username (blob, desc[n].u.name, 0); |
1108 | 0 | if (uid_no) |
1109 | 0 | goto found; |
1110 | 0 | break; |
1111 | 0 | case KEYDB_SEARCH_MODE_MAIL: |
1112 | 0 | uid_no = has_mail (blob, desc[n].u.name, 0); |
1113 | 0 | if (uid_no) |
1114 | 0 | goto found; |
1115 | 0 | break; |
1116 | 0 | case KEYDB_SEARCH_MODE_MAILSUB: |
1117 | 0 | uid_no = has_mail (blob, desc[n].u.name, 1); |
1118 | 0 | if (uid_no) |
1119 | 0 | goto found; |
1120 | 0 | break; |
1121 | 0 | case KEYDB_SEARCH_MODE_SUBSTR: |
1122 | 0 | uid_no = has_username (blob, desc[n].u.name, 1); |
1123 | 0 | if (uid_no) |
1124 | 0 | goto found; |
1125 | 0 | break; |
1126 | 0 | case KEYDB_SEARCH_MODE_MAILEND: |
1127 | 0 | case KEYDB_SEARCH_MODE_WORDS: |
1128 | | /* not yet implemented */ |
1129 | 0 | break; |
1130 | 0 | case KEYDB_SEARCH_MODE_ISSUER: |
1131 | 0 | if (has_issuer (blob, desc[n].u.name)) |
1132 | 0 | goto found; |
1133 | 0 | break; |
1134 | 0 | case KEYDB_SEARCH_MODE_ISSUER_SN: |
1135 | 0 | if (has_issuer_sn (blob, desc[n].u.name, |
1136 | 0 | sn_array? sn_array[n].sn : desc[n].sn, |
1137 | 0 | sn_array? sn_array[n].snlen : desc[n].snlen)) |
1138 | 0 | goto found; |
1139 | 0 | break; |
1140 | 0 | case KEYDB_SEARCH_MODE_SN: |
1141 | 0 | if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn, |
1142 | 0 | sn_array? sn_array[n].snlen : desc[n].snlen)) |
1143 | 0 | goto found; |
1144 | 0 | break; |
1145 | 0 | case KEYDB_SEARCH_MODE_SUBJECT: |
1146 | 0 | if (has_subject (blob, desc[n].u.name)) |
1147 | 0 | goto found; |
1148 | 0 | break; |
1149 | 0 | case KEYDB_SEARCH_MODE_SHORT_KID: |
1150 | 0 | pk_no = has_short_kid (blob, desc[n].u.kid[1]); |
1151 | 0 | if (pk_no) |
1152 | 0 | goto found; |
1153 | 0 | break; |
1154 | 0 | case KEYDB_SEARCH_MODE_LONG_KID: |
1155 | 0 | pk_no = has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]); |
1156 | 0 | if (pk_no) |
1157 | 0 | goto found; |
1158 | 0 | break; |
1159 | | |
1160 | 0 | case KEYDB_SEARCH_MODE_FPR: |
1161 | 0 | pk_no = has_fingerprint (blob, desc[n].u.fpr, desc[n].fprlen); |
1162 | 0 | if (pk_no) |
1163 | 0 | goto found; |
1164 | 0 | break; |
1165 | | |
1166 | 0 | case KEYDB_SEARCH_MODE_KEYGRIP: |
1167 | 0 | if (has_keygrip (blob, desc[n].u.grip)) |
1168 | 0 | goto found; |
1169 | 0 | break; |
1170 | 0 | case KEYDB_SEARCH_MODE_UBID: |
1171 | 0 | if (has_ubid (blob, desc[n].u.ubid)) |
1172 | 0 | goto found; |
1173 | 0 | break; |
1174 | 0 | case KEYDB_SEARCH_MODE_FIRST: |
1175 | 0 | goto found; |
1176 | 0 | break; |
1177 | 0 | case KEYDB_SEARCH_MODE_NEXT: |
1178 | 0 | goto found; |
1179 | 0 | break; |
1180 | 0 | default: |
1181 | 0 | rc = gpg_error (GPG_ERR_INV_VALUE); |
1182 | 0 | goto found; |
1183 | 0 | } |
1184 | 0 | } |
1185 | 0 | continue; |
1186 | 0 | found: |
1187 | | /* Record which DESC we matched on. Note this value is only |
1188 | | meaningful if this function returns with no errors. */ |
1189 | 0 | if(r_descindex) |
1190 | 0 | *r_descindex = n; |
1191 | 0 | for (n=any_skip?0:ndesc; n < ndesc; n++) |
1192 | 0 | { |
1193 | 0 | u32 kid[2]; |
1194 | |
|
1195 | 0 | if (desc[n].skipfnc |
1196 | 0 | && blob_get_first_keyid (blob, kid) |
1197 | 0 | && desc[n].skipfnc (desc[n].skipfncvalue, kid, uid_no)) |
1198 | 0 | break; |
1199 | 0 | } |
1200 | 0 | if (n == ndesc) |
1201 | 0 | break; /* got it */ |
1202 | 0 | } |
1203 | | |
1204 | 5.09k | if (!rc) |
1205 | 0 | { |
1206 | 0 | hd->found.blob = blob; |
1207 | 0 | hd->found.pk_no = pk_no; |
1208 | 0 | hd->found.uid_no = uid_no; |
1209 | 0 | } |
1210 | 5.09k | else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) |
1211 | 5.09k | { |
1212 | 5.09k | _keybox_release_blob (blob); |
1213 | 5.09k | hd->eof = 1; |
1214 | 5.09k | } |
1215 | 0 | else |
1216 | 0 | { |
1217 | 0 | _keybox_release_blob (blob); |
1218 | 0 | hd->error = rc; |
1219 | 0 | } |
1220 | | |
1221 | 5.09k | if (sn_array) |
1222 | 0 | release_sn_array (sn_array, ndesc); |
1223 | | |
1224 | 5.09k | return rc; |
1225 | 5.09k | } |
1226 | | |
1227 | | |
1228 | | |
1229 | | |
1230 | | /* |
1231 | | * Functions to return a certificate or a keyblock. To be used after |
1232 | | * a successful search operation. |
1233 | | */ |
1234 | | |
1235 | | /* Return the raw data from the last found blob. Caller must release |
1236 | | * the value stored at R_BUFFER. If called with NULL for R_BUFFER |
1237 | | * only the needed length for the buffer and the public key type is |
1238 | | * returned. R_PUBKEY_TYPE and R_UBID can be used to return these |
1239 | | * attributes. */ |
1240 | | gpg_error_t |
1241 | | keybox_get_data (KEYBOX_HANDLE hd, void **r_buffer, size_t *r_length, |
1242 | | enum pubkey_types *r_pubkey_type, unsigned char *r_ubid) |
1243 | 0 | { |
1244 | 0 | const unsigned char *buffer; |
1245 | 0 | size_t length; |
1246 | 0 | size_t image_off, image_len; |
1247 | |
|
1248 | 0 | if (r_buffer) |
1249 | 0 | *r_buffer = NULL; |
1250 | 0 | if (r_length) |
1251 | 0 | *r_length = 0; |
1252 | 0 | if (r_pubkey_type) |
1253 | 0 | *r_pubkey_type = PUBKEY_TYPE_UNKNOWN; |
1254 | |
|
1255 | 0 | if (!hd) |
1256 | 0 | return gpg_error (GPG_ERR_INV_VALUE); |
1257 | 0 | if (!hd->found.blob) |
1258 | 0 | return gpg_error (GPG_ERR_NOTHING_FOUND); |
1259 | | |
1260 | 0 | switch (blob_get_type (hd->found.blob)) |
1261 | 0 | { |
1262 | 0 | case KEYBOX_BLOBTYPE_PGP: |
1263 | 0 | if (r_pubkey_type) |
1264 | 0 | *r_pubkey_type = PUBKEY_TYPE_OPGP; |
1265 | 0 | break; |
1266 | 0 | case KEYBOX_BLOBTYPE_X509: |
1267 | 0 | if (r_pubkey_type) |
1268 | 0 | *r_pubkey_type = PUBKEY_TYPE_X509; |
1269 | 0 | break; |
1270 | 0 | default: |
1271 | 0 | return gpg_error (GPG_ERR_WRONG_BLOB_TYPE); |
1272 | 0 | } |
1273 | | |
1274 | 0 | buffer = _keybox_get_blob_image (hd->found.blob, &length); |
1275 | 0 | if (length < 40) |
1276 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
1277 | 0 | image_off = get32 (buffer+8); |
1278 | 0 | image_len = get32 (buffer+12); |
1279 | 0 | if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length) |
1280 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
1281 | | |
1282 | 0 | if (r_ubid) |
1283 | 0 | { |
1284 | 0 | size_t keyinfolen; |
1285 | | |
1286 | | /* We do a quick but sufficient consistency check. For the full |
1287 | | * check see blob_cmp_ubid. */ |
1288 | 0 | if (!get16 (buffer + 16) /* No keys. */ |
1289 | 0 | || (keyinfolen = get16 (buffer + 18)) < 28 |
1290 | 0 | || (20 + (uint64_t)keyinfolen) > (uint64_t)length) |
1291 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
1292 | | |
1293 | 0 | memcpy (r_ubid, buffer + 20, UBID_LEN); |
1294 | 0 | } |
1295 | | |
1296 | 0 | if (r_length) |
1297 | 0 | *r_length = image_len; |
1298 | 0 | if (r_buffer) |
1299 | 0 | { |
1300 | 0 | *r_buffer = xtrymalloc (image_len); |
1301 | 0 | if (!*r_buffer) |
1302 | 0 | return gpg_error_from_syserror (); |
1303 | 0 | memcpy (*r_buffer, buffer + image_off, image_len); |
1304 | 0 | } |
1305 | | |
1306 | 0 | return 0; |
1307 | 0 | } |
1308 | | |
1309 | | |
1310 | | /* Return the last found keyblock. Returns 0 on success and stores a |
1311 | | * new iobuf at R_IOBUF. R_UID_NO and R_PK_NO are used to return the |
1312 | | * index of the key or user id which matched the search criteria; if |
1313 | | * not known they are set to 0. */ |
1314 | | gpg_error_t |
1315 | | keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf, |
1316 | | int *r_pk_no, int *r_uid_no) |
1317 | 0 | { |
1318 | 0 | gpg_error_t err; |
1319 | 0 | const unsigned char *buffer; |
1320 | 0 | size_t length; |
1321 | 0 | size_t image_off, image_len; |
1322 | 0 | size_t siginfo_off, siginfo_len; |
1323 | |
|
1324 | 0 | *r_iobuf = NULL; |
1325 | |
|
1326 | 0 | if (!hd) |
1327 | 0 | return gpg_error (GPG_ERR_INV_VALUE); |
1328 | 0 | if (!hd->found.blob) |
1329 | 0 | return gpg_error (GPG_ERR_NOTHING_FOUND); |
1330 | | |
1331 | 0 | if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP) |
1332 | 0 | return gpg_error (GPG_ERR_WRONG_BLOB_TYPE); |
1333 | | |
1334 | 0 | buffer = _keybox_get_blob_image (hd->found.blob, &length); |
1335 | 0 | if (length < 40) |
1336 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
1337 | 0 | image_off = get32 (buffer+8); |
1338 | 0 | image_len = get32 (buffer+12); |
1339 | 0 | if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length) |
1340 | 0 | return gpg_error (GPG_ERR_TOO_SHORT); |
1341 | | |
1342 | 0 | err = _keybox_get_flag_location (buffer, length, KEYBOX_FLAG_SIG_INFO, |
1343 | 0 | &siginfo_off, &siginfo_len); |
1344 | 0 | if (err) |
1345 | 0 | return err; |
1346 | | |
1347 | 0 | *r_pk_no = hd->found.pk_no; |
1348 | 0 | *r_uid_no = hd->found.uid_no; |
1349 | 0 | *r_iobuf = iobuf_temp_with_content (buffer+image_off, image_len); |
1350 | 0 | return 0; |
1351 | 0 | } |
1352 | | |
1353 | | |
1354 | | #ifdef KEYBOX_WITH_X509 |
1355 | | /* |
1356 | | Return the last found cert. Caller must free it. |
1357 | | */ |
1358 | | int |
1359 | | keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *r_cert) |
1360 | | { |
1361 | | const unsigned char *buffer; |
1362 | | size_t length; |
1363 | | size_t cert_off, cert_len; |
1364 | | ksba_reader_t reader = NULL; |
1365 | | ksba_cert_t cert = NULL; |
1366 | | unsigned int blobflags; |
1367 | | int rc; |
1368 | | |
1369 | | if (!hd) |
1370 | | return gpg_error (GPG_ERR_INV_VALUE); |
1371 | | if (!hd->found.blob) |
1372 | | return gpg_error (GPG_ERR_NOTHING_FOUND); |
1373 | | |
1374 | | if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_X509) |
1375 | | return gpg_error (GPG_ERR_WRONG_BLOB_TYPE); |
1376 | | |
1377 | | buffer = _keybox_get_blob_image (hd->found.blob, &length); |
1378 | | if (length < 40) |
1379 | | return gpg_error (GPG_ERR_TOO_SHORT); |
1380 | | cert_off = get32 (buffer+8); |
1381 | | cert_len = get32 (buffer+12); |
1382 | | if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length) |
1383 | | return gpg_error (GPG_ERR_TOO_SHORT); |
1384 | | |
1385 | | rc = ksba_reader_new (&reader); |
1386 | | if (rc) |
1387 | | return rc; |
1388 | | rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len); |
1389 | | if (rc) |
1390 | | { |
1391 | | ksba_reader_release (reader); |
1392 | | /* fixme: need to map the error codes */ |
1393 | | return gpg_error (GPG_ERR_GENERAL); |
1394 | | } |
1395 | | |
1396 | | rc = ksba_cert_new (&cert); |
1397 | | if (rc) |
1398 | | { |
1399 | | ksba_reader_release (reader); |
1400 | | return rc; |
1401 | | } |
1402 | | |
1403 | | rc = ksba_cert_read_der (cert, reader); |
1404 | | if (rc) |
1405 | | { |
1406 | | ksba_cert_release (cert); |
1407 | | ksba_reader_release (reader); |
1408 | | /* fixme: need to map the error codes */ |
1409 | | return gpg_error (GPG_ERR_GENERAL); |
1410 | | } |
1411 | | |
1412 | | rc = get_flag_from_image (buffer, length, KEYBOX_FLAG_BLOB, &blobflags); |
1413 | | if (!rc) |
1414 | | rc = ksba_cert_set_user_data (cert, "keydb.blobflags", |
1415 | | &blobflags, sizeof blobflags); |
1416 | | if (rc) |
1417 | | { |
1418 | | ksba_cert_release (cert); |
1419 | | ksba_reader_release (reader); |
1420 | | return gpg_error (rc); |
1421 | | } |
1422 | | |
1423 | | *r_cert = cert; |
1424 | | ksba_reader_release (reader); |
1425 | | return 0; |
1426 | | } |
1427 | | |
1428 | | #endif /*KEYBOX_WITH_X509*/ |
1429 | | |
1430 | | /* Return the flags named WHAT at the address of VALUE. IDX is used |
1431 | | only for certain flags and should be 0 if not required. */ |
1432 | | int |
1433 | | keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value) |
1434 | 0 | { |
1435 | 0 | const unsigned char *buffer; |
1436 | 0 | size_t length; |
1437 | 0 | gpg_err_code_t ec; |
1438 | |
|
1439 | 0 | (void)idx; /* Not yet used. */ |
1440 | |
|
1441 | 0 | if (!hd) |
1442 | 0 | return gpg_error (GPG_ERR_INV_VALUE); |
1443 | 0 | if (!hd->found.blob) |
1444 | 0 | return gpg_error (GPG_ERR_NOTHING_FOUND); |
1445 | | |
1446 | 0 | buffer = _keybox_get_blob_image (hd->found.blob, &length); |
1447 | 0 | ec = get_flag_from_image (buffer, length, what, value); |
1448 | 0 | return ec? gpg_error (ec):0; |
1449 | 0 | } |
1450 | | |
1451 | | off_t |
1452 | | keybox_offset (KEYBOX_HANDLE hd) |
1453 | 0 | { |
1454 | 0 | if (!hd->fp) |
1455 | 0 | return 0; |
1456 | 0 | return es_ftello (hd->fp); |
1457 | 0 | } |
1458 | | |
1459 | | gpg_error_t |
1460 | | keybox_seek (KEYBOX_HANDLE hd, off_t offset) |
1461 | 0 | { |
1462 | 0 | gpg_error_t err; |
1463 | |
|
1464 | 0 | if (hd->error) |
1465 | 0 | return hd->error; /* still in error state */ |
1466 | | |
1467 | 0 | if (! hd->fp) |
1468 | 0 | { |
1469 | 0 | if (!offset) |
1470 | 0 | { |
1471 | | /* No need to open the file. An unopened file is effectively at |
1472 | | offset 0. */ |
1473 | 0 | return 0; |
1474 | 0 | } |
1475 | | |
1476 | 0 | err = _keybox_ll_open (&hd->fp, hd->kb->fname, 0); |
1477 | 0 | if (err) |
1478 | 0 | return err; |
1479 | 0 | } |
1480 | | |
1481 | 0 | err = es_fseeko (hd->fp, offset, SEEK_SET); |
1482 | 0 | hd->error = gpg_error_from_errno (err); |
1483 | |
|
1484 | 0 | return hd->error; |
1485 | 0 | } |