Annotation of embedaddon/mpd/src/chap.c, revision 1.1.1.3

1.1       misho       1: 
                      2: /*
                      3:  * chap.c
                      4:  *
                      5:  * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
                      6:  * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
                      7:  * See ``COPYRIGHT.iij''
                      8:  * 
                      9:  * Rewritten by Archie Cobbs <archie@freebsd.org>
                     10:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
                     11:  * See ``COPYRIGHT.whistle''
                     12:  */
                     13: 
                     14: #include "ppp.h"
                     15: #include "auth.h"
                     16: #include "msoft.h"
                     17: #include "util.h"
                     18: #include <openssl/md5.h>
                     19: 
                     20: /*
                     21:  * INTERNAL FUNCTIONS
                     22:  */
                     23: 
                     24:   static int   ChapHash(Link l, int alg, u_char *hash_value, u_char id,
                     25:                  const char *username, const char *secret,
                     26:                  const u_char *challenge, int clen, int local);
                     27:   static int   ChapHashAgree(int alg, const u_char *self, int slen,
                     28:                  const u_char *peer, int plen);
                     29:   static int   ChapParsePkt(const char *pref, const u_char *pkt, const int pkt_len,
                     30:                  char *peer_name, u_char *chap_value,
                     31:                  int *chap_value_size);
                     32:   static char  *ChapGetSecret(Link l, int alg, char *password);
                     33:   static void  ChapGenRandom(Link l, u_char *buf, int len);
                     34: 
                     35: /*
                     36:  * INTERNAL VARIABLES
                     37:  */
                     38: 
                     39:   static const u_char  gIdBytes[] = { 0x3b, 0x1e, 0x68 };
                     40: 
                     41: /*
                     42:  * ChapStart()
                     43:  */
                     44: 
                     45: void
                     46: ChapStart(Link l, int which)
                     47: {
                     48:   Auth                 a = &l->lcp.auth;
                     49:   ChapInfo     chap = &l->lcp.auth.chap;
                     50:   ChapParams   cp = &l->lcp.auth.params.chap;
                     51:   
                     52:   chap->proto = PROTO_CHAP;
                     53: 
                     54:   if (l->originate == LINK_ORIGINATE_LOCAL)
                     55:     a->params.msoft.chap_alg = a->self_to_peer_alg;
                     56:   else
                     57:     a->params.msoft.chap_alg = a->peer_to_self_alg;
                     58:   
                     59:   switch (which)
                     60:   {
                     61:     case AUTH_SELF_TO_PEER:    /* Just wait for peer's challenge */
                     62:       break;
                     63: 
                     64:     case AUTH_PEER_TO_SELF:
                     65: 
                     66:       /* Invalidate any old challenge data */
                     67:       cp->chal_len = 0;
                     68: 
                     69:       /* Initialize retry counter and timer */
                     70:       chap->next_id = 1;
                     71:       chap->retry = AUTH_RETRIES;
                     72: 
                     73:       TimerInit(&chap->chalTimer, "ChalTimer",
                     74:        l->conf.retry_timeout * SECONDS, ChapChalTimeout, l);
                     75:       TimerStart(&chap->chalTimer);
                     76: 
                     77:       /* Send first challenge */
                     78:       ChapSendChallenge(l);
                     79:       break;
                     80: 
                     81:     default:
                     82:       assert(0);
                     83:   }
                     84: }
                     85: 
                     86: /*
                     87:  * ChapStop()
                     88:  */
                     89: 
                     90: void
                     91: ChapStop(ChapInfo chap)
                     92: {
                     93:   TimerStop(&chap->chalTimer);
                     94:   TimerStop(&chap->respTimer);
                     95:   if (chap->resp) {
                     96:     Freee(chap->resp);
                     97:     chap->resp = NULL;
                     98:   }
                     99: }
                    100: 
                    101: /*
                    102:  * ChapSendChallenge()
                    103:  */
                    104: 
                    105: void
                    106: ChapSendChallenge(Link l)
                    107: {
                    108:   Auth          const a = &l->lcp.auth;
                    109:   ChapInfo     chap = &a->chap;
                    110:   ChapParams   cp = &a->params.chap;
                    111:   u_char       *pkt;
                    112: 
                    113:   /* don't generate new challenges on re-transmit */
                    114:   if (cp->chal_len)
                    115:     goto send_pkt;
                    116: 
                    117:   /* Put random challenge data in buffer (only once for Microsoft CHAP) */
                    118:   switch (a->peer_to_self_alg) {
                    119:     case CHAP_ALG_MSOFT: {
                    120:        cp->chal_len = CHAP_MSOFT_CHAL_LEN;
                    121:        ChapGenRandom(l, cp->chal_data, cp->chal_len);
                    122:        if (l->originate == LINK_ORIGINATE_REMOTE) {
                    123:          memcpy(a->params.msoft.msChal, cp->chal_data, cp->chal_len);
                    124:        }
                    125:       }
                    126:       break;
                    127:     case CHAP_ALG_MSOFTv2:
                    128:       cp->chal_len = CHAP_MSOFTv2_CHAL_LEN;
                    129:       ChapGenRandom(l, cp->chal_data, cp->chal_len);
                    130:       if (l->originate == LINK_ORIGINATE_REMOTE) {
                    131:        memcpy(a->params.msoft.msChal, cp->chal_data, cp->chal_len);
                    132:       }
                    133:       break;
                    134:     case CHAP_ALG_MD5:
                    135:       cp->chal_len = random() % 32 + 16;
                    136:       ChapGenRandom(l, cp->chal_data, cp->chal_len);
                    137:       break;
                    138:     default:
                    139:       assert(0);
                    140:   }
1.1.1.3 ! misho     141:   assert(cp->chal_len <= (int)sizeof(cp->chal_data));
1.1       misho     142: 
                    143: send_pkt:
                    144:   /* Build a challenge packet */
                    145:   pkt = Malloc(MB_AUTH, 1 + cp->chal_len + strlen(a->conf.authname) + 1);
                    146:   pkt[0] = cp->chal_len;
                    147:   memcpy(pkt + 1, cp->chal_data, cp->chal_len);
                    148:   memcpy(pkt + 1 + cp->chal_len,
                    149:     a->conf.authname, strlen(a->conf.authname));
                    150: 
                    151:   /* Send it off */
                    152:   AuthOutput(l, chap->proto,
                    153:     chap->proto == PROTO_CHAP ? CHAP_CHALLENGE : EAP_REQUEST,
                    154:     chap->next_id++, pkt,
                    155:     1 + cp->chal_len + strlen(a->conf.authname), 0,
                    156:     EAP_TYPE_MD5CHAL);
                    157:   Freee(pkt);
                    158: }
                    159: 
                    160: /*
                    161:  * ChapSendResponse()
                    162:  */
                    163: 
                    164: static void
                    165: ChapSendResponse(Link l)
                    166: {
                    167:   ChapInfo     chap = &l->lcp.auth.chap;
                    168: 
                    169:   /* Stop response timer */
                    170:   TimerStop(&chap->respTimer);
                    171: 
                    172:   /* Send response (possibly again) */
                    173:   assert(chap->resp);
                    174:   AuthOutput(l, chap->proto,
                    175:     chap->proto == PROTO_CHAP ? CHAP_RESPONSE : EAP_RESPONSE,
                    176:     chap->resp_id, chap->resp, chap->resp_len, 0, EAP_TYPE_MD5CHAL);
                    177: 
                    178:   /* Start re-send timer (only during authenticate phase where the
                    179:      authentication timer is still running) */
                    180:   if (l->lcp.phase == PHASE_AUTHENTICATE) {
                    181:     TimerInit(&chap->respTimer, "RespTimer",
                    182:       l->conf.retry_timeout * SECONDS,
                    183:       (void (*)(void *)) ChapSendResponse, (void *) l);
                    184:     TimerStart(&chap->respTimer);
                    185:   }
                    186: }
                    187: 
                    188: /*
                    189:  * ChapParsePkt()
                    190:  *
                    191:  */
                    192: 
                    193: static int
                    194: ChapParsePkt(const char *pref, const u_char *pkt, const int pkt_len,
                    195:   char *peer_name, u_char *chap_value, int *chap_value_size)
                    196: {
                    197:   int          val_len, name_len;
                    198: 
                    199:   /* Compute and check lengths */
                    200:   if (pkt == NULL
                    201:       || pkt_len < 1
                    202:       || (val_len = pkt[0]) < 1
                    203:       || val_len > CHAP_MAX_VAL
                    204:       || (name_len = (pkt_len - val_len - 1)) < 0
                    205:       || name_len > CHAP_MAX_NAME) {
                    206:     Log(LG_AUTH, ("[%s]   Bogus packet", pref));
                    207:     return(-1);
                    208:   }
                    209: 
                    210:   /* Extract stuff */
                    211:   memcpy(peer_name, pkt + 1 + val_len, name_len);
                    212:   peer_name[name_len] = 0;
                    213:   memcpy(chap_value, pkt + 1, val_len);
                    214:   *chap_value_size = val_len;
                    215:   Log(LG_AUTH, ("[%s]   Name: \"%s\"", pref, peer_name));
                    216: #if 0
                    217:   Log(LG_AUTH, ("[%s]   Value: %d bytes", pref, *chap_value_size));
                    218: #endif
                    219:   return(0);
                    220: }
                    221: 
                    222: /*
                    223:  * ChapChalTimeout()
                    224:  *
                    225:  * Timer expired for reply to challenge packet
                    226:  */
                    227: 
                    228: void
                    229: ChapChalTimeout(void *ptr)
                    230: {
                    231:   Link         const l = (Link) ptr;
                    232:   ChapInfo     const chap = &l->lcp.auth.chap;
                    233: 
                    234:   if (--chap->retry > 0) {
                    235:     TimerStart(&chap->chalTimer);
                    236:     ChapSendChallenge(l);
                    237:   }
                    238: }
                    239: 
                    240: /*
                    241:  * ChapInput()
                    242:  */
                    243: 
                    244: void
                    245: ChapInput(Link l, AuthData auth, const u_char *pkt, u_short len)
                    246: {
                    247:   Auth         const a = &l->lcp.auth;
                    248:   ChapInfo     const chap = &a->chap;
                    249:   char         peer_name[CHAP_MAX_NAME + 1];
                    250:   char         password[AUTH_MAX_PASSWORD];
                    251:   u_char       hash_value[CHAP_MAX_VAL];
                    252:   int          hash_value_size;
                    253:   
                    254:   chap->proto = auth->proto;
                    255:   
                    256:   switch (auth->code) {
                    257:     case CHAP_CHALLENGE:
                    258:       {
                    259:        u_char  value[CHAP_MAX_VAL];            /* Chap packet */
                    260:        int     value_len;                      /* Packet length */
                    261:        char    *name, *secret;
                    262:        int     name_len, idFail;
                    263: 
                    264:        auth->alg = a->self_to_peer_alg;
                    265: 
                    266:        /* Check packet */
                    267:        if ((a->self_to_peer != PROTO_CHAP && a->self_to_peer != PROTO_EAP)
                    268:            || l->lcp.phase != PHASE_AUTHENTICATE)
                    269:          Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
                    270:        if (ChapParsePkt(l->name, pkt, len, peer_name, value, &value_len) < 0)
                    271:          break;
                    272: 
                    273:        /* Never respond to our own outstanding challenge */
                    274:        if (value_len == auth->params.chap.chal_len
                    275:            && !memcmp(value, auth->params.chap.chal_data, auth->params.chap.chal_len)) {
                    276:          Log(LG_AUTH, ("[%s] CHAP: SECURITY: peer sent same challenge! Ignoring.", l->name));
                    277:          break;
                    278:        }
                    279: 
                    280:        /* Don't respond to a challenge that looks like it came from
                    281:           us and has the wrong origination value embedded in it. This
                    282:           avoids a security hole associated with using the same CHAP
                    283:           password to authenticate in both directions on a link. */
                    284:        idFail = 0;
                    285:        do {
                    286:          char  buf[sizeof(gIdBytes)];
                    287:          int   chalOrig;
                    288: 
                    289:          /* Check challenge length */
1.1.1.3 ! misho     290:          if (value_len < (int)sizeof(buf))
1.1       misho     291:            break;
                    292: 
                    293:          /* Copy challenge bits and extract origination value */
                    294:          memcpy(buf, value, sizeof(buf));
                    295:          chalOrig = (buf[0] >> 6) & 0x03;
                    296:          buf[0] &= 0x3f;
                    297: 
                    298:          /* Check for same ID bytes in the challenge */
                    299:          if (memcmp(buf, gIdBytes, sizeof(gIdBytes)) != 0)
                    300:            break;
                    301: 
                    302:          /* ID bytes match; origination value must be opposite. Note this
                    303:             assumes that if we can tell the origination direction of a link,
                    304:             then so can the peer. */
                    305:          switch (l->originate) {
                    306:            case LINK_ORIGINATE_LOCAL:
                    307:              idFail = (chalOrig != LINK_ORIGINATE_REMOTE);
                    308:              break;
                    309:            case LINK_ORIGINATE_REMOTE:
                    310:              idFail = (chalOrig != LINK_ORIGINATE_LOCAL);
                    311:              break;
                    312:            case LINK_ORIGINATE_UNKNOWN:
                    313:            default:
                    314:              idFail = 0;       /* XXX assumes leased line, etc is secure */
                    315:              break;
                    316:          }
                    317: 
                    318:          /* Log failure */
                    319:          if (idFail) {
                    320:            Log(LG_AUTH,
                    321:              ("[%s] CHAP: SECURITY: origination value check failed (%s,%s). Ignoring.",
                    322:                l->name,
                    323:                LINK_ORIGINATION(l->originate),
                    324:                LINK_ORIGINATION(chalOrig)));
                    325:            break;
                    326:          }
                    327:        } while (0);
                    328:        if (idFail)
                    329:          break;
                    330: 
                    331:        /*
                    332:         * Name we use to authenticate ourselves:
                    333:         *
                    334:         * 1. The manually configured authname ("set authname ...")
                    335:         * 2. The peer's supplied name
                    336:         */
                    337:        if (*auth->conf.authname)
                    338:          name = auth->conf.authname;
                    339:        else
                    340:          name = peer_name;
                    341:        name_len = strlen(name);
                    342:        Log(LG_AUTH, ("[%s] CHAP: Using authname \"%s\"", l->name, name));
                    343: 
                    344:        strlcpy(auth->params.authname, name, sizeof(auth->params.authname));
                    345: 
                    346:        /* Get the corresponding secret */
                    347:        if ((strcmp(auth->conf.authname, auth->params.authname) == 0) && 
                    348:            auth->conf.password[0] != 0) {
                    349:                strlcpy(password, auth->conf.password, sizeof(password));
                    350:        } else if (AuthGetData(auth->params.authname, password, 
                    351:            sizeof(password), NULL, NULL) < 0) {
                    352:                Log(LG_AUTH, ("[%s] CHAP: Warning: no secret for \"%s\" found",
                    353:                    l->name, 
                    354:                    auth->params.authname));
                    355:                break;
                    356:        }
                    357: 
                    358:        secret = ChapGetSecret(l, a->self_to_peer_alg, password);
                    359: 
                    360:        /* Get hash value */
                    361:        if ((hash_value_size = ChapHash(l, a->self_to_peer_alg, hash_value,
                    362:            auth->id, name, secret, value, value_len, 1)) < 0) {
                    363:          Log(LG_AUTH, ("[%s] CHAP: Hash failure", l->name));
                    364:          break;
                    365:        }
                    366: 
                    367:        /* Need to remember MS-CHAP stuff for use with MPPE encryption */
                    368:        switch (a->self_to_peer_alg) {
                    369:        case CHAP_ALG_MSOFT:
                    370:          if (l->originate == LINK_ORIGINATE_LOCAL)
                    371:                memcpy(a->params.msoft.msChal, value, CHAP_MSOFT_CHAL_LEN);
                    372:          break;
                    373:        case CHAP_ALG_MSOFTv2:
                    374:          if (l->originate == LINK_ORIGINATE_LOCAL) {
                    375:                memcpy(a->params.msoft.msChal, value, CHAP_MSOFTv2_CHAL_LEN);
                    376:                memcpy(a->params.msoft.ntResp,
                    377:                    hash_value + offsetof(struct mschapv2value, ntHash),
                    378:                    CHAP_MSOFTv2_RESP_LEN);
                    379:          }
                    380:          break;
                    381:        }
                    382: 
                    383:        /* Build response packet */
                    384:        if (chap->resp)
                    385:          Freee(chap->resp);
                    386:        chap->resp = Malloc(MB_AUTH, 1 + hash_value_size + name_len);
                    387:        chap->resp[0] = hash_value_size;
                    388:        memcpy(&chap->resp[1], hash_value, hash_value_size);
                    389:        memcpy(&chap->resp[1 + hash_value_size], name, name_len);
                    390:        chap->resp_len = 1 + hash_value_size + name_len;
                    391:        chap->resp_id = auth->id;
                    392: 
                    393:        /* Send response to peer */
                    394:        ChapSendResponse(l);
                    395:       }
                    396:       break;
                    397: 
                    398:     case CHAP_RESPONSE:
                    399:        auth->alg = a->peer_to_self_alg;
                    400: 
                    401:        /* Stop challenge timer */
                    402:        TimerStop(&chap->chalTimer);
                    403: 
                    404:        /* Check response */
                    405:        if ((a->peer_to_self != PROTO_CHAP && a->peer_to_self != PROTO_EAP)
                    406:            || l->lcp.phase != PHASE_AUTHENTICATE)
                    407:          Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
                    408:        if (ChapParsePkt(l->name, pkt, len,
                    409:            peer_name, auth->params.chap.value, &auth->params.chap.value_len) < 0) {
                    410:          auth->why_fail = AUTH_FAIL_INVALID_PACKET;
                    411:          ChapInputFinish(l, auth);
                    412:          return;
                    413:        }
                    414: 
                    415:        /* Strip MS domain if any */
                    416:        if (!Enabled(&l->conf.options, LINK_CONF_MSDOMAIN))
                    417:          if (a->peer_to_self_alg == CHAP_ALG_MSOFT
                    418:              || a->peer_to_self_alg == CHAP_ALG_MSOFTv2) {
                    419:            char        *s;
                    420: 
                    421:            if ((s = strrchr(peer_name, '\\')))
                    422:              memmove(peer_name, s + 1, strlen(s) + 1);
                    423:          }
                    424: 
                    425:        strlcpy(auth->params.authname, peer_name, sizeof(auth->params.authname));
                    426:        
                    427:        auth->finish = ChapInputFinish;
                    428:        AuthAsyncStart(l, auth);
                    429:        return;
                    430: 
                    431:     case CHAP_SUCCESS:
                    432:     case CHAP_FAILURE:
                    433: 
                    434:        auth->alg = a->self_to_peer_alg;
                    435: 
                    436:       /* Stop response timer */
                    437:       TimerStop(&chap->respTimer);
                    438:       if (chap->resp) {
                    439:        Freee(chap->resp);
                    440:        chap->resp = NULL;
                    441:       }
                    442: 
                    443:       /* Appropriate? */
                    444:       if (a->self_to_peer != PROTO_CHAP
                    445:          || l->lcp.phase != PHASE_AUTHENTICATE) {
                    446:        Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
                    447:        break;
                    448:       }
                    449: 
                    450:       /* Log message */
1.1.1.3 ! misho     451:       ShowMesg(LG_AUTH, l->name, (const char*)pkt, len);
1.1       misho     452:       AuthFinish(l, AUTH_SELF_TO_PEER, auth->code == CHAP_SUCCESS);
                    453:       break;
                    454:       
                    455:     case CHAP_MS_V1_CHANGE_PW:
                    456:       Log(LG_AUTH, ("[%s] CHAP: Sorry changing passwords using MS-CHAPv1 is not yet implemented",
                    457:        l->name));
                    458:       goto badResponse;
                    459: 
                    460:     case CHAP_MS_V2_CHANGE_PW:
                    461:       Log(LG_AUTH, ("[%s] CHAP: Sorry changing passwords using MS-CHAPv2 is not yet implemented",
                    462:        l->name));
                    463:       goto badResponse;
                    464: 
                    465:     default:
                    466:       Log(LG_AUTH, ("[%s] CHAP: unknown code %d", l->name, auth->code));
                    467:       break;
                    468:   }
                    469:     AuthDataDestroy(auth);
                    470:     return;
                    471:   
                    472: badResponse:
                    473:   {
                    474:     char       failMesg[64];
                    475: 
                    476:     auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
                    477:     AuthFailMsg(auth, failMesg, sizeof(failMesg));
                    478:     AuthOutput(l, auth->proto, auth->proto == PROTO_CHAP ? CHAP_FAILURE : EAP_FAILURE,
                    479:        auth->id, (u_char *)failMesg, strlen(failMesg), 0, EAP_TYPE_MD5CHAL);
                    480:     AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
                    481:     AuthDataDestroy(auth);
                    482:   }
                    483: }
                    484: 
                    485: /*
                    486:  * ChapInputFinish()
                    487:  *
                    488:  * Possible return point from the asynch auth handler.
                    489:  * 
                    490:  */
                    491:  
                    492: void 
                    493: ChapInputFinish(Link l, AuthData auth)
                    494: {
                    495:     Auth       a = &l->lcp.auth;
                    496:     ChapInfo   chap = &a->chap;
                    497:     u_char     hash_value[CHAP_MAX_VAL];
                    498:     int                hash_value_size;
                    499:     char       ackMesg[128], *secret;
                    500:    
                    501:     Log(LG_AUTH, ("[%s] CHAP: Auth return status: %s", 
                    502:        l->name, AuthStatusText(auth->status)));
                    503:     
                    504:     if (auth->status == AUTH_STATUS_BUSY) {
                    505:        AuthDataDestroy(auth);  
                    506:        return;
                    507:     }
                    508:     
                    509:     if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2 && 
                    510:       auth->mschapv2resp != NULL) {
                    511:        strlcpy(ackMesg, auth->mschapv2resp, sizeof(ackMesg));
                    512:     } else if (auth->reply_message != NULL) {
                    513:        strlcpy(ackMesg, auth->reply_message, sizeof(ackMesg));
                    514:     } else {
                    515:        strlcpy(ackMesg, AUTH_MSG_WELCOME, sizeof(ackMesg));
                    516:     }
                    517: 
                    518:     if (auth->status == AUTH_STATUS_FAIL)
                    519:        goto badResponse;
                    520:     else if (auth->status == AUTH_STATUS_SUCCESS)
                    521:        goto goodResponse;
                    522:   
                    523:     /* Copy in peer challenge for MS-CHAPv2 */
                    524:     if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2)
                    525:        memcpy(hash_value, a->params.chap.value, 16);
                    526:     
                    527:     secret = ChapGetSecret(l, a->peer_to_self_alg, a->params.password);
                    528: 
                    529:     /* Get expected hash value */
                    530:     if ((hash_value_size = ChapHash(l, a->peer_to_self_alg, hash_value, auth->id,
                    531:       a->params.authname, secret, a->params.chap.chal_data, a->params.chap.chal_len,
                    532:       0)) < 0) {
                    533:        Log(LG_AUTH, ("[%s] CHAP: Hash failure", l->name));
                    534:        auth->why_fail = AUTH_FAIL_INVALID_PACKET;
                    535:        goto badResponse;
                    536:     }
                    537: 
                    538:     /* Compare with peer's response */
                    539:     if (a->params.chap.chal_len == 0
                    540:       || !ChapHashAgree(a->peer_to_self_alg, hash_value, hash_value_size,
                    541:                a->params.chap.value, a->params.chap.value_len)) {
                    542:        Log(LG_AUTH, ("[%s] CHAP: Invalid response", l->name));
                    543:        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                    544:        goto badResponse;
                    545:     }
                    546:   
                    547:     /* Response is good */
                    548:     Log(LG_AUTH, ("[%s] CHAP: Response is valid", l->name));
                    549: 
                    550:     if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2) {
                    551:        struct mschapv2value *const pv = (struct mschapv2value *)a->params.chap.value;
                    552:        char hex[41];
                    553:        u_char authresp[20];
                    554:        int i;
                    555: 
                    556:        /* Generate MS-CHAPv2 'authenticator response' */
                    557:        GenerateAuthenticatorResponse(a->params.msoft.nt_hash, pv->ntHash,
                    558:            pv->peerChal, a->params.chap.chal_data, a->params.authname, authresp);
                    559:        for (i = 0; i < 20; i++)
                    560:            sprintf(hex + (i * 2), "%02X", authresp[i]);
                    561:        /* If we have reply message, send it. */
                    562:        if (auth->reply_message != NULL) {
                    563:            snprintf(ackMesg, sizeof(ackMesg), "S=%s M=%s",
                    564:                hex, auth->reply_message);
                    565:        } else
                    566:            snprintf(ackMesg, sizeof(ackMesg), "S=%s", hex);
                    567:     }
                    568:   
                    569: goodResponse:
                    570: #ifdef USE_OPIE
                    571:     /* make a dummy verify to force an update of the opiekeys database */
                    572:     if (a->params.authentic == AUTH_CONF_OPIE)
                    573:        opieverify(&auth->opie.data, a->params.password);
                    574: #endif
                    575: 
                    576:     /* Need to remember MS-CHAP stuff for use with MPPE encryption */
                    577:     if (l->originate == LINK_ORIGINATE_REMOTE &&
                    578:       a->peer_to_self_alg == CHAP_ALG_MSOFTv2 &&
                    579:       !memcmp(a->params.msoft.ntResp, gMsoftZeros, CHAP_MSOFTv2_RESP_LEN)) {
                    580:        memcpy(a->params.msoft.ntResp,
                    581:            a->params.chap.value + offsetof(struct mschapv2value, ntHash),
                    582:            CHAP_MSOFTv2_RESP_LEN);
                    583:     }
                    584:   
                    585:     Log(LG_AUTH, ("[%s] CHAP: Reply message: %s", l->name, ackMesg));
                    586:     AuthOutput(l, chap->proto, chap->proto == PROTO_CHAP ? CHAP_SUCCESS : EAP_SUCCESS,
                    587:        auth->id, (u_char *)ackMesg, strlen(ackMesg), 0, EAP_TYPE_MD5CHAL);
                    588:     AuthFinish(l, AUTH_PEER_TO_SELF, TRUE);
                    589:     AuthDataDestroy(auth);
                    590:     return;  
                    591: 
                    592: badResponse:
                    593:   {
                    594:     char        failMesg[64];
                    595: 
                    596:     AuthFailMsg(auth, failMesg, sizeof(failMesg));
                    597:     Log(LG_AUTH, ("[%s] CHAP: Reply message: %s", l->name, failMesg));
                    598:     AuthOutput(l, chap->proto, chap->proto == PROTO_CHAP ? CHAP_FAILURE : EAP_FAILURE,
                    599:        auth->id, (u_char *)failMesg, strlen(failMesg), 0, EAP_TYPE_MD5CHAL);
                    600:     AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
                    601:     AuthDataDestroy(auth);  
                    602:   }
                    603: }
                    604: 
                    605: /*
                    606:  * ChapGetSecret()
                    607:  * 
                    608:  * returns either the plaintext pass for CHAP-MD5
                    609:  * or the NT-Hash for MS-CHAP. Set's credentials for
                    610:  * MPPE-Key derivation
                    611:  */
                    612: 
                    613: static char *
                    614: ChapGetSecret(Link l, int alg, char *password)
                    615: {
                    616:   Auth         a = &l->lcp.auth;
                    617:   char         *pw;
                    618:   
                    619:   if (alg == CHAP_ALG_MD5)
                    620:     pw = password;
                    621:   else {
                    622:     if (!a->params.msoft.has_nt_hash)
                    623:     {
                    624:       NTPasswordHash(password, a->params.msoft.nt_hash);
                    625:       NTPasswordHashHash(a->params.msoft.nt_hash, a->params.msoft.nt_hash_hash);
                    626:       LMPasswordHash(password, a->params.msoft.lm_hash);
                    627:       a->params.msoft.has_nt_hash = TRUE;
                    628:       a->params.msoft.has_lm_hash = TRUE;
                    629:     }
                    630: 
                    631:     pw = (char *) a->params.msoft.nt_hash;
                    632:   }
                    633: 
                    634:   return pw;
                    635: }
                    636: 
                    637: /*
                    638:  * ChapGenRandom()
                    639:  */
                    640: 
                    641: static void
                    642: ChapGenRandom(Link l, u_char *buf, int len)
                    643: {
                    644:   int  k;
                    645: 
                    646:   /* Prefix with our unique ID plus origination value */
1.1.1.3 ! misho     647:   for (k = 0; k < (int)sizeof(gIdBytes) && k < len; k++)
1.1       misho     648:     buf[k] = gIdBytes[k];
                    649:   buf[0] |= (l->originate & 0x03) << 6;
                    650: 
                    651:   /* Fill the rest with semi-random bytes */
                    652:   for (; k < len; k++)
                    653:     buf[k] = random() & 0xff;
                    654: }
                    655: 
                    656: /*
                    657:  * ChapHash()
                    658:  */
                    659: 
                    660: static int
                    661: ChapHash(Link l, int alg, u_char *hash_value, u_char id, const char *username,
                    662:        const char *secret, const u_char *challenge, int clen, int local)
                    663: {
                    664:   int  hash_size;
                    665: 
                    666:   switch (alg) {
                    667:     case CHAP_ALG_MD5:
                    668:       {
                    669:        MD5_CTX md5ctx;
                    670: 
                    671:        MD5_Init(&md5ctx);
                    672:        MD5_Update(&md5ctx, &id, 1);
                    673:        MD5_Update(&md5ctx, secret, strlen(secret));
                    674:        MD5_Update(&md5ctx, challenge, clen);
                    675:        MD5_Final(hash_value, &md5ctx);
                    676:        hash_size = 16;
                    677:       }
                    678:       break;
                    679: 
                    680:     case CHAP_ALG_MSOFT:
                    681:       {
                    682:        struct mschapvalue      *const val = (struct mschapvalue *) hash_value;
                    683: 
                    684:        /* We don't generate the LANManager hash because it's too insecure */
                    685:        memset(val->lmHash, 0, sizeof(val->lmHash));
                    686:        NTChallengeResponse(challenge, secret, val->ntHash);
                    687:        val->useNT = 1;
                    688:        hash_size = 49;
                    689:       }
                    690:       break;
                    691:     case CHAP_ALG_MSOFTv2:
                    692:       {
                    693:        struct mschapv2value *const val = (struct mschapv2value *) hash_value;
                    694:        const char *s;
                    695: 
                    696:        if ((s = strrchr(username, '\\')) != NULL)
                    697:          username = s + 1;
                    698:        if (local) {                    /* generate reverse 'peer challenge' */
                    699:          ChapGenRandom(l, val->peerChal, sizeof(val->peerChal));
                    700:          memset(val->reserved, 0, sizeof(val->reserved));
1.1.1.2   misho     701:          val->flags = 0; /* rfc2759, paragraph 4 says that flags MUST be zero */
1.1       misho     702:        }
                    703:        GenerateNTResponse(challenge,
                    704:          val->peerChal, username, secret, val->ntHash);
                    705: 
                    706:        hash_size = 49;
                    707:       }
                    708:       break;
                    709: 
                    710:     default:
                    711:       return(-1);
                    712:   }
                    713: 
                    714:   /* Done */
                    715:   return(hash_size);
                    716: }
                    717: 
                    718: /*
                    719:  * ChapHashAgree()
                    720:  */
                    721: 
                    722: static int
                    723: ChapHashAgree(int alg, const u_char *self, int slen,
                    724:        const u_char *peer, int plen)
                    725: {
                    726:   switch (alg)
                    727:   {
                    728:     case CHAP_ALG_MD5:
                    729:       return(slen == plen && !memcmp(self, peer, slen));
                    730: 
                    731:     case CHAP_ALG_MSOFT:
                    732:       {
1.1.1.3 ! misho     733:        const struct mschapvalue *const sv = (const struct mschapvalue *) self;
        !           734:        const struct mschapvalue *const pv = (const struct mschapvalue *) peer;
1.1       misho     735: 
                    736:        if (slen != 49 || plen != 49)
                    737:          return(0);
                    738:        if (sv->useNT != 1 || pv->useNT != 1)
                    739:          return(0);
                    740:        return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
                    741:       }
                    742:     case CHAP_ALG_MSOFTv2:
                    743:       {
1.1.1.3 ! misho     744:        const struct mschapv2value *const sv =(const struct mschapv2value *) self;
        !           745:        const struct mschapv2value *const pv =(const struct mschapv2value *) peer;
1.1       misho     746: 
                    747:        if (slen != 49 || plen != 49)
                    748:          return(0);
                    749:        return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
                    750:       }
                    751: 
                    752:     default:
                    753:       return(0);
                    754:   }
                    755: }
                    756: 
                    757: /*
                    758:  * ChapCode()
                    759:  */
                    760: 
                    761: const char *
                    762: ChapCode(int code, char *buf, size_t len)
                    763: {
                    764:   switch (code) {
                    765:     case CHAP_CHALLENGE:
                    766:        strlcpy(buf, "CHALLENGE", len);
                    767:        break;
                    768:     case CHAP_RESPONSE:
                    769:        strlcpy(buf, "RESPONSE", len);
                    770:        break;
                    771:     case CHAP_SUCCESS:
                    772:        strlcpy(buf, "SUCCESS", len);
                    773:        break;
                    774:     case CHAP_FAILURE:
                    775:        strlcpy(buf, "FAILURE", len);
                    776:        break;
                    777:     default:
                    778:        snprintf(buf, len, "code%d", code);
                    779:   }
                    780:   return(buf);
                    781: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>