Sunday, July 14, 2013

PPP Authentication

Just a short article today.  How many of us use PPP authentication regularly at our day jobs?  Unless you're at an ISP, not likely very often, and even then you probably use a cut & paste template.

Anyway, I always forget how this thing works, and the syntax is hard to understand.

No drawing this time, only two routers involved, R1 and R2, with a single serial interface between them. R1 will be assigned 172.16.0.1 and R2 will be assigned 172.16.0.2.

R1:
interface Serial0/0
 ip address 172.16.0.1 255.255.255.0
 encapsulation ppp
 clock rate 2000000

R2:
interface Serial0/0
 ip address 172.16.0.2 255.255.255.0
 encapsulation ppp

R1#ping 172.16.0.2
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 172.16.0.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/11/28 ms

We have connectivity, let's enable PAP.  PAP sends the password in cleartext across the wire.

R1(config-if)#ppp authentication pap

...and we'll see the other side of the link go down.  Of note, you frequently need to bounce (shut/no shut) the link in order to get the authentication changes to kick in. This time it kicked in immediately for me:

R2(config-if)#
*Mar  1 00:03:41.323: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to down

So what's "ppp authentication pap" do?

ppp authentication pap says "I require my neighbor to authenticate PAP to me".  So now we need some way for R2 to authenticate PAP back to R1.

R2(config-if)#ppp pap sent-username PAPUSER password PAPPASSWORD

So now R2 has a way to authenticate back to R1.  But how does R1 check this password?

R1(config-if)#username PAPUSER password PAPPASSWORD
R1(config)#
*Mar  1 00:19:34.535: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to up

To recap, R1 asks R2 to authenticate, R2 sends the username configured on its interface, and then R1 confirms that against its local user database.  To recap, this is what the config looks like now:

R1:
interface Serial0/0
 ip address 172.16.0.1 255.255.255.0
 encapsulation ppp
 clock rate 2000000
 ppp authentication pap

username PAPUSER password PAPPASSWORD

R2:
interface Serial0/0
 ip address 172.16.0.2 255.255.255.0
 encapsulation ppp
 clock rate 2000000
 ppp pap sent-username PAPUSER password 0 PAPPASSWORD

If we wanted R2 to additionally authenticate R1, we'd add:

R2(config)#username R1USER password R1PASS
R2(config-if)#ppp authentication pap
R2(config-if)#
*Mar  1 00:26:11.471: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to down
R1(config-if)#ppp pap sent-username R1USER password R1PASS
R1(config-if)#
*Mar  1 00:28:04.067: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to up

In short, if you put ppp authentication pap on both sides of the link, you end up with both devices authenticating the other.

CHAP, the challenge-response method, uses similar rules. CHAP never actually puts the password on the wire, instead favoring a hash.

R1(config-if)#ppp authentication chap
R1(config-if)#shut
R1(config-if)#no shut
*Mar  1 01:23:10.919: %LINK-5-CHANGED: Interface Serial0/0, changed state to administratively down
*Mar  1 01:23:11.919: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to down
R2(config)#
*Mar  1 00:28:00.771: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to up
R2(config)#
*Mar  1 01:23:18.851: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to down

We can see the interface is now up/down:

R1(config-if)#do show int s0/0
Serial0/0 is up, line protocol is down
<output omitted>

To make the debug easier to read, I'm going to remove the PAP authentication requirement on R2.  There's no reason R2 can't authenticate R1 with PAP and R1 authenticate R2 with CHAP, other than it makes for complex debugs.

R2(config-if)#no ppp authentication pap
R2(config-if)#no ppp pap sent-username PAPUSER password 0 PAPPASSWORD
R2(config-if)#do debug ppp authentication
*Mar  1 01:56:10.271: Se0/0 PPP: Authorization required
*Mar  1 01:56:12.311: Se0/0 PPP: No authorization without authentication
*Mar  1 01:56:12.315: Se0/0 CHAP: I CHALLENGE id 164 len 23 from "R1"
*Mar  1 01:56:12.323: Se0/0 CHAP: Unable to authenticate for peer

So what this is telling us is that R1 is requesting CHAP, and challenging us with R1. Furthermore this tells R2 is that it should have a username for R1, to take that password, and send it to R2 in hash format.

R2(config)#username R1 password chappass
R2(config)#
*Mar  1 02:16:28.259: Se0/0 PPP: Authorization required
*Mar  1 02:16:28.303: Se0/0 PPP: No authorization without authentication
*Mar  1 02:16:28.307: Se0/0 CHAP: I CHALLENGE id 73 len 23 from "R1"
*Mar  1 02:16:28.315: Se0/0 CHAP: Using hostname from unknown source
*Mar  1 02:16:28.319: Se0/0 CHAP: Using password from AAA
*Mar  1 02:16:28.319: Se0/0 CHAP: O RESPONSE id 73 len 23 from "R2"
*Mar  1 02:16:28.343: Se0/0 CHAP: I FAILURE id 73 len 25 msg is "Authentication failed"

So we sent our hash to R1, but R1 told us we didn't match up.  That's because R1 needs a password for R2:

R1(config)#username R2 password chappass
R2(config)#
*Mar  1 02:21:16.047: Se0/0 PPP: Authorization required
*Mar  1 02:21:16.107: Se0/0 PPP: No authorization without authentication
*Mar  1 02:21:16.107: Se0/0 CHAP: I CHALLENGE id 165 len 23 from "R1"
*Mar  1 02:21:16.119: Se0/0 CHAP: Using hostname from unknown source
*Mar  1 02:21:16.123: Se0/0 CHAP: Using password from AAA
*Mar  1 02:21:16.123: Se0/0 CHAP: O RESPONSE id 165 len 23 from "R2"
*Mar  1 02:21:16.151: Se0/0 CHAP: I SUCCESS id 165 len 4
R2(config)#
*Mar  1 02:21:17.059: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to up

and we're up!

You can change what hostname you send to your neighbor.

R1(config-if)#ppp chap hostname FOO
R1(config-if)#shut
*Mar  1 02:42:08.943: %LINK-5-CHANGED: Interface Serial0/0, changed state to administratively down
R1(config-if)#no shut

A sample from the debug on R2:
*Mar  1 02:42:35.407: Se0/0 CHAP: I CHALLENGE id 173 len 24 from "FOO"
*Mar  1 02:42:35.411: Se0/0 CHAP: Unable to authenticate for peer
and the fix:

R2(config)#username FOO password chappass
*Mar  1 02:42:39.459: Se0/0 CHAP: I CHALLENGE id 174 len 24 from "FOO"
*Mar  1 02:42:39.467: Se0/0 CHAP: Using hostname from unknown source
*Mar  1 02:42:39.471: Se0/0 CHAP: Using password from AAA
*Mar  1 02:42:39.471: Se0/0 CHAP: O RESPONSE id 174 len 23 from "R2"
*Mar  1 02:42:39.527: Se0/0 CHAP: I SUCCESS id 174 len 4
R2(config)#
*Mar  1 02:42:40.527: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to up

To recap, R1 sends its hostname to R2 as "FOO" instead of "R1".  R2 looks up FOO in its local database and sends back "R2" and "chappass".  R1 already has a username for R2/chappass, and authentication succeeds.

It's possible to ask for both PAP and CHAP, in the order we prefer them:

R1(config-if)#ppp authen pap chap

I'm going to change debugs on R2, the output from debug ppp authentication is lacking some details I want.

R2(config-if)#do u all
All possible debugging has been turned off
R2(config-if)#do debug ppp negotiation

debug ppp negotiation is great, but it produces a lot of output, so be careful enabling it.

R2(config-if)#shut
*Mar  1 03:16:01.343: %LINK-5-CHANGED: Interface Serial0/0, changed state to administratively down
R2(config-if)#no shut
R2(config-if)#
*Mar  1 03:16:04.171: %LINK-3-UPDOWN: Interface Serial0/0, changed state to up
*Mar  1 03:16:04.175: Se0/0 PPP: Using default call direction
*Mar  1 03:16:04.175: Se0/0 PPP: Treating connection as a dedicated line
*Mar  1 03:16:04.175: Se0/0 PPP: Session handle[2000047F] Session id[286]
*Mar  1 03:16:04.179: Se0/0 PPP: Phase is ESTABLISHING, Active Open
*Mar  1 03:16:04.179: Se0/0 LCP: O CONFREQ [Closed] id 185 len 10
*Mar  1 03:16:04.179: Se0/0 LCP:    MagicNumber 0x0245ACCB (0x05060245ACCB)
*Mar  1 03:16:04.235: Se0/0 LCP: I CONFREQ [REQsent] id 227 len 14
*Mar  1 03:16:04.235: Se0/0 LCP:    AuthProto PAP (0x0304C023)
*Mar  1 03:16:04.239: Se0/0 LCP:    MagicNumber 0x0145B453 (0x05060145B453)
*Mar  1 03:16:04.239: Se0/0 LCP: O CONFNAK [REQsent] id 227 len 9
*Mar  1 03:16:04.239: Se0/0 LCP:    AuthProto CHAP (0x0305C22305)


We see PAP requested first, we decline, and then CHAP.  CHAP eventually succeeds:

*Mar  1 03:16:04.387: Se0/0 IPCP: State is Open
*Mar  1 03:16:04.395: Se0/0 IPCP: Install route to 172.16.0.1
*Mar  1 03:16:05.319: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial0/0, changed state to up
R2(config-if)#

This leads into another interesting point. Other blogs mention using ppp pap refuse if you don't want to authenticate with PAP. There's some call for using this command with AAA-backed PAP, but you just don't need it for this simple config.

For example,
R2(config-if)#ppp pap refuse
R2(config-if)#ppp pap sent-username PAPUSER password PAPPASS

Will refuse PAP.

However, so will:
R2(config-if)#no ppp pap refuse
R2(config-if)#no ppp pap sent-username PAPUSER password PAPPASS

Simply not providing PAP authentication details will work.

On the other hand, ppp chap refuse does make some sense.  Let's say your neighbor (R1), prefers CHAP but also accepts PAP:

R1(config-if)#ppp authen chap pap

You don't want your user database being checked for matches against CHAP, you want to authenticate with PAP instead.  This is the way to accomplish that:

R2(config-if)#ppp chap refuse
R2(config-if)#ppp pap sent-username R2 password 0 chappass

Hopefully that clears up this easy to implement, but easily misunderstood, topic.

Cheers,

Jeff Kronlage

1 comment:

  1. great post. could you pleas post other ppp complex authentication combinations which are required for CCIE?

    ReplyDelete