[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: New IPSec Monitoring MIB draft



OK, now I've had a chance to work on my IPSec DOI textual conventions,
I know the MIB well enough to comment on it in structure and in
detail.

Sorry folks, but it's a BIG message.  I've got lots to say here...

STRUCTURE
=========

The first issue is that this is not, as written an IPSec Monitoring
MIB.  It is an IKE monitoring MIB.  The structure assumes IKE in every
grain, despite the notes that you could use it with manual keys.  It
also completely assumes the IPSec DOI, despite the fact that there
have been active proposals for other DOIs (RIP, OSPF).  Also, there
are already two DOI's, ISAKMP (0), and IPSEC (1).

So, we need to be more careful of where we hang this in the MIB tree.
There should be a object identifier { ipsec }, but it shouldn't be
where this MIB hangs directly on.  Instead, this mib should be

    ikeMonitoring OBJECT IDENTIFIER ::= { ipsec 1 }

or something like that.  Well, really there should be branches for
ipsec, for isakmp, for ike, etc...

If you don't get the numbering right up front, you wind up having to
throw a lot away later, unmaintainable.

LAYERING
========

I think we need to try and be much more careful about our layering.
There is a first layer that assumes nothing but IPSec proper.  There
is a next layer that assumes ISAKMP, but nothing above that.  Then
there is a layer that assumes IKE with the IPSEC DOI.  (Or should we
split that too?)  This all works fine with the AUGMENTS model of
SMIv2.

PHASE 1
=======

So, there should be a isakmpSaTable.  It would contain, and (in my
opinion) be indexed by, the two cookies.  As data, it would have only
the IPv4/IPv6 address of each peer, the UDP port of each peer, the
ISAKMP major version, the ISAKMP minor version, the mode, and the
Domain of Interpretation.  You can't put in the Protocol-ID, it's
within the DOI.

So you have:

isakmpSaInitiatorCookie        OCTET STRING (SIZE (16))      *** index
isakmpSaResponderCookie        OCTET STRING (SIZE (16))      *** index
isakmpSaLocalIpAddress         OCTET STRING (SIZE (4 | 16))
isakmpSaLocalUdpPort           INTEGER (0..65535)
isakmpSaLocalMajorVersion      INTEGER (0..15)
isakmpSaLocalMinorVersion      INTEGER (0..15)
isakmpSaRemoteIpAddress        OCTET STRING (SIZE (4 | 16))
isakmpSaRemoteUdpPort          INTEGER (0..65535)
isakmpSaRemoteMajorVersion     INTEGER (0..15)
isakmpSaRemoteMinorVersion     INTEGER (0..15)
isakmpSaMode                   INTEGER { base(1),
                               identityProtection(2), authOnly(3),
                               agressive(4) }
isakmpSaDoi                    Unsigned32

Note that I support all the Phase 1 ISAKMP modes, even though IKE only
uses identityProtection(2) and aggressive(4).

We need to note that the isakmpSaResponderCookie is 0 when the
initiator has sent it's first packet, but no response has been
received. 

As you can see, I still want to index without creating arbitrary
indices.  But, even if I lose on that issue, the table will have some
index, allowing it to be augmented.

Augmented tables aren't performance pigs, since the indexing
code/hooks/overhead can be shared by all the tables if you like.
There is a bit more overhead of skipping those entries that aren't
relevant when the augmentation is partial.

The first table augmenting this would be ISAKMP SA's using DOI 0 for
Phase 1 identification.  (Reference sections 3.4 and A.4 of RFC 2408
and section 4 paragraph 8 of RFC 2409.)  This would be
isakmpSaDoi0Table, partially augmenting isakmpSaTable, having:

isakmpSaDoi0LocalIdType        INTEGER { ipv4(0), ipv4Subnet(1),
                               ipv6(2), ipv6Subnet(3) }
isakmpSaDoi0LocalId            OCTET STRING (SIZE (4 | 8 | 16 | 32))
isakmpSaDoi0RemoteIdType       INTEGER { ipv4(0), ipv4Subnet(1),
                               ipv6(2), ipv6Subnet(3) }
isakmpSaDoi0RemoteId           OCTET STRING (SIZE (4 | 8 | 16 | 32))

(Maybe this needs other elements?)

The second, and far more commonly used, table augmenting isakmpSaTable
would be isakmpSaDoi1Table, having:

isakmpSaDoi1LocalIdType        INTEGER { reserved(0), idIpv4Addr(1),
                               idFqdn(2), idUserFqdn(3),
                               idIpv4AddrSubnet(4), idIpv6Addr(5),
                               idIpv6AddrSubnet(6),
                               idIpv4AddrRange(7), idIpv6AddrRange(8),
                               idDerAsn1Dn(9), idDerAsn1Gn(10),
                               idKeyId(11) } 
isakmpSaDoi1LocalId            OCTET STRING (SIZE (0..511))
isakmpSaDoi1RemoteIdType       INTEGER { reserved(0), idIpv4Addr(1),
                               idFqdn(2), idUserFqdn(3),
                               idIpv4AddrSubnet(4), idIpv6Addr(5),
                               idIpv6AddrSubnet(6),
                               idIpv4AddrRange(7), idIpv6AddrRange(8),
                               idDerAsn1Dn(9), idDerAsn1Gn(10),
                               idKeyId(11) } 
isakmpSaDoi1RemoteId           OCTET STRING (SIZE (0..511))

(You may ask why two tables?  Well, the syntax of
isakmpSaDoi1LocalIdType is not the same as isakmpSaDoi0LocalIdType.
If you want to decode symbolically, you have to have a seperate table
for each DOI.)

Then we can work our way up to ikePhase1SaTable.  This augments
isakmpSaTable, since you can use IKE with Phase 1 ID's of DOI 0 or 1.
This would have:

ikePhase1SaAuthMethod          INTEGER
ikePhase1SaEncAlg              INTEGER
ikePhase1SaEncKeyLength        INTEGER
ikePhase1SaHashAlg             INTEGER
ikePhase1SaDifHelGroupDesc     INTEGER
ikePhase1SaDifHelGroupType     INTEGER
ikePhase1SaInboundOctets       Counter64
ikePhase1SaOutboundOctets      Counter64
ikePhase1SaInboundPackets      Counter32
ikePhase1SaOutboundPackets     Counter32
ikePhase1SaProtSuitesCreated   Counter32
ikePhase1SaProtSuitesDeleted   Counter32
ikePhase1SaCurrentProtSuites   Gauge32  -- new...
ikePhase1SaDecryptErrors       Counter32
ikePhase1SaAuthErrors          Counter32
ikePhase1SaOtherRecieveErrors  Counter32
ikePhase1SaSendErrors          Counter32

Now, this table needs some expansion over the variables that were in
the ipsecIkeSaTable.  We need the full parameters of the
Diffie-Hellman group, since all are negotiable in Phase 1 and Phase
2.   So, throw in:

ikePhase1SaDifHelGroupPrime    OCTET STRING
ikePhase1SaDifHelGroupGenOne   Integer32 (or must it be OCTET STRING?)
ikePhase1SaDifHelGroupGenTwo   Integer32 (")
ikePhase1SaDifHelGroupCurveA   Integer32 (")
ikePhase1SaDifHelGroupCurveB   Integer32 (")
ikePhase1SaDifHelGroupOrder    OCTET STRING

Then, we have to decide if the MIB is obligated to fill in these
values for standard Groups, or whether it is filled on only when the
GroupType is 0.  Or perhaps it's clearer if we define GroupType to be
-1 if non-standard, or have a TruthValue SYNTAX variable incidating
non-standard group.

As for the SA lifetime variables, I think Counter64 is safe.  Really,
who is going to use "bignum" math in their SA's to count the lifetime
in kbytes?  Nobody will accept (or properly implement) a lifetime with
a length greater than 8 bytes.  For that matter, I think lifetimes in
seconds can be limited to 4 bytes, that's 136 years.  (68 years if you
want to allow for sign bugs.)  These are really flaws in the DOI, it
doesn't prohibit insane values...

Next, I'd rather have a seperate variable for lifetime in kbytes versus
lifetime in seconds.  Why?  Becuase you can then put proper UNITS
statements on each.  So, we would have:

ikePhase1SaLifeType           INTEGER { none(0), seconds(1), kilobytes(2) }
ikePhase1SaTimeStart          DataAndTime
ikePhase1SaTimeLimit          Counter32 UNITS "Seconds"
ikePhase1SaByteLimit          Counter64 UNITS "Kilobytes"

You might want to make ikePhase1SaTimeStart optional, not all systems
may have the facilities to determine DateAndTime.  This might raise
the issue of wanting to add:

ikePhase1SaTimeActive         Counter32 UNITS "Seconds"

for calendar-challenged implementations.

Now we come to another major issue.  There is no limit of one
Certificate Payload per SA.  You ROUTINELY will have a chain of
certificates.  But that's not possible with this MIB.  So, we need a
table for certs.  But, the cert formats are all documented in ISAKMP,
not IKE, so we push it back to being more generic.  Thus we create
isakmpPhase1CertTable.  The first two indices would be the
augmentation of isakmpSaTable.  The last index would be an integer
from 1 to (say) 1000, for each of the Phase 1 certs for this SA.
(There has to be some upper limit on the number of certs, if only due
to maximum UDP packet size of 65535!)

Here's the data I'd put in:

isakmpPhase1SaCertIndex       INTEGER (1..1000)    *** last index
isakmpPhase1SaCertType        INTEGER { pkcs7(1), pgp(2), ... }
isakmpPhase1SaCertData        OCTET STRING (SIZE (1..65530))
isakmpPhase1SaCertSerial      OCTET STRING (SIZE (1..63))
isakmpPhase1SaCertIssuer      OCTET STRING

I don't see the need to put "Peer" in the name, since this is a table
only of Peer certificates.  (Does bring up the issue, should we have a
global table of our own Certs?)

Another thing to think about when we reach peer certificates is the
identity protection issues.  ISAKMP and IKE go to great lengths to
ensure identity protection.  Now we go and put all those identities in
a MIB.  Obviously, there have to be different MIB views that can and
cannot see the identity information.  (These views would probably be
different for SNMPv1, SNMPv2c, SNMPv3 with crypto, and perhaps any
SNMP with Transport mode ESP.)  We should be careful to have seperate
tables with sensitive information, to make it easier to configure the
MIB views.  (Otherwise they will have to protect individual collumns
in tables, which is a configuration pain in the butt.)

So far, I'm OK on that score, as isakmpSaDoi0Table, isakmpSaDoi1Table,
and isakmpPhase1CertTable, are all standalone tables full of
"identity" information.

DATA SA'S
=========

As I've noted before, I really want to see tables of the individual
SA's, indexed by the true indices of the SA's.  However, we have to
have one table per SA type, because SPI's are unique only within one
security protocol (AH, ESP, IPCOMP).  (See section 2.1 of RFC 2408.)
We also have to do this because the additional uniqueness criteria (IP
address, which is optional as a SPI discriminator in ISAKMP) are not
necessarily the same for each security protocol.  Also, the other
annoying problem is that the numbering space for security protocols is
DOI-specific.

So, I would like to see ahSaTable, espSaTable, and ipcompSaTable.
Each is indexed by destination IP address and SPI.

Another reason for seperate tables is that ipcomp is optional.  This
makes it easy to leave out everything about ipcomp.

Further, after the Destination and SPI, everything else is specific to
DOI 1.  (Magic numbers.)  That's handy, since all the DOI 1
information is security-sensitive, you again you want it in a seperate
table to simply view control.

So, for instance, on AH:

ahSaDestination               OCTET STRING (SIZE (4 | 16))
ahSaSpi                       Unsigned32

Then there is ahSaDoi1Table, indexed by the previous table's indices:

ahSaDoi1AuthAlgorithm         INTEGER

Similarly for ESP:

espSaTable::
espSaDestination
espSaSpi

augmented by espSaDoi1Table::
espSaDoi1Encapsulation
espSaDoi1EncryptAlg
espSaDoi1EncryptKeyLength
espSaDoi1AuthAlgorithm

Finally, for IPCOMP:

ipcompSaTable::
ipcompSaDestination
ipcompSaSpi

augmented by ipcompSaDoi1Table::
ipcompSaDoi1Algorithm


PROTECTION SUITES
=================

What does the proposed ipsecProtSuiteTable do during the 30 second
rekey period (per Tim's draft-jenkins-ipsec-rekey-00.txt) when two
sets of SA's are active?  Just show the new ones and leave the old
ones orphans?

Very clear rules need to be laid out when a protection suite table
entry can be changed in-place, and when it must be replaced by a new
one.  Certainly, if the Local ID or Remote ID change, it's a new
protection suite.  But changes in the SPI's don't cause a new row.

Obviously, if the above AH, ESP, and IPCOMP tables are created, the
corresponding entries would be removed from the protection suite
table.

Also, protection suites are a specifically IKE-specific concept,
methinks.  So, lets name the table ikeProtSuiteTable.

It would be really nice if there was some way to have the Protection
Suite entry point back to the Phase 1 SA.  We could have the two
cookies, with a syntax similar to IfIndexOrZero, where Zero means that
the Phase I SA is no longer there.  (If I can't win the cookie index,
then it can be the arbitrary index, where 0 is a reserved index.)

There's rather a mish-mosh between Inbound/Outbound and Local/Remote
in the proposed table.  That will get realy confusing if we create the
proper 4 variables:

ikeProtSuiteLocalLocalPort
ikeProtSuiteLocalRemotePort
ikeProtSuiteRemoteLocalPort
ikeProtSuiteRemoteRemotePort

Probably better to do Inbound/Outbound consistently.

Another approach to inbound/outbound would be to have the table
changed from full-duplex to half-duplex, and make the last index be
INTEGER { inbound(1), outbound(2) }.  Half as many MIB variables to
define and implement, at the cost of one more dimension.  Also
addresses simplex connections, if such a thing becomes important.

We probably want to make an augmenting table with the error counters,
since that's security sensitive.  Maybe the traffic counters belong
there as well.

Should there be a "status" variable?

Again, as in the ISAKMP SA, we need the FULL set of Diffie-Hellman
group parameters.


REPLAY COUNTERS
===============

I'd like to propose two more counters for receive replay events.  The
first would count "out of order" packets.  The second wound count
"lost" packets.

The out of order counter would increment whenever you received an
anti-replay counter lower than the previously received one, but it is
has not be received before.  This is a handy QOS measurement, you can
tell if the Internet between the peers is shuffling packets on you.

The lost counter would be incremented every time you slid the
anti-replay window, and some of the "flags" that you slid away were
for packets you never recieved.  This is another indication of the QOS
the Internet is providing.

Since monitoring the QOS of the underlying Internet is generally a
VERY hot button on VPN, I think that these would be really valuable
counters.

To interpret the latter counter, you also need to know the size of the
receive anti-replay window, so add a variable for that.

NOTIFY TABLE
============

Every notify message has a Protocol-ID field.  This needs to be added
as an index to the notify count table.

Also, there's a DOI in the Notification Payload.  So we need to make
it DOI 1 specific.  Also, some of the message types are DOI 1
specific.  (Most are ISAKMP generic.)

So, it should be isakmpNotifyDoi1CountTable:

isakmpNotifyDoi1ProtocolId      INTEGER { isakmp(1), ah(2), esp(3), ipcomp(4) }
isakmpNotifyDoi1MessageType     INTEGER { invalidPayloadType(1),
                                          doiNotSupported(2), ... }
isakmpNotifyDoi1Count           Counter32

With the first two variables being the two indices (in order).

It would also be nice to have a scalar variable containing the
Notification Data from the last received Notify Payload.  This may be
a helpful human-readable string.  This could be passed along with the
trap(s) generated on receiving such messages.  However, we'd need to
make the size rather limited, given the 576 byte limit on trap
PDU's...


Follow-Ups: References: