diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2013-03-17 13:06:02 +0100 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2013-03-17 13:06:02 +0100 |
commit | d2467c38d42f590deecd807741324fc0e5522a8a (patch) | |
tree | c9d56cee1e0119ba9bd5f516a68bd7e1269712fe /runtime | |
parent | 44b4922825df794f678cd4ad18d940ff114b943f (diff) | |
download | rsyslog-d2467c38d42f590deecd807741324fc0e5522a8a.tar.gz rsyslog-d2467c38d42f590deecd807741324fc0e5522a8a.tar.bz2 rsyslog-d2467c38d42f590deecd807741324fc0e5522a8a.zip |
logsig: milestone/verfier: record hashes are verified
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/librsgt.c | 6 | ||||
-rw-r--r-- | runtime/librsgt.h | 33 | ||||
-rw-r--r-- | runtime/librsgt_read.c | 126 | ||||
-rw-r--r-- | runtime/lmsig_gt.c | 12 |
4 files changed, 172 insertions, 5 deletions
diff --git a/runtime/librsgt.c b/runtime/librsgt.c index 83a2fe05..e49011f4 100644 --- a/runtime/librsgt.c +++ b/runtime/librsgt.c @@ -514,7 +514,7 @@ bufAddLevel(uchar *buf, size_t *len, uint8_t level) } -static void +void hash_m(gtfile gf, GTDataHash **m) { #warning Overall: check GT API return states! @@ -527,7 +527,7 @@ hash_m(gtfile gf, GTDataHash **m) GTDataHash_create(gf->hashAlg, concatBuf, len, m); } -static inline void +void hash_r(gtfile gf, GTDataHash **r, const uchar *rec, const size_t len) { // r = hash(canonicalize(rec)); @@ -535,7 +535,7 @@ hash_r(gtfile gf, GTDataHash **r, const uchar *rec, const size_t len) } -static void +void hash_node(gtfile gf, GTDataHash **node, GTDataHash *m, GTDataHash *r, uint8_t level) { diff --git a/runtime/librsgt.h b/runtime/librsgt.h index d9d221ea..35ee96b5 100644 --- a/runtime/librsgt.h +++ b/runtime/librsgt.h @@ -120,6 +120,12 @@ struct rsgtstatefile { given in block-sig record */ #define RSGTE_INVLHDR 8/* invalid file header */ #define RSGTE_EOF 9 /* specific EOF */ +#define RSGTE_MISS_REC_HASH 10 /* record hash missing when expected */ +#define RSGTE_MISS_TREE_HASH 11 /* tree hash missing when expected */ +#define RSGTE_INVLD_REC_HASH 12 /* invalid record hash (failed verification) */ +#define RSGTE_INVLD_TREE_HASH 13 /* invalid tree hash (failed verification) */ +#define RSGTE_INVLD_REC_HASHID 14 /* invalid record hash ID (failed verification) */ +#define RSGTE_INVLD_TREE_HASHID 15 /* invalid tree hash ID (failed verification) */ static inline uint16_t @@ -180,6 +186,26 @@ hashAlgName(uint8_t hashID) default:return "[unknown]"; } } +static inline enum GTHashAlgorithm +hashID2Alg(uint8_t hashID) +{ + switch(hashID) { + case 0x00: + return GT_HASHALG_SHA1; + case 0x02: + return GT_HASHALG_RIPEMD160; + case 0x03: + return GT_HASHALG_SHA224; + case 0x01: + return GT_HASHALG_SHA256; + case 0x04: + return GT_HASHALG_SHA384; + case 0x05: + return GT_HASHALG_SHA512; + default: + return 0xff; + } +} static inline char * sigTypeName(uint8_t sigID) { @@ -233,5 +259,12 @@ void rsgt_tlvprint(FILE *fp, uint16_t tlvtype, void *obj, uint8_t verbose); void rsgt_printBLOCK_SIG(FILE *fp, block_sig_t *bs, uint8_t verbose); int rsgt_getBlockParams(FILE *fp, uint8_t bRewind, block_sig_t **bs, uint8_t *bHasRecHashes, uint8_t *bHasIntermedHashes); int rsgt_chkFileHdr(FILE *fp, char *expect); +gtfile rsgt_vrfyConstruct_gf(void); +void rsgt_vrfyBlkInit(gtfile gf, block_sig_t *bs, uint8_t bHasRecHashes, uint8_t bHasIntermedHashes); +int rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, size_t lenRec); +/* TODO: replace these? */ +void hash_m(gtfile gf, GTDataHash **m); +void hash_r(gtfile gf, GTDataHash **r, const unsigned char *rec, const size_t len); +void hash_node(gtfile gf, GTDataHash **node, GTDataHash *m, GTDataHash *r, uint8_t level); #endif /* #ifndef INCLUDED_LIBRSGT_H */ diff --git a/runtime/librsgt_read.c b/runtime/librsgt_read.c index 961e50c5..ca52cb93 100644 --- a/runtime/librsgt_read.c +++ b/runtime/librsgt_read.c @@ -277,6 +277,22 @@ rsgt_tlvrdIMPRINT(FILE *fp, imprint_t **imprint, uint16_t tlvlen) done: return r; } +static int +rsgt_tlvrdRecHash(FILE *fp, imprint_t **imp) +{ + int r; + uint16_t tlvtype, tlvlen; + + if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; +printf("read tlvtype %4.4x\n", tlvtype); + if(tlvtype != 0x0900) { + r = RSGTE_MISS_REC_HASH; + goto done; + } + if((r = rsgt_tlvrdIMPRINT(fp, imp, tlvlen)) != 0) goto done; + r = 0; +done: return r; +} /**; * Read the next "object" from file. This usually is @@ -528,3 +544,113 @@ rsgt_chkFileHdr(FILE *fp, char *expect) done: return r; } + +gtfile +rsgt_vrfyConstruct_gf(void) +{ + gtfile gf; + if((gf = calloc(1, sizeof(struct gtfile_s))) == NULL) + goto done; + gf->x_prev = NULL; + +done: return gf; +} + +void +rsgt_vrfyBlkInit(gtfile gf, block_sig_t *bs, uint8_t bHasRecHashes, uint8_t bHasIntermedHashes) +{ +printf("bs->hashID %d\n", bs->hashID); + gf->hashAlg = hashID2Alg(bs->hashID); + gf->bKeepRecordHashes = bHasRecHashes; + gf->bKeepTreeHashes = bHasIntermedHashes; + free(gf->IV); + gf->IV = malloc(getIVLen(bs)); + memcpy(gf->IV, bs->iv, getIVLen(bs)); +} + +static int +rsgt_vrfy_chkRecHash(gtfile gf, FILE *sigfp, GTDataHash *recHash) +{ + int r = 0; + imprint_t *imp; + + if(!gf->bKeepRecordHashes) + goto done; + if((r = rsgt_tlvrdRecHash(sigfp, &imp)) != 0) + goto done; + if(imp->hashID != hashIdentifier(gf->hashAlg)) { + r = RSGTE_INVLD_REC_HASHID; + goto done; + } +printf("imp hash:"); +outputHexBlob(stdout, imp->data, hashOutputLengthOctets(imp->hashID), 1); +printf("\nrec hash:"); +outputHexBlob(stdout, recHash->digest, hashOutputLengthOctets(imp->hashID), 1); +printf("\n"); + if(memcmp(imp->data, recHash->digest, + hashOutputLengthOctets(imp->hashID))) { + r = RSGTE_INVLD_REC_HASH; + goto done; + } +printf("record hash is OK\n"); + r = 0; +done: + return r; +} + +int +rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, + size_t len) +{ + int r = 0; + GTDataHash *x; /* current hash */ + GTDataHash *m, *recHash, *t; + uint8_t j; + +printf("hasRecHash %d, verify: %s", gf->bKeepRecordHashes, rec); + hash_m(gf, &m); + hash_r(gf, &recHash, rec, len); + if(gf->bKeepRecordHashes) { + r = rsgt_vrfy_chkRecHash(gf, sigfp, recHash); + if(r != 0) goto done; + } + hash_node(gf, &x, m, recHash, 1); /* hash leaf */ + /* persists x here if Merkle tree needs to be persisted! */ + //if(gf->bKeepTreeHashes) + //tlvWriteHash(gf, 0x0901, x); + /* add x to the forest as new leaf, update roots list */ + t = x; + for(j = 0 ; j < gf->nRoots ; ++j) { + if(gf->roots_valid[j] == 0) { + gf->roots_hash[j] = t; + gf->roots_valid[j] = 1; + t = NULL; + break; + } else if(t != NULL) { + /* hash interim node */ + hash_node(gf, &t, gf->roots_hash[j], t, j+2); + gf->roots_valid[j] = 0; + GTDataHash_free(gf->roots_hash[j]); + // TODO: check if this is correct location (paper!) + //if(gf->bKeepTreeHashes) + //tlvWriteHash(gf, 0x0901, t); + } + } + if(t != NULL) { + /* new level, append "at the top" */ + gf->roots_hash[gf->nRoots] = t; + gf->roots_valid[gf->nRoots] = 1; + ++gf->nRoots; + assert(gf->nRoots < MAX_ROOTS); + t = NULL; + } + gf->x_prev = x; /* single var may be sufficient */ + ++gf->nRecords; + + /* cleanup */ + /* note: x is freed later as part of roots cleanup */ + GTDataHash_free(m); + GTDataHash_free(recHash); +done: + return r; +} diff --git a/runtime/lmsig_gt.c b/runtime/lmsig_gt.c index 021cd9f8..54a795a1 100644 --- a/runtime/lmsig_gt.c +++ b/runtime/lmsig_gt.c @@ -130,12 +130,20 @@ dbgprintf("DDDD: onFileOpen: %s\n", fn); RETiRet; } +/* Note: we assume that the record is terminated by a \n. + * As of the GuardTime paper, \n is not part of the signed + * message, so we subtract one from the record size. This + * may cause issues with non-standard formats, but let's + * see how things evolve (the verifier will not work in + * any case when the records are not \n delimited...). + * rgerhards, 2013-03-17 + */ static rsRetVal OnRecordWrite(void *pF, uchar *rec, rs_size_t lenRec) { DEFiRet; -dbgprintf("DDDD: onRecordWrite (%d): %s\n", lenRec, rec); - sigblkAddRecord(pF, rec, lenRec); +dbgprintf("DDDD: onRecordWrite (%d): %s\n", lenRec-1, rec); + sigblkAddRecord(pF, rec, lenRec-1); RETiRet; } |