Subject: RE: [extensibility 4] ASN.1 module - checksums on KDC-REQ/REP

From: "Medvinsky, Sasha (SD-EX)" <[email-masked]>
Date: Wed, 12 Dec 2001 14:32:01 -0500

I understand that there may be some discussion on whether or not there is a
need to have the checksums that cover the cleartext portions of the KDC-REQ
and KDC-REP.  These are currently being used within the PacketCable VoIP
networks and are considered to be important features.

In the KDC-REQ, without a keyed checksum, a man-in-the-middle could modify
the requested KDC options, duration of the ticket, client or server name,
etc.   When cannonicalization or referrals are used, a client might accept a
ticket in the response with a different client or server name.

For example, a client requests an initial service ticket with an AS-REQ,
then MITM modifies an AS-REQ and turns it into a cross-realm TGT request and
the client mistakenly accepts the corresponding AS-REP with a cross-realm
TGT as a referral.  This would be a DOS attack on both the client and the
KDCs in both realms.  Or, in another example a client request contains
etypes with DES and 3-DES and MITM removes 3-DES from the etypes to make the
session key easier to break.

There are also potential threats when the AS-REP or TGS-REP is not
authenticated.  One such threat is when MITM replaces the issued ticket with
some invalid ticket, where the encrypted part may be garbage.  The client
cannot validate the ticket checksum and will subsequently try to use it with
some application server or the KDC (if it is the TGT).  Later, the client is
going to send an AP-REC to a server say over UDP and get back some sort of
ticket error that could be misinterpreted as line noise and the client might
keep retrying.  Or, since bad ticket errors cannot be authenticated, the
client might ignore such error.

These and probably many other DOS attacks can be easily prevented if
Kerberos provides a checksum over the KDC-REQ/KDC-REP as we have already in
Kerberos revisions and as Sam is proposing with the ASN.1 encoding below.
PacketCable would be strongly opposed if these checksums were taken out.

Sasha.  

-----Original Message-----
From: Sam Hartman [mailto:[email-masked]]
Sent: Thursday, December 06, 2001 8:54 PM
To: [email-masked]
Subject: [extensibility 4] ASN.1 module

It turns out this will not be the last message.  I don't quite have
the per-message guidelines for message checksumming and using new
types ready yet, will send those out later tonight or early in the
morning.

Not surprisingly, Tom wrote up the ASN.1 module.  He also included a
few open issues with the module:

* Should we use a new tag number for EncTicketPart2, to distinguish
  from EncTicketPart1?  We could alternatively use a flag bit.  It's
  important to do something along these lines, since if we don't,
  someone could undetectably convert a Ticket2 into a Ticket1 by
  removing the checksum wrapper.

[Currently the module is written assuming yes , although  the answer
will be a bit more complex because of the multiple client
implementation problem.  One possibility is to allow a client to
convert a ticket2 into a ticket1 if the cleartext part of the ticket
is trivial.  We still need to think about how this interacts with
UTF8, but hopefully we'll have a write up on this issue soon.
]

* Do we want to do something about the TypedData monstrosity?

[We at least internally believe yes, not sure if that made it into
this module.  The problem is that the claimed contents of the
octet-string hole in KRB-ERROR changed between 1510 and revisions in a
potentially backward incompatible way.  If really no one uses the
edata field besides for preauthentication errors, then this change is
OK, but unless we are absolutely sure of this, then it creates an
interoperability problem and is better handled by means used elsewhere
in the protocol.]

----------

Kerberos5 {
	iso(1) org(3) dod(6) internet(1) security(5) kerberosV5(2)
} DEFINITIONS	::= BEGIN

Int32		::= INTEGER (-2147483648..2147483647)
		    -- signed values representable in 32 bits

UInt32		::= INTEGER (0..4294967295)
		    -- unsigned 32 bit values

Microseconds	::= INTEGER (0..99999)
		    -- microseconds

KerberosString	::= CHOICE {
	general		GeneralString (IA5String),
	...		-- no extension may be sent
			-- to an rfc1510 implementation --
}

Realm		::= KerberosString
PrincipalName	::= SEQUENCE {
	name-type	[0] Int32,
	name-string	[1] SEQUENCE OF KerberosString
}

KerberosTime	::= GeneralizedTime
			-- with no fractional seconds

HostAddress	::= SEQUENCE  {
	addr-type	[0] Int32,
	address		[1] OCTET STRING
}
HostAddresses	::= SEQUENCE OF HostAddress

AuthorizationData	::= SEQUENCE OF SEQUENCE {
	ad-type		[0] Int32,
	ad-data		[1] OCTET STRING
}

PA-DATA		::= SEQUENCE {
	padata-type	[1] Int32,
	padata-value	[2] OCTET STRING
			    -- might be encoded AP-REQ
}

KerberosFlags	::= BIT STRING (SIZE (32..MAX))

EncryptedData	::= SEQUENCE {
	etype	[0] Int32 -- EncryptionType --,
	kvno	[1] INTEGER OPTIONAL,
	cipher	[2] OCTET STRING -- ciphertext
}

EncryptionKey	::= SEQUENCE {
	keytype		[0] Int32 -- actually encryption type --,
	keyvalue	[1] OCTET STRING
}

Checksum	::= SEQUENCE {
	cksumtype	[0] Int32,
	checksum	[1] OCTET STRING
}

-- handy parameterized type for wrapping authenticated plaintext
Signed{InnerType}	::= SEQUENCE {
        cksum   [0] Checksum OPTIONAL,
        inner	[1] InnerType,
        ...
}

Ticket		::= CHOICE {
        ticket1		[APPLICATION 1] TicketCommon
				(WITH COMPONENTS {
					...,
					extensions ABSENT
					-- also excluding
					-- ASN.1 extensions
				}),
        ticket2		[APPLICATION 4] Signed{TicketCommon}
}

TicketCommon	::= SEQUENCE {
	tkt-vno		[0] INTEGER,
	realm		[1] Realm,
	sname		[2] PrincipalName,
	enc-part	[3] EncryptedData -- EncTicketPart --,
	extensions	[4] TicketExtensions OPTIONAL,
	...
}

-- Encrypted part of ticket
EncTicketPart		::= CHOICE {
	encTicketPart1	[APPLICATION 3] EncTicketPartCommon,
	encTicketPart2	[APPLICATION 5] EncTicketPartCommon
				-- This new version must be used
				-- inside the enc-part of the
				-- ticket2 alternative of Ticket.
				-- Possibly use a flag instead?
}

EncTicketPartCommon	::= SEQUENCE {
	flags			[0] TicketFlags,
	key			[1] EncryptionKey,
	crealm			[2] Realm,
	cname			[3] PrincipalName,
	transited		[4] TransitedEncoding,
	authtime		[5] KerberosTime,
	starttime		[6] KerberosTime OPTIONAL,
	endtime			[7] KerberosTime,
	renew-till		[8] KerberosTime OPTIONAL,
	caddr			[9] HostAddresses OPTIONAL,
	authorization-data	[10] AuthorizationData OPTIONAL,
	...			-- ASN.1 extensions must be excluded
				-- when issued for a rfc1510 service
}

-- encoded Transited field
TransitedEncoding	::= SEQUENCE {
	tr-type		[0] Int32 -- must be registered --,
	contents	[1] OCTET STRING
}

-- ticket extensions: for Ticket2 only
TicketExtensions	::= SEQUENCE OF SEQUENCE {
	te-type		[0] Int32,
	te-data		[1] OCTET STRING
}

TicketFlags	::= KerberosFlags
	-- reserved(0),
	-- forwardable(1),
	-- forwarded(2),
	-- proxiable(3),
	-- proxy(4),
	-- may-postdate(5),
	-- postdated(6),
	-- invalid(7),
	-- renewable(8),
	-- initial(9),
	-- pre-authent(10),
	-- hw-authent(11),
	-- transited-policy-checked(12),
	-- ok-as-delegate(13),
	-- anonymous(14),
	-- cksummed-ticket(15)

AS-REQ	::= CHOICE {
	as-req1		[APPLICATION 10] KDC-REQ-COMMON
				(WITH COMPONENTS {
					...,
					req-body (WITH COMPONENTS {
						...,
						till PRESENT
						-- also excluding
						-- ASN.1 extensions
					})
					-- also excluding
					-- ASN.1 extensions
				}),
	as-req2		[APPLICATION 6]  Signed{KDC-REQ-COMMON}
				(WITH COMPONENTS {
					...,
					cksum ABSENT
				})
}
TGS-REQ	::= CHOICE {
	tgs-req1	[APPLICATION 12] KDC-REQ-COMMON
				(WITH COMPONENTS {
					...,
					req-body (WITH COMPONENTS {
						...,
						till PRESENT
						-- also excluding
						-- ASN.1 extensions
					})
					-- also excluding
					-- ASN.1 extensions
				}),
	tgs-req2	[APPLICATION 8]  Signed{KDC-REQ-COMMON}
}

KDC-REQ-COMMON	::= SEQUENCE {
	pvno		[1] INTEGER,
	msg-type	[2] INTEGER,
	padata		[3] SEQUENCE OF PA-DATA OPTIONAL,
	req-body	[4] KDC-REQ-BODY,
	...		-- The usefulness of this extension marker
			-- is debatable, as there is one in req-body.
}

KDC-REQ-BODY	::= SEQUENCE {
	kdc-options		[0] KDCOptions,
	cname			[1] PrincipalName OPTIONAL
				    -- Used only in AS-REQ --,
	realm			[2] Realm
				    -- Server's realm
				    -- Also client's in AS-REQ --,
	sname			[3] PrincipalName OPTIONAL,
	from			[4] KerberosTime OPTIONAL,
	till			[5] KerberosTime OPTIONAL
				    -- was required in rfc1510;
				    -- still required for compat versions
				    -- of messages --,
	rtime			[6] KerberosTime OPTIONAL,
	nonce			[7] INTEGER,
	etype			[8] SEQUENCE OF Int32 -- EncryptionType
				    -- in preference order --,
	addresses		[9] HostAddresses OPTIONAL,
	enc-authorization-data	[10] EncryptedData OPTIONAL
				     -- Encrypted AuthorizationData
				     -- encoding --,
	additional-tickets	[11] SEQUENCE OF Ticket OPTIONAL,
	...
}

KDCOptions	::= KerberosFlags
	-- reserved(0),
	-- forwardable(1),
	-- forwarded(2),
	-- proxiable(3),
	-- proxy(4),
	-- allow-postdate(5),
	-- postdated(6),
	-- unused7(7),
	-- renewable(8),
	-- unused9(9),
	-- unused10(10),
	-- unused11(11),
	-- unused12(12),
	-- unused13(13),
	-- requestanonymous(14), 
	-- canonicalize(15), 
	-- disable-transited-check(26),
	-- renewable-ok(27),
	-- enc-tkt-in-skey(28),
	-- renew(30),
	-- validate(31)

AS-REP		::= CHOICE {
	as-rep1		[APPLICATION 11] KDC-REP-COMMON
				(WITH COMPONENTS {
					...,
					req-cksum ABSENT
					-- also excluding
					-- ASN.1 extensions
				}),
	as-rep2		[APPLICATION 7]  Signed{KDC-REP-COMMON}
				(WITH COMPONENTS {
					...,
					req-cksum PRESENT
				})
}
TGS-REP		::= CHOICE {
	tgs-rep1	[APPLICATION 11] KDC-REP-COMMON
				(WITH COMPONENTS {
					...,
					req-cksum ABSENT
					-- also excluding
					-- ASN.1 extensions
				}),
	tgs-rep2	[APPLICATION 9]  Signed{KDC-REP-COMMON}
				(WITH COMPONENTS {
					...,
					req-cksum ABSENT
				})
}

KDC-REP-COMMON	::= SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	padata		[2] SEQUENCE OF PA-DATA OPTIONAL,
	crealm		[3] Realm,
	cname		[4] PrincipalName,
	ticket		[5] Ticket,
	enc-part	[6] EncryptedData
			    -- EncASREpPart or EncTGSRepPart --,
	req-cksum	[7] Checksum OPTIONAL,
	...
}

EncASRepPart	::= [APPLICATION 25] EncKDCRepPart
EncTGSRepPart	::= [APPLICATION 26] EncKDCRepPart

EncKDCRepPart	::= SEQUENCE {
	key		[0] EncryptionKey,
	last-req	[1] LastReq,
	nonce		[2] INTEGER,
	key-expiration	[3] KerberosTime OPTIONAL,
	flags		[4] TicketFlags,
	authtime	[5] KerberosTime,
	starttime	[6] KerberosTime OPTIONAL,
	endtime		[7] KerberosTime,
	renew-till	[8] KerberosTime OPTIONAL,
	srealm		[9] Realm,
	sname		[10] PrincipalName,
	caddr		[11] HostAddresses OPTIONAL,
	...		-- ASN.1 extensions must be excluded
			-- when sending to rfc1510 implementation
}

LastReq		::=	SEQUENCE OF SEQUENCE {
	lr-type		[0] Int32,
	lr-value	[1] KerberosTime
}

AP-REQ		::= CHOICE {
	ap-req1		[APPLICATION 14] AP-REQ-COMMON
				(WITH COMPONENTS {
					...,
					extensions ABSENT
					-- also excluding
					-- ASN.1 extensions
				}),
	ap-req2		[APPLICATION 18] Signed{AP-REQ-COMMON}
}

AP-REQ-COMMON	::= SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	ap-options	[2] APOptions,
	ticket		[3] Ticket,
	authenticator	[4] EncryptedData -- Authenticator --,
	extensions	[5] ApReqExtensions OPTIONAL,
	...
}

ApReqExtensions	::= SEQUENCE OF SEQUENCE {
	apRepExt-Type	[0] Int32,
	apRepExt-Data	[1] OCTET STRING
}

APOptions	::= KerberosFlags
	-- reserved(0),
	-- use-session-key(1),
	-- mutual-required(2)

-- Unencrypted authenticator
Authenticator	::= [APPLICATION 2] SEQUENCE  {
	authenticator-vno	[0] INTEGER,
	crealm			[1] Realm,
	cname			[2] PrincipalName,
	cksum			[3] Checksum OPTIONAL,
	cusec			[4] Microseconds,
	ctime			[5] KerberosTime,
	subkey			[6] EncryptionKey OPTIONAL,
	seq-number		[7] UInt32 OPTIONAL,
	authorization-data	[8] AuthorizationData OPTIONAL
}

AP-REP		::= CHOICE {
	ap-rep1		[APPLICATION 15] AP-REP-COMMON
				(WITH COMPONENTS {
					...,
					extensions ABSENT
					-- also excluding
					-- ASN.1 extensions
				}),
	ap-rep2		[APPLICATION 19] Signed{AP-REP-COMMON}
}

AP-REP-COMMON	::= SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	enc-part	[2] EncryptedData -- EncAPRepPart --,
	extensions	[3] ApRepExtensions OPTIONAL,
	...
}

ApRepExtensions	::= SEQUENCE OF SEQUENCE {
	apRepExt-Type	[0] Int32,
	apRepExt-Data	[1] OCTET STRING
}

EncAPRepPart	::= [APPLICATION 27] SEQUENCE {
	ctime		[0] KerberosTime,
	cusec		[1] Microseconds,
	subkey		[2] EncryptionKey OPTIONAL,
	seq-number	[3] UInt32 OPTIONAL
}

KRB-SAFE	::= [APPLICATION 20] SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	safe-body	[2] KRB-SAFE-BODY,
	cksum		[3] Checksum,
	...		-- ASN.1 extensions must be excluded
			-- when sending to rfc1510 implementations
}

KRB-SAFE-BODY	::= SEQUENCE {
	user-data	[0] OCTET STRING,
	timestamp	[1] KerberosTime OPTIONAL,
	usec		[2] Microseconds OPTIONAL,
	seq-number	[3] UInt32 OPTIONAL,
	s-address	[4] HostAddress,
	r-address	[5] HostAddress OPTIONAL
}

KRB-PRIV	::= [APPLICATION 21] SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	enc-part	[3] EncryptedData -- EncKrbPrivPart --,
	...
}

EncKrbPrivPart	::= [APPLICATION 28] SEQUENCE {
	user-data	[0] OCTET STRING,
	timestamp	[1] KerberosTime OPTIONAL,
	usec		[2] Microseconds OPTIONAL,
	seq-number	[3] UInt32 OPTIONAL,
	s-address	[4] HostAddress -- sender's addr --,
	r-address	[5] HostAddress OPTIONAL -- recip's addr --,
	...		-- ASN.1 extensions must be excluded
			-- when sending to rfc1510 implementations
}

KRB-CRED	::= CHOICE {
	krb-cred1	[APPLICATION 22] KRB-CRED-COMMON
				-- excluding ASN.1 extensions --,
	krb-cred2	[APPLICATION 17] Signed{KRB-CRED-COMMON}
}

KRB-CRED-COMMON	::= SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	tickets		[2] SEQUENCE OF Ticket,
	enc-part	[3] EncryptedData -- EncKrbCredPart --,
	...
}

EncKrbCredPart	::= [APPLICATION 29] SEQUENCE {
	ticket-info	[0] SEQUENCE OF KrbCredInfo,
	nonce		[1] INTEGER OPTIONAL,
	timestamp	[2] KerberosTime OPTIONAL,
	usec		[3] Microseconds OPTIONAL,
	s-address	[4] HostAddress OPTIONAL,
	r-address	[5] HostAddress OPTIONAL
}

KrbCredInfo	::= SEQUENCE {
	key		[0] EncryptionKey,
	prealm		[1] Realm OPTIONAL,
	pname		[2] PrincipalName OPTIONAL,
	flags		[3] TicketFlags OPTIONAL,
	authtime	[4] KerberosTime OPTIONAL,
	starttime	[5] KerberosTime OPTIONAL,
	endtime		[6] KerberosTime OPTIONAL,
	renew-till	[7] KerberosTime OPTIONAL,
	srealm		[8] Realm OPTIONAL,
	sname		[9] PrincipalName OPTIONAL,
	caddr		[10] HostAddresses OPTIONAL
}

TGT-REQ		::= [APPLICATION 16] SEQUENCE {
        pvno            [0] INTEGER,
        msg-type        [1] INTEGER,
        sname           [2] PrincipalName OPTIONAL,
        srealm          [3] Realm OPTIONAL
}

KRB-ERROR	::= CHOICE {
	krb-error1	[APPLICATION 30] KRB-ERROR-COMMON
				-- excluding ASN.1 extensions --,
	krb-error2	[APPLICATION 23] Signed{KRB-ERROR-COMMON}
}

KRB-ERROR-COMMON ::= SEQUENCE {
	pvno		[0] INTEGER,
	msg-type	[1] INTEGER,
	ctime		[2] KerberosTime OPTIONAL,
	cusec		[3] Microseconds OPTIONAL,
	stime		[4] KerberosTime,
	susec		[5] Microseconds,
	error-code	[6] Int32,
	crealm		[7] Realm OPTIONAL,
	cname		[8] PrincipalName OPTIONAL,
	realm		[9] Realm -- Correct realm --,
	sname		[10] PrincipalName -- Correct name --,
	e-text		[11] KerberosString OPTIONAL,
	e-data		[12] OCTET STRING OPTIONAL,
	...
}

-- preauth stuff follows

PA-ENC-TIMESTAMP	::= EncryptedData -- encrypted PA-ENC-TS-ENC
PA-ENC-TS-ENC		::= SEQUENCE {
	patimestamp	[0] KerberosTime -- client's time --,
	pausec		[1] Microseconds OPTIONAL
}

-- remove PA-ENC-TIMESTAMP2?

PA-ENC-TIMESTAMP2	::= EncryptedData -- encrypted PA-ENC-TS2-ENC
PA-ENC-TS2-ENC		::= SEQUENCE {
	patimestamp	[0] KerberosTime -- client's time --,
	pausec		[1] Microseconds OPTIONAL,
	pachecksum	[2] Checksum OPTIONAL
			    -- keyed checksum of KDC-REQ-BODY
}

PA-AS-REQ		::= as-req2<AS-REQ

END