Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / gdp / gdp_datum.c @ master

History | View | Annotate | Download (17.6 KB)

1 9509f13b Eric Allman
/* vim: set ai sw=4 sts=4 ts=4 :*/
2
3
/*
4
**  Message management
5
**
6
**                Messages contain the header and data information for a single
7
**                message.
8 055d3009 Eric Allman
**
9
**        ----- BEGIN LICENSE BLOCK -----
10
**        GDP: Global Data Plane Support Library
11
**        From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
12
**
13 c87dd166 Eric Allman
**        Copyright (c) 2015-2019, Regents of the University of California.
14 6bd5476b Eric Allman
**        All rights reserved.
15 055d3009 Eric Allman
**
16 6bd5476b Eric Allman
**        Permission is hereby granted, without written agreement and without
17
**        license or royalty fees, to use, copy, modify, and distribute this
18
**        software and its documentation for any purpose, provided that the above
19
**        copyright notice and the following two paragraphs appear in all copies
20
**        of this software.
21 055d3009 Eric Allman
**
22 6bd5476b Eric Allman
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
23
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
24
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
25
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 055d3009 Eric Allman
**
27 6bd5476b Eric Allman
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
28 055d3009 Eric Allman
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 6bd5476b Eric Allman
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
30
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
31
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
32
**        OR MODIFICATIONS.
33 055d3009 Eric Allman
**        ----- END LICENSE BLOCK -----
34 9509f13b Eric Allman
*/
35
36
#include <ep/ep.h>
37
#include <ep/ep_dbg.h>
38 3ddd2ed9 Eric Allman
#include <ep/ep_hexdump.h>
39 59fe1e09 Eric Allman
#include <ep/ep_prflags.h>
40 22442bd4 Eric Allman
#include <ep/ep_string.h>
41 9509f13b Eric Allman
#include <ep/ep_thr.h>
42
43 343366c2 Eric Allman
#include "gdp.h"
44 c9f4745b Eric Allman
#include "gdp_md.h"
45 9509f13b Eric Allman
#include "gdp_priv.h"
46
47 22442bd4 Eric Allman
#include <string.h>
48
49 9509f13b Eric Allman
static EP_DBG        Dbg = EP_DBG_INIT("gdp.datum", "GDP datum processing");
50
51
static gdp_datum_t                *DatumFreeList;
52 7882a3b0 Eric Allman
static EP_THR_MUTEX                DatumFreeListMutex EP_THR_MUTEX_INITIALIZER2(GDP_MUTEX_LORDER_LEAF);
53 9509f13b Eric Allman
54 e7b2a80c Eric Allman
55
/*
56
**  Create a new datum.
57
**                The datum is returned unlocked with a data buffer.
58
*/
59
60 9509f13b Eric Allman
gdp_datum_t *
61 2e65953f Eric Allman
gdp_datum_new(void)
62 9509f13b Eric Allman
{
63
        gdp_datum_t *datum;
64
65
        // get a message off the free list, if any
66
        ep_thr_mutex_lock(&DatumFreeListMutex);
67
        if ((datum = DatumFreeList) != NULL)
68
        {
69
                DatumFreeList = datum->next;
70
        }
71
        ep_thr_mutex_unlock(&DatumFreeListMutex);
72
73
        if (datum == NULL)
74
        {
75
                // nothing on the free list; allocate anew
76 fc0cbc23 Eric Allman
                datum = (gdp_datum_t *) ep_mem_zalloc(sizeof *datum);
77 9509f13b Eric Allman
                ep_thr_mutex_init(&datum->mutex, EP_THR_MUTEX_DEFAULT);
78 a72e8d44 Eric Allman
                ep_thr_mutex_setorder(&datum->mutex, GDP_MUTEX_LORDER_DATUM);
79 9509f13b Eric Allman
        }
80
        datum->next = NULL;
81
82 59fe1e09 Eric Allman
        EP_ASSERT(!EP_UT_BITSET(GDP_DF_INUSE, datum->flags));
83 9509f13b Eric Allman
84
        // initialize metadata
85 7bc0e2cf Eric Allman
        gdp_datum_reset(datum);
86 9509f13b Eric Allman
        ep_dbg_cprintf(Dbg, 48, "gdp_datum_new => %p\n", datum);
87 85b68a8f Eric Allman
        VALGRIND_HG_CLEAN_MEMORY(datum, sizeof *datum);
88 9509f13b Eric Allman
        return datum;
89
}
90
91
92
void
93
gdp_datum_free(gdp_datum_t *datum)
94
{
95
        ep_dbg_cprintf(Dbg, 48, "gdp_datum_free(%p)\n", datum);
96 a104a10f Eric Allman
97
        // sanity
98
        if (datum == NULL)
99
                return;
100 59fe1e09 Eric Allman
        EP_ASSERT_ELSE(EP_UT_BITSET(GDP_DF_INUSE, datum->flags), return);
101
        datum->flags = 0;
102 a104a10f Eric Allman
103 8f19d4ba Eric Allman
        if (datum->dbuf != NULL)
104
        {
105 197e9ea3 Eric Allman
                size_t ndrain = gdp_buf_getlength(datum->dbuf);
106 02de7463 Eric Allman
                ep_dbg_cprintf(Dbg, 50, "  ... draining %zd bytes\n", ndrain);
107
                if (ndrain > 0)
108 197e9ea3 Eric Allman
                        gdp_buf_drain(datum->dbuf, ndrain);
109 8f19d4ba Eric Allman
        }
110 48fe62d6 Eric Allman
        if (datum->sig != NULL)
111
        {
112
                //XXX retain this buffer?
113 fa7cfdb9 Eric Allman
                gdp_sig_free(datum->sig);
114 48fe62d6 Eric Allman
                datum->sig = NULL;
115
        }
116 e7b2a80c Eric Allman
117
        // make sure the datum is unlocked before putting on the free list
118
        if (ep_thr_mutex_trylock(&datum->mutex) != 0)
119
        {
120
                // shouldn't happen
121
                ep_dbg_cprintf(Dbg, 1, "gdp_datum_free(%p): was locked\n", datum);
122
        }
123
        ep_thr_mutex_unlock(&datum->mutex);
124 1ca7751e Eric Allman
#if GDP_DEBUG_NO_FREE_LISTS                // avoid helgrind complaints
125
        ep_thr_mutex_destroy(&datum->mutex);
126 fdeae6ab Eric Allman
        if (datum->dbuf == NULL)
127
                gdp_buf_free(datum->dbuf);
128 1ca7751e Eric Allman
        ep_mem_free(datum);
129
#else
130 9509f13b Eric Allman
        ep_thr_mutex_lock(&DatumFreeListMutex);
131
        datum->next = DatumFreeList;
132
        DatumFreeList = datum;
133
        ep_thr_mutex_unlock(&DatumFreeListMutex);
134 1ca7751e Eric Allman
#endif
135 9509f13b Eric Allman
}
136 22442bd4 Eric Allman
137
138 7bc0e2cf Eric Allman
/*
139
**  Reset a datum
140
**
141 d65c01e2 Eric Allman
**                This resets the data and signature buffers, but leaves the
142
**                timestamp and recno since the caller might like to see the
143
**                updated values.
144 7bc0e2cf Eric Allman
*/
145
146
void
147
gdp_datum_reset(gdp_datum_t *datum)
148
{
149
        if (datum->dbuf == NULL)
150
                datum->dbuf = gdp_buf_new();
151
        else
152
                gdp_buf_reset(datum->dbuf);
153
        if (datum->sig != NULL)
154 fa7cfdb9 Eric Allman
                gdp_sig_reset(datum->sig);
155 9852be60 Eric Allman
        datum->recno = GDP_PDU_NO_RECNO;
156 e1c055ad Eric Allman
        datum->flags = GDP_DF_INUSE;
157 9852be60 Eric Allman
        EP_TIME_INVALIDATE(&datum->ts);
158 7bc0e2cf Eric Allman
}
159
160
161 22442bd4 Eric Allman
gdp_recno_t
162
gdp_datum_getrecno(const gdp_datum_t *datum)
163
{
164
        return datum->recno;
165
}
166
167
void
168
gdp_datum_getts(const gdp_datum_t *datum, EP_TIME_SPEC *ts)
169
{
170
        memcpy(ts, &datum->ts, sizeof *ts);
171
}
172
173
size_t
174
gdp_datum_getdlen(const gdp_datum_t *datum)
175
{
176 7fc131d1 Eric Allman
        return gdp_buf_getlength(datum->dbuf);
177 22442bd4 Eric Allman
}
178
179
gdp_buf_t *
180 7fc131d1 Eric Allman
gdp_datum_getbuf(const gdp_datum_t *datum)
181 22442bd4 Eric Allman
{
182
        return datum->dbuf;
183
}
184
185 fa7cfdb9 Eric Allman
gdp_sig_t *
186 c8e97446 Eric Allman
gdp_datum_getsig(const gdp_datum_t *datum)
187
{
188
        return datum->sig;
189
}
190
191
192 22442bd4 Eric Allman
/*
193 7a52336b Eric Allman
**        GDP_DATUM_PRINT --- print a datum (for debugging)
194 22442bd4 Eric Allman
*/
195
196 59fe1e09 Eric Allman
static EP_PRFLAGS_DESC        DatumFlagsDesc[] =
197
{
198
        { GDP_DF_INUSE,                GDP_DF_INUSE,                "INUSE"                        },
199 e1c055ad Eric Allman
        { GDP_DF_GOODSIG,        GDP_DF_GOODSIG,                "GOODSIG"                },
200 59fe1e09 Eric Allman
        { 0,                                0,                                        NULL                        }
201
};
202
203 b42c4583 Eric Allman
void
204
gdp_datum_print(const gdp_datum_t *datum, FILE *fp, uint32_t flags)
205 22442bd4 Eric Allman
{
206
        unsigned char *d;
207
        int l;
208 87a0bdac Eric Allman
        bool quiet = EP_UT_BITSET(GDP_DATUM_PRQUIET, flags);
209
        bool debug = EP_UT_BITSET(GDP_DATUM_PRDEBUG, flags);
210
211 56f047d8 Eric Allman
        if (quiet && (debug || EP_UT_BITSET(GDP_DATUM_PRMETAONLY, flags)))
212 87a0bdac Eric Allman
                quiet = false;
213 22442bd4 Eric Allman
214 f095a16d Eric Allman
        if (!EP_ASSERT(fp != NULL))
215
                return;
216
217 2a8fd2c7 Eric Allman
        flockfile(fp);
218 87a0bdac Eric Allman
        if (debug)
219 153ffd95 Eric Allman
                fprintf(fp, "datum @ %p: ", datum);
220 22442bd4 Eric Allman
        if (datum == NULL)
221
        {
222 87a0bdac Eric Allman
                if (!quiet)
223
                        fprintf(fp, "null datum\n");
224 2a8fd2c7 Eric Allman
                goto done;
225 22442bd4 Eric Allman
        }
226 7a52336b Eric Allman
227 87a0bdac Eric Allman
        if (!quiet)
228
                fprintf(fp, "recno %" PRIgdp_recno ", ", datum->recno);
229 7a52336b Eric Allman
230 22442bd4 Eric Allman
        if (datum->dbuf == NULL)
231
        {
232 87a0bdac Eric Allman
                if (!quiet)
233
                        fprintf(fp, "no data");
234 22442bd4 Eric Allman
                d = NULL;
235
                l = -1;
236
        }
237
        else
238
        {
239
                l = gdp_buf_getlength(datum->dbuf);
240 87a0bdac Eric Allman
                if (!quiet)
241
                        fprintf(fp, "len %d", l);
242 37a1fb57 Eric Allman
                if (l > 0)
243
                        d = gdp_buf_getptr(datum->dbuf, l);
244
                else
245 f786d159 Eric Allman
                        d = (unsigned char *) "";
246 22442bd4 Eric Allman
        }
247
248 87a0bdac Eric Allman
        if (!quiet)
249 22442bd4 Eric Allman
        {
250 d2647d1f Eric Allman
                if (EP_TIME_IS_VALID(&datum->ts))
251 87a0bdac Eric Allman
                {
252
                        fprintf(fp, ", ts ");
253
                        ep_time_print(&datum->ts, fp, EP_TIME_FMT_HUMAN);
254
                }
255
                else
256
                {
257
                        fprintf(fp, ", no timestamp");
258
                }
259 22442bd4 Eric Allman
260 59fe1e09 Eric Allman
                if (debug)
261
                {
262
                        fprintf(fp, ", flags ");
263
                        ep_prflags(datum->flags, DatumFlagsDesc, fp);
264
                }
265
                fprintf(fp, "\n");
266 87a0bdac Eric Allman
        }
267 7a52336b Eric Allman
268 15d8c53d Eric Allman
        if (!EP_UT_BITSET(GDP_DATUM_PRMETAONLY, flags))
269
        {
270
                if (EP_UT_BITSET(GDP_DATUM_PRTEXT, flags))
271 6218b529 Rick Pratt
                        fprintf(fp, "%.*s\n", l, d);
272 c3369218 Eric Allman
                else if (EP_UT_BITSET(GDP_DATUM_PRBINARY, flags))
273
                        fwrite(fp, l, 1, fp);
274 15d8c53d Eric Allman
                else
275
                        ep_hexdump(d, l, fp, EP_HEXDUMP_ASCII, 0);
276
        }
277 c8e97446 Eric Allman
278
        if (EP_UT_BITSET(GDP_DATUM_PRSIG, flags))
279
        {
280 15d8c53d Eric Allman
                if (datum->sig != NULL)
281 c8e97446 Eric Allman
                {
282 fa7cfdb9 Eric Allman
                        size_t siglen;
283
                        d = gdp_sig_getptr(datum->sig, &siglen);
284 15d8c53d Eric Allman
                        if (siglen > 0)
285
                        {
286
                                fprintf(fp, "  sig\n");
287
                                ep_hexdump(d, siglen, fp, EP_HEXDUMP_HEX, 0);
288
                        }
289
                        else
290
                                fprintf(fp, "  empty sig\n");
291 c8e97446 Eric Allman
                }
292 15d8c53d Eric Allman
                else
293
                        fprintf(fp, "  no sig\n");
294 c8e97446 Eric Allman
        }
295 2a8fd2c7 Eric Allman
done:
296
        funlockfile(fp);
297 22442bd4 Eric Allman
}
298 153ffd95 Eric Allman
299
300 e7b2a80c Eric Allman
/*
301 39fae5ac Eric Allman
**  Copy contents of one datum into another
302
*/
303
304
void
305
gdp_datum_copy(gdp_datum_t *to, const gdp_datum_t *from)
306
{
307
        to->recno = from->recno;
308
        to->ts = from->ts;
309 59fe1e09 Eric Allman
        to->flags = from->flags;
310 39fae5ac Eric Allman
        if (from->dbuf != NULL)
311
        {
312 2a8cda22 Eric Allman
                if (EP_ASSERT(to->dbuf != NULL))
313 39fae5ac Eric Allman
                        gdp_buf_copy(to->dbuf, from->dbuf);
314
        }
315
        if (from->sig != NULL)
316
        {
317 2a8cda22 Eric Allman
                if (EP_ASSERT(to->sig != NULL))
318 fa7cfdb9 Eric Allman
                        gdp_sig_copy(to->sig, from->sig);
319 39fae5ac Eric Allman
        }
320
}
321
322
323
/*
324 e7b2a80c Eric Allman
**  Duplicate a datum (internal use)
325
*/
326
327
gdp_datum_t *
328
gdp_datum_dup(const gdp_datum_t *datum)
329
{
330
        gdp_datum_t *ndatum;
331
332 2e65953f Eric Allman
        ndatum = gdp_datum_new();
333 e7b2a80c Eric Allman
        ndatum->recno = datum->recno;
334
        ndatum->ts = datum->ts;
335
        gdp_buf_copy(ndatum->dbuf, datum->dbuf);
336
        if (datum->sig != NULL)
337 fa7cfdb9 Eric Allman
                ndatum->sig = gdp_sig_dup(datum->sig);
338 e7b2a80c Eric Allman
339
        return ndatum;
340
}
341
342
343 fa7cfdb9 Eric Allman
/*
344
**  Print a datum (for debugging)
345
*/
346
347 153ffd95 Eric Allman
void
348
_gdp_datum_dump(const gdp_datum_t *datum,
349
                        FILE *fp)
350
{
351 9cacb7ea Eric Allman
        if (fp == NULL)
352
                fp = ep_dbg_getfile();
353 b42c4583 Eric Allman
        gdp_datum_print(datum, fp, GDP_DATUM_PRDEBUG);
354 153ffd95 Eric Allman
}
355 d65c01e2 Eric Allman
356 c9f4745b Eric Allman
/*
357 fa7cfdb9 Eric Allman
**  Incorporate a datum into a pre-existing message digest.
358
**  This can also be used when signing and verifying.
359
**
360
**  The message digest must already be initialized, and can already
361
**  have data included in it.  Generally speaking, this will include at
362
**  a minimum the name of the log in which this data is stored, which
363
**  itself will be the hash of the metadata for that log.  This allows
364
**  this routine to be usable for both computing a basic hash and for
365
**  signing.
366
**
367
**  This routine adds to the existing digest:
368
**                * record number
369
**                * timestamp
370
**                * hash of previous datum
371 2da682ef Eric Allman
**                * the "proof" (hash back pointers and offsets)
372 fa7cfdb9 Eric Allman
**                * hash of data payload
373
**
374
**        If the datum does not yet include the hash of the data payload,
375
**        that will be computed and cached.
376
*/
377
378 1042a70f Eric Allman
EP_STAT
379 fa7cfdb9 Eric Allman
_gdp_datum_digest(gdp_datum_t *datum, EP_CRYPTO_MD *md)
380
{
381 2da682ef Eric Allman
        if (ep_dbg_test(Dbg, 50))
382
        {
383
                ep_dbg_printf("_gdp_datum_digest: ");
384
                _gdp_datum_dump(datum, NULL);
385
        }
386
387 1042a70f Eric Allman
        // check for upstream problems and avoid core dumps
388
        if (md == NULL)
389
                return GDP_STAT_CRYPTO_ERROR;
390
391 2da682ef Eric Allman
        // now compute H(recno || timestamp || prevHash || proof || H(data))
392 fa7cfdb9 Eric Allman
        // recno
393
        {
394
                uint8_t recnobuf[8];                // 64 bits
395
                uint8_t *pbp = recnobuf;
396
                PUT64(datum->recno);
397
                ep_crypto_md_update(md, &recnobuf, sizeof recnobuf);
398
        }
399
        // timestamp
400
        {
401
                uint8_t tsbuf[16];                        // 64 + 32 + 32 bits
402
                uint8_t *pbp = tsbuf;
403
                PUT64(datum->ts.tv_sec);
404
                PUT32(datum->ts.tv_nsec);
405
                PUT32(*(uint32_t *) &datum->ts.tv_accuracy);
406
                ep_crypto_md_update(md, tsbuf, sizeof tsbuf);
407
        }
408
        // prevhash
409
        if (datum->prevhash != NULL)
410
        {
411
                size_t prevhashlen;
412
                void *hashbytes = gdp_hash_getptr(datum->prevhash, &prevhashlen);
413
                ep_crypto_md_update(md, hashbytes, prevhashlen);
414
        }
415 2da682ef Eric Allman
        // proof
416
        //TODO: include proof
417 fa7cfdb9 Eric Allman
        // data hash
418
        {
419 b7d4c21d Eric Allman
                int hashalg = ep_crypto_md_type(md);
420 1042a70f Eric Allman
                EP_CRYPTO_MD *dmd;
421
                EP_STAT estat = ep_crypto_md_new(hashalg, &dmd);
422
423
                if (!EP_STAT_ISOK(estat))
424
                {
425
                        char ebuf[100];
426
                        ep_dbg_cprintf(Dbg, 9,
427
                                        "_gdp_datum_digest: ep_crypto_md_new(%d) => %s\n",
428
                                        hashalg, ep_stat_tostr(estat, ebuf, sizeof ebuf));
429
                        return estat;
430
                }
431 b7d4c21d Eric Allman
                if (datum->dbuf != NULL)
432
                {
433
                        size_t dlen = gdp_buf_getlength(datum->dbuf);
434
                        ep_crypto_md_update(dmd, gdp_buf_getptr(datum->dbuf, dlen), dlen);
435
                }
436
437
                uint8_t dhash[EP_CRYPTO_MAX_DIGEST];
438
                size_t dhlen = sizeof dhash;
439
                ep_crypto_md_final(dmd, &dhash, &dhlen);
440
                ep_crypto_md_free(dmd);
441
                ep_crypto_md_update(md, dhash, dhlen);
442 fa7cfdb9 Eric Allman
        }
443 1042a70f Eric Allman
        return EP_STAT_OK;
444 fa7cfdb9 Eric Allman
}
445
446
447 8cfe4117 Eric Allman
/*
448
**  Compute hash of a datum.
449
**
450
**                Two versions, one using a GIN, other using a GOB.
451 2da682ef Eric Allman
**                This is not usable for signing or verification.
452 8cfe4117 Eric Allman
*/
453
454 fa7cfdb9 Eric Allman
gdp_hash_t *
455 8cfe4117 Eric Allman
gdp_datum_hash(gdp_datum_t *datum, gdp_gin_t *gin)
456
{
457
        return _gdp_datum_hash(datum, gin->gob);
458
}
459
460
461
gdp_hash_t *
462 c9f4745b Eric Allman
_gdp_datum_hash(gdp_datum_t *datum, gdp_gob_t *gob)
463 fa7cfdb9 Eric Allman
{
464 c9f4745b Eric Allman
        if (gob->vrfy_ctx == NULL)
465 e1c055ad Eric Allman
        {
466
                EP_STAT estat = _gdp_gob_init_vrfy_ctx(gob);
467
                if (gob->vrfy_ctx == NULL)
468
                {
469
                        char ebuf[100];
470
                        ep_dbg_cprintf(Dbg, 3, "_gdp_datum_hash(init): %s\n",
471
                                        ep_stat_tostr(estat, ebuf, sizeof ebuf));
472
                        return NULL;
473
                }
474
        }
475 fa7cfdb9 Eric Allman
476 c9f4745b Eric Allman
        EP_CRYPTO_MD *md = ep_crypto_md_clone(gob->vrfy_ctx);
477 fa7cfdb9 Eric Allman
        _gdp_datum_digest(datum, md);
478
        uint8_t mdbuf[EP_CRYPTO_MAX_DIGEST];
479
        size_t mdlen = sizeof mdbuf;
480
        ep_crypto_md_final(md, &mdbuf, &mdlen);
481
        ep_crypto_md_free(md);
482 2da682ef Eric Allman
        gdp_hash_t *hash = gdp_hash_new(gob->hashalg, mdbuf, mdlen);
483 fa7cfdb9 Eric Allman
        return hash;
484
}
485
486
487
/*
488
**  Check a datum hash for equality
489
*/
490
491
bool
492 8cfe4117 Eric Allman
gdp_datum_hash_equal(gdp_datum_t *datum,
493
                                        const gdp_gin_t *gin,
494
                                        const gdp_hash_t *hash)
495
{
496
        return _gdp_datum_hash_equal(datum, gin->gob, hash);
497
}
498
499
bool
500 fa7cfdb9 Eric Allman
_gdp_datum_hash_equal(gdp_datum_t *datum,
501 c9f4745b Eric Allman
                                        gdp_gob_t *gob,
502 8cfe4117 Eric Allman
                                        const gdp_hash_t *hash)
503 fa7cfdb9 Eric Allman
{
504
        bool r = false;
505 8cfe4117 Eric Allman
        gdp_hash_t *newhash = _gdp_datum_hash(datum, gob);
506 fa7cfdb9 Eric Allman
507
        if (gdp_hash_equal(hash, newhash))
508
                r = true;
509
        gdp_hash_free(newhash);
510
        return r;
511
}
512
513
514
/*
515 53393e9c Eric Allman
**  Convert internal datum structure to protobuf-encoded datum.
516
**  Assumes the protobuf version is empty on entry.
517
*/
518
519 d65c01e2 Eric Allman
void
520 7f74c3b3 Eric Allman
_gdp_datum_to_pb(const gdp_datum_t *datum,
521
                                GdpMessage *msg,
522 53393e9c Eric Allman
                                GdpDatum *pbd)
523 d65c01e2 Eric Allman
{
524 9852be60 Eric Allman
        // recno
525 53393e9c Eric Allman
        pbd->recno = datum->recno;
526 9852be60 Eric Allman
527
        // timestamp
528 d65c01e2 Eric Allman
        if (EP_TIME_IS_VALID(&datum->ts))
529
        {
530 53393e9c Eric Allman
                if (pbd->ts == NULL)
531 d65c01e2 Eric Allman
                {
532 53393e9c Eric Allman
                        pbd->ts = (GdpTimestamp *) ep_mem_zalloc(sizeof *pbd->ts);
533
                        gdp_timestamp__init(pbd->ts);
534 d65c01e2 Eric Allman
                }
535 53393e9c Eric Allman
                pbd->ts->sec = datum->ts.tv_sec;
536 9852be60 Eric Allman
                pbd->ts->has_sec = true;
537 53393e9c Eric Allman
                pbd->ts->nsec = datum->ts.tv_nsec;
538 9852be60 Eric Allman
                pbd->ts->has_nsec = pbd->ts->nsec != 0;
539 53393e9c Eric Allman
                pbd->ts->accuracy = datum->ts.tv_accuracy;
540 9852be60 Eric Allman
                pbd->ts->has_accuracy = pbd->ts->accuracy != 0.0;
541 d65c01e2 Eric Allman
        }
542 9852be60 Eric Allman
        else if (pbd->ts != NULL)
543
        {
544 e95fef13 Eric Allman
                ep_dbg_cprintf(Dbg, 3, "_gdp_datum_to_pb: freeing ts\n");
545 9852be60 Eric Allman
                gdp_timestamp__free_unpacked(pbd->ts, NULL);
546
                pbd->ts = NULL;
547
        }
548
549
        // data payload
550 d65c01e2 Eric Allman
        if (datum->dbuf != NULL && gdp_buf_getlength(datum->dbuf) > 0)
551
        {
552
                size_t l = gdp_buf_getlength(datum->dbuf);
553 fa7cfdb9 Eric Allman
                pbd->data.len = l;
554 53393e9c Eric Allman
                pbd->data.data = (uint8_t *) ep_mem_malloc(l);
555
                memcpy(pbd->data.data, gdp_buf_getptr(datum->dbuf, l), l);
556 d65c01e2 Eric Allman
        }
557
558 9852be60 Eric Allman
        // hash of previous record
559 fa7cfdb9 Eric Allman
        if (datum->prevhash == NULL)
560
                pbd->has_prevhash = false;
561
        else
562
        {
563
                size_t l = gdp_hash_getlength(datum->prevhash);
564
                pbd->has_prevhash = true;
565
                pbd->prevhash.len = l;
566
                if (pbd->prevhash.data != NULL)
567
                        ep_mem_free(pbd->prevhash.data);
568
                pbd->prevhash.data = (uint8_t *) ep_mem_malloc(l);
569
                memcpy(pbd->prevhash.data, gdp_hash_getptr(datum->prevhash, NULL), l);
570
        }
571
572 9852be60 Eric Allman
        // signature
573 fa7cfdb9 Eric Allman
        if (datum->sig != NULL)
574
        {
575
                if (pbd->sig == NULL)
576
                {
577
                        pbd->sig = (GdpSignature *) ep_mem_malloc(sizeof *pbd->sig);
578
                        gdp_signature__init(pbd->sig);
579
                }
580
                size_t l;
581
                void *sigdata = gdp_sig_getptr(datum->sig, &l);
582
                pbd->sig->sig.len = l;
583
                if (pbd->sig->sig.data != NULL)
584
                        ep_mem_free(pbd->sig->sig.data);
585
                pbd->sig->sig.data = ep_mem_malloc(l);
586
                memcpy(pbd->sig->sig.data, sigdata, l);
587
        }
588 b6423859 Eric Allman
        else if (pbd->sig != NULL)
589 fa7cfdb9 Eric Allman
        {
590 e95fef13 Eric Allman
                ep_dbg_cprintf(Dbg, 3, "_gdp_datum_to_pb: freeing sig\n");
591 fa7cfdb9 Eric Allman
                gdp_signature__free_unpacked(pbd->sig, NULL);
592
                pbd->sig = NULL;
593
        }
594 d65c01e2 Eric Allman
}
595
596
597 53393e9c Eric Allman
/*
598
**  Convert protobuf-encoded datum to internal datum structure.
599
*/
600
601 d65c01e2 Eric Allman
void
602 bd278f2e Eric Allman
_gdp_timestamp_from_pb(EP_TIME_SPEC *ts,
603
                                const GdpTimestamp *pbd)
604
{
605
        if (pbd != NULL)
606
        {
607
                ts->tv_sec = pbd->sec;
608
                ts->tv_nsec = pbd->nsec;
609
                ts->tv_accuracy = pbd->accuracy;
610
        }
611
        else
612
        {
613
                EP_TIME_INVALIDATE(ts);
614
        }
615
}
616
617
void
618 7f74c3b3 Eric Allman
_gdp_datum_from_pb(gdp_datum_t *datum,
619 9f6be413 Eric Allman
                                const GdpDatum *pbd,
620
                                const GdpSignature *sig)
621 d65c01e2 Eric Allman
{
622
        // recno
623 53393e9c Eric Allman
        datum->recno = pbd->recno;
624 d65c01e2 Eric Allman
625
        // timestamp
626 bd278f2e Eric Allman
        _gdp_timestamp_from_pb(&datum->ts, pbd->ts);
627 d65c01e2 Eric Allman
628
        // data
629
        if (datum->dbuf == NULL)
630
                datum->dbuf = gdp_buf_new();
631 53393e9c Eric Allman
        gdp_buf_write(datum->dbuf, pbd->data.data, pbd->data.len);
632 7f74c3b3 Eric Allman
633
        // signature
634 9f6be413 Eric Allman
        if (sig != NULL)
635 7f74c3b3 Eric Allman
        {
636
                if (datum->sig == NULL)
637 2da682ef Eric Allman
                        datum->sig = gdp_sig_new(0, NULL, 0);
638 9f6be413 Eric Allman
                gdp_sig_set(datum->sig, sig->sig.data, sig->sig.len);
639 fa7cfdb9 Eric Allman
        }
640
}
641
642
643
/*
644
**  Sign a datum
645
**
646
**                gob->digest must already be set up to contain the header part
647
**                of the signature before this is called.  Since this also
648
**                includes the secret key, it isn't passed in here.
649
**                The signature is left in the datum.
650
*/
651
652
EP_STAT
653
_gdp_datum_sign(gdp_datum_t *datum, gdp_gob_t *gob)
654
{
655
        EP_STAT estat;
656
657 c9f4745b Eric Allman
        if (gob->sign_ctx == NULL)
658 fa7cfdb9 Eric Allman
        {
659 c9f4745b Eric Allman
                ep_dbg_cprintf(Dbg, 1, "_gdp_datum_sign: null GOB signature digest\n");
660 49d76189 Eric Allman
                return GDP_STAT_CRYPTO_SKEY_REQUIRED;
661 fa7cfdb9 Eric Allman
        }
662
663 c9f4745b Eric Allman
        EP_CRYPTO_MD *md = ep_crypto_md_clone(gob->sign_ctx);
664 2da682ef Eric Allman
        _gdp_datum_digest(datum, md);
665 fa7cfdb9 Eric Allman
666
        // now get the final signature
667 2da682ef Eric Allman
        uint8_t sigbuf[EP_CRYPTO_MAX_SIG];
668 fa7cfdb9 Eric Allman
        size_t siglen = sizeof sigbuf;
669
        estat = ep_crypto_sign_final(md, sigbuf, &siglen);
670
671
        // transfer the signature into the datum
672
        if (EP_STAT_ISOK(estat))
673
        {
674
                if (datum->sig == NULL)
675 2da682ef Eric Allman
                        datum->sig = gdp_sig_new(gob->hashalg, NULL, 0);
676 fa7cfdb9 Eric Allman
                gdp_sig_set(datum->sig, sigbuf, siglen);
677 7f74c3b3 Eric Allman
        }
678 2da682ef Eric Allman
        else if (ep_dbg_test(Dbg, 1))
679
        {
680
                char ebuf[100];
681
                ep_dbg_printf("_gdp_datum_sign: ep_crypto_sign_final => %s\n",
682
                                        ep_stat_tostr(estat, ebuf, sizeof ebuf));
683
        }
684 fa7cfdb9 Eric Allman
685
        // zero out sigbuf (good hygiene)
686
        memset(sigbuf, 0, sizeof sigbuf);
687
        return estat;
688 d65c01e2 Eric Allman
}
689 c9f4745b Eric Allman
690
691
/*
692
**  Verify datum signature
693
**
694
**                This also initializes the message digest (hash) field, even if
695
**                we don't have a public key, so it's important that this be
696
**                called even if we don't care about the signature.
697
*/
698
699
EP_STAT
700
gdp_datum_vrfy(gdp_datum_t *datum, gdp_gin_t *gin)
701
{
702 e1c055ad Eric Allman
        // if signature already verified, don't do it again
703
        if (EP_UT_BITSET(GDP_DF_GOODSIG, datum->flags))
704
        {
705
                ep_dbg_cprintf(Dbg, 32, "gdp_datum_vrfy: already OK\n");
706
                return EP_STAT_OK;
707
        }
708
709 c9f4745b Eric Allman
        return _gdp_datum_vrfy_gob(datum, gin->gob);
710
}
711
712
EP_STAT
713
_gdp_datum_vrfy_gob(gdp_datum_t *datum, gdp_gob_t *gob)
714
{
715
        EP_STAT estat = EP_STAT_OK;
716
717
        if (gob->vrfy_ctx == NULL)
718 e1c055ad Eric Allman
        {
719
                // sets up message digest hash even if no public key
720 ee0cddb9 Eric Allman
                estat = _gdp_gob_init_vrfy_ctx(gob);
721 e1c055ad Eric Allman
                if (!EP_STAT_ISOK(estat))
722
                {
723
                        char ebuf[100];
724
                        ep_dbg_cprintf(Dbg, 30,
725
                                        "gdp_datum_vrfy(init): %s\n",
726
                                        ep_stat_tostr(estat, ebuf, sizeof ebuf));
727
                        estat = GDP_STAT_CRYPTO_NO_PUB_KEY;
728
                        goto nopubkey;
729
                }
730
        }
731 c9f4745b Eric Allman
732
        // if we aren't verifying we can quit now
733
        if (!EP_UT_BITSET(GOBF_VERIFYING, gob->flags))
734
        {
735 e1c055ad Eric Allman
                // not verifying: no public key
736 738cd5c6 Eric Allman
                ep_dbg_cprintf(Dbg, 21, "gdp_datum_vrfy: no pub key\n");
737 e1c055ad Eric Allman
                return GDP_STAT_CRYPTO_NO_PUB_KEY;
738 c9f4745b Eric Allman
        }
739
740 2331d9f7 Eric Allman
        // if there's no signature we can give up now
741
        size_t siglen;
742
        if (datum->sig == NULL || (siglen = gdp_sig_getlength(datum->sig)) <= 0)
743
        {
744
                ep_dbg_cprintf(Dbg, 31, "gdp_datum_vrfy: no signature\n");
745
                return GDP_STAT_CRYPTO_SIG_MISSING;
746
        }
747
748 c9f4745b Eric Allman
        EP_CRYPTO_MD *md = ep_crypto_md_clone(gob->vrfy_ctx);
749
750
        _gdp_datum_digest(datum, md);
751
        size_t len = gdp_sig_getlength(datum->sig);
752
        estat = ep_crypto_vrfy_final(md, gdp_sig_getptr(datum->sig, NULL), len);
753
        ep_crypto_md_free(md);
754
        if (!EP_STAT_ISOK(estat))
755
        {
756 e1c055ad Eric Allman
                // error: signature failure
757 caef25cd Eric Allman
                char ebuf[100];
758 e1c055ad Eric Allman
                ep_dbg_cprintf(Dbg, 31, "gdp_datum_vrfy(final): %s\n",
759 caef25cd Eric Allman
                                        ep_stat_tostr(estat, ebuf, sizeof ebuf));
760 c9f4745b Eric Allman
                if (EP_UT_BITSET(GOBF_VRFY_WARN, gob->flags))
761
                {
762
                        ep_dbg_cprintf(Dbg, 31,
763
                                                "gdp_datum_vrfy: signature failure (warn)\n");
764
                        estat = EP_STAT_OK;                //XXX: perhaps a warning status?
765 e1c055ad Eric Allman
766
                        // pretend the verification succeeded
767
                        datum->flags |= GDP_DF_GOODSIG;
768 c9f4745b Eric Allman
                }
769
                else
770
                {
771
                        ep_dbg_cprintf(Dbg, 1,
772
                                                "gdp_datum_vrfy: signature failure (fail)\n");
773 e1c055ad Eric Allman
                        estat = GDP_STAT_CRYPTO_VRFY_FAIL;
774 c9f4745b Eric Allman
                }
775
        }
776
        else
777
        {
778 e1c055ad Eric Allman
                // successful verification
779
                datum->flags |= GDP_DF_GOODSIG;
780
781
nopubkey:
782
                {
783
                        int lev = EP_STAT_ISOK(estat) ? 51 : 31;
784
                        char ebuf[100];
785
                        ep_dbg_cprintf(Dbg, lev, "gdp_datum_vrfy: %s\n",
786
                                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
787
                }
788 c9f4745b Eric Allman
        }
789
        return estat;
790
}