# syslog-sign

syslog-sign defines digital signatures for logfiles. This provides end-to-end authentication for network transports, enables the detection of lost UDP messages, and also makes it possible to check a log archive for later modifications (assuming the private key was kept safe).

## Signature Groups

A basic concept of syslog-sign is the signature group which describes a set of messages that are grouped and signed together. Their purpose becomes clear with an example: assume you split your messages to two logservers serverA and serverB. Now if all messages were signed as one stream, then a) where do the signatures go to? and b) how could serverA, having only hashes and signatures, decide which message are missing and which are on serverB?
Thus the messages are selected into two signature groups containing all signatures for messages to serverA and serverB respectively. Then every server has its own messages and its own signatures to verify them.

There are three predefined and one custom signature groups:

0. one global signature group, useful if all messages go to one central logserver anyway
1. every syslog priority (=combination of facility and severity) gets its own group, i.e. 192 of them, useful if there are lots of different destinations which all receive messages with different priorities
2. take the priorities and split them into intervals, useful to define bigger subsets, e.g. one signature group for the mail facility and two for everything else
3. not defined and reserved for custom strategy. I use this to have one signature group for every configured destination. In this case the selector in syslog.conf will determine which messages go into one group; it is also the only strategy that allows a message to be in multiple groups.

Every signature group has several attributes and only the combination of several values determines one signature group unambiguously. Currently the key to identify a signature group is the tuple (hostname, reboot session ID, SG value, SPRI value).

## Configuration/Activation

syslog-sign is enabled with the option "sign_sg" in syslog.conf. The value selects the signature group strategy, so for example the line "sign_sg=0" enables syslog-sign with one signature group.

The SG="2" strategy is the only one that might require additional configuration. When selected (with "sign_sg=2") the default is to use one signature group per facility (kernel, user, mail, ...). To allow custom configuration there is an additional option "sign_sg2_delim" to specify the numerical SPRI values, i.e. the boundaries between the signature groups.
Example: With "sign_sg2_delim = 15 31" syslogd will set up three signature groups: one for all priorities x ≤ 15 (kernel.*,user.*), one for priorities 15 < x ≤ 31 (mail.*), and one for all priorities x > 31.

## Key, Signature, and Hash Types

The current internet draft defines two values for the VERsion field for using either SHA-1 or SHA-256 hashes. Both versions mandate DSA keys and signatures.
There are several alternatives for sending the public key in the initial Certificate Block. If a X.509 certificate is available (for TLS connections) then syslogd will use key type 'C' (PKIX) and send the certificate in DER encoding. Otherwise it generates a new DSA key and uses key type 'K' (public key) to send the public key in DER encoding.

## Redundancy

As mentioned above one design target of syslog-sign is the detection of lost messages, e.g. due to UDP datagram loss. So one has to take extra precaution to prevent lost signature messages and send them multiple times.
This implementation sends the first Certificate block only on demand, just before the first Signature Block. After that it is resent n times with several seconds delay. The Signature Blocks are not repeated but use a sliding window so that every message hash is included in m sequential Signature Blocks.

## Verification

Sending signatures is only half of the job, -- they have to be verified as well. I used Perl to write an offline verification tool that reads a complete logfile and prints all messages in their correct order. See the example below for a sample usage and output.

## Example

Here is an example of a signed message sequence. I let syslogd generate me a DSA key for a self-signed X.509 certificate and use that for signing. I also changed one message so you can see the resulting verification output below.

    $ cat test.log
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg0
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg1
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg2
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg3
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg4
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg5
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg6
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg7
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg8
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg9
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg10
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg11
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - modified msg12
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg13
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg14
    <110>1 2008-08-02T01:09:27.773505+02:00 host.example.org syslogd - - [ssign-cert VER="0111" RSID="1217632162" SG="3" SPRI="0" TBPL="1059" INDEX="1" FLEN="1059" FRAG="2008-08-02T01:09:27.773464+02:00 C  " SIGN="MC0CFFEHx8UX391lbmhbisJNS0zLGD/WAhUAuMfCO0BWtARt2vEWHbM2mAe2k+o="]
    <110>1 2008-08-02T01:09:27.778347+02:00 host.example.org syslogd - - [ssign VER="0111" RSID="1217632162" SG="3" SPRI="0" GBC="1" FMN="1" CNT="15" HB="siUJM358eYFHOS2K0MTlveWeH/U= zTxfthW8WqmtFhOG4k/+ZxkirTA= j9dubU1GNVp7qWShwph/w32nD08= XQDLZ/NuwirmLdMORtm84r9kIW4= RNDFNCo7hiCsK/EKumsPBbFHNZA= ANiE3KbY948J6cEB640fAtWXuO4= e2M/OqjHDfxLVUSPt1CsNJHm9wU= Y+racQst7F1gR8eEUh8O7o+M53s= JAMULRxjMPbOO5EhhKbsUkAwbl0= pd+N5kmlnyQ0BoItELd/KWQrcMg= dsMQSzPHIS6S3Vaa23/t7U8JAJ4= i4rE3x7N4qyQGTkmaWHsWDFP9SY= qgTqV4EgfUFd3uZXNPvJ25erzBI= XW0YrME5kQEh+fxhg1fetnWxfIc= 7YPcRHsDwXWnQuGRWaJtFWw9hus=" SIGN="MCwCFF5hS5GTLxLDwsDCUmOnHhzkmWzbAhRJ0io+LBKM6Ux/cM7eqZ6eRAI11Q=="]
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg15
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg16
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg17
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg18
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg19
    <110>1 2008-08-02T01:09:32.399406+02:00 host.example.org syslogd - - [ssign VER="0111" RSID="1217632162" SG="3" SPRI="0" GBC="4" FMN="1" CNT="20" HB="siUJM358eYFHOS2K0MTlveWeH/U= zTxfthW8WqmtFhOG4k/+ZxkirTA= j9dubU1GNVp7qWShwph/w32nD08= XQDLZ/NuwirmLdMORtm84r9kIW4= RNDFNCo7hiCsK/EKumsPBbFHNZA= ANiE3KbY948J6cEB640fAtWXuO4= e2M/OqjHDfxLVUSPt1CsNJHm9wU= Y+racQst7F1gR8eEUh8O7o+M53s= JAMULRxjMPbOO5EhhKbsUkAwbl0= pd+N5kmlnyQ0BoItELd/KWQrcMg= dsMQSzPHIS6S3Vaa23/t7U8JAJ4= i4rE3x7N4qyQGTkmaWHsWDFP9SY= qgTqV4EgfUFd3uZXNPvJ25erzBI= XW0YrME5kQEh+fxhg1fetnWxfIc= 7YPcRHsDwXWnQuGRWaJtFWw9hus= PIvLm0mh+he5+PDihG1p7sQlx8k= lPzUvx0I1VwSGWV7yKF9W//Yb2U= X+PWYcx5AXnsDVSNAHLZUGk5ioY= okXY88MGG4QybrYMf8HJN23WO1Y= HcaPyHfQ2s1SuSciTKw4woYWuMg=" SIGN="MCwCFFr0i6taT1vWowR7yc5bEQxFfY7/AhQBCK+rBNPgzR0vUgxPeARvD24kIQ=="]

Just in case you wonder about the different timestamps: The messages were send with a normal syslog(3), so the syslogd received them in BSD Syslog format without subsecond resolution.

    $ perl verify.pl --help

    syslog-sign verifier
    reads logfile and verifies message signatures

    Notes:
    - By default uses only SHA-1 hashes. Use option "--sha256" to use only
      SHA-256 and "--sha1 --sha256"to use both types.
    - Some status messages are printed to stderr.
      Use option "--quiet" to disable them.
    - All verified messages are printed with their identifying signature group.
      Every line starts with a comma-separated tuple: hostname, reboot session ID,
      SG value, SPRI value, and message number.
    - If only one hash is used then all messages not signed are printed as well.

    Limitations: handles only key types 'C' (PKIX) and 'K' (public key)
      with DSA keys and signatures

    Command Line Options:
      -i  --in         input file (default: stdin)
      -o  --out        output file for verified messages (default: stdout)
      -u  --unsigned   output file for unsigned messages (default: stdout)
          --sha1       use SHA-1 hashes (default)
          --sha256     use SHA-256 hashes
      -v  --verbose    shows some internals (every CB,SB,hash,...)
      -q  --quiet      no status messages to stderr
      -h  --help       this help

    $ perl verify.pl -i test.log
    reading input...
    processing CBs...
    decoding SGs...
    got PKIX DSA key
    verifying CBs...
    verified CB and got key for SG: (host.example.org,1217632162,0111,3,0), start: 2008-08-02T01:09:27.773464+02:00
    now process SBs
    signed messages:
    host.example.org,1217632162,0111,3,0,1  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg0
    host.example.org,1217632162,0111,3,0,2  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg1
    host.example.org,1217632162,0111,3,0,3  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg2
    host.example.org,1217632162,0111,3,0,4  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg3
    host.example.org,1217632162,0111,3,0,5  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg4
    host.example.org,1217632162,0111,3,0,6  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg5
    host.example.org,1217632162,0111,3,0,7  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg6
    host.example.org,1217632162,0111,3,0,8  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg7
    host.example.org,1217632162,0111,3,0,9  <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg8
    host.example.org,1217632162,0111,3,0,10 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg9
    host.example.org,1217632162,0111,3,0,11 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg10
    host.example.org,1217632162,0111,3,0,12 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg11
    host.example.org,1217632162,0111,3,0,13 **** msg lost
    host.example.org,1217632162,0111,3,0,14 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg13
    host.example.org,1217632162,0111,3,0,15 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg14
    host.example.org,1217632162,0111,3,0,16 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg15
    host.example.org,1217632162,0111,3,0,17 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg16
    host.example.org,1217632162,0111,3,0,18 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg17
    host.example.org,1217632162,0111,3,0,19 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg18
    host.example.org,1217632162,0111,3,0,20 <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - msg19
    messages without signature:
    <15>1 2008-08-02T02:09:27+02:00 host.example.org test 6255 - - modified msg12

Martin Schütte <`info@mschuette.name`>
$Id: sign.html,v 1.2 2023/05/01 11:57:53 andvar Exp $