Annotation of embedaddon/libpdel/ppp/ppp_msoft.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (c) 2001-2002 Packet Design, LLC.
        !             4:  * All rights reserved.
        !             5:  * 
        !             6:  * Subject to the following obligations and disclaimer of warranty,
        !             7:  * use and redistribution of this software, in source or object code
        !             8:  * forms, with or without modifications are expressly permitted by
        !             9:  * Packet Design; provided, however, that:
        !            10:  * 
        !            11:  *    (i)  Any and all reproductions of the source or object code
        !            12:  *         must include the copyright notice above and the following
        !            13:  *         disclaimer of warranties; and
        !            14:  *    (ii) No rights are granted, in any manner or form, to use
        !            15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
        !            16:  *         on advertising, endorsements, or otherwise except as such
        !            17:  *         appears in the above copyright notice or in the software.
        !            18:  * 
        !            19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
        !            20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
        !            21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
        !            22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
        !            23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
        !            24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
        !            25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
        !            26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
        !            27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
        !            28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
        !            29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
        !            30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
        !            31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
        !            32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
        !            33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
        !            35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
        !            36:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            37:  *
        !            38:  * Author: Archie Cobbs <archie@freebsd.org>
        !            39:  */
        !            40: 
        !            41: #include "ppp/ppp_defs.h"
        !            42: #include "ppp/ppp_msoft.h"
        !            43: 
        !            44: #include <openssl/md4.h>
        !            45: #include <openssl/des.h>
        !            46: #include <openssl/sha.h>
        !            47: 
        !            48: /* Magic constants */
        !            49: #define MS_MAGIC_1     "This is the MPPE Master Key"
        !            50: #define MS_MAGIC_2     "On the client side, this is the send key;" \
        !            51:                        " on the server side, it is the receive key."
        !            52: #define MS_MAGIC_3     "On the client side, this is the receive key;" \
        !            53:                        " on the server side, it is the send key."
        !            54: #define MS_AR_MAGIC_1  "Magic server to client signing constant"
        !            55: #define MS_AR_MAGIC_2  "Pad to make it do more than one iteration"
        !            56: 
        !            57: /* Internal functions */
        !            58: static void    ppp_msoft_challenge_response(const u_char *chal,
        !            59:                        const char *pwHash, u_char *hash);
        !            60: static void    ppp_msoft_des_encrypt(const u_char *clear,
        !            61:                        u_char *key0, u_char *cypher);
        !            62: static void    ppp_msoft_challenge_hash(const u_char *peerchal,
        !            63:                        const u_char *authchal, const char *username,
        !            64:                        u_char *hash);
        !            65: 
        !            66: /*
        !            67:  * ppp_msoft_lm_password_hash()
        !            68:  *
        !            69:  * password    ASCII password
        !            70:  * hash                16 byte output LanManager hash
        !            71:  */
        !            72: void
        !            73: ppp_msoft_lm_password_hash(const char *password, u_char *hash)
        !            74: {
        !            75:        const char *const clear = "KGS!@#$%%";
        !            76:        u_char up[14];
        !            77:        int k;
        !            78: 
        !            79:        memset(&up, 0, sizeof(up));
        !            80:        for (k = 0; k < sizeof(up) && password[k]; k++)
        !            81:                up[k] = toupper(password[k]);
        !            82: 
        !            83:        ppp_msoft_des_encrypt(clear, &up[0], &hash[0]);
        !            84:        ppp_msoft_des_encrypt(clear, &up[7], &hash[8]);
        !            85: }
        !            86: 
        !            87: /*
        !            88:  * ppp_msoft_nt_password_hash()
        !            89:  *
        !            90:  * password    ASCII (NOT Unicode) password
        !            91:  * hash                16 byte output NT hash
        !            92:  */
        !            93: void
        !            94: ppp_msoft_nt_password_hash(const char *password, u_char *hash)
        !            95: {
        !            96:        u_int16_t unipw[128];
        !            97:        const char *s;
        !            98:        int unipwLen;
        !            99:        MD4_CTX ctx;
        !           100: 
        !           101:        /* Convert password to Unicode */
        !           102:        for (unipwLen = 0, s = password;
        !           103:            unipwLen < sizeof(unipw) / 2 && *s; s++)
        !           104:                unipw[unipwLen++] = htons(*s << 8);
        !           105: 
        !           106:        /* Compute MD4 of Unicode password */
        !           107:        MD4_Init(&ctx);
        !           108:        MD4_Update(&ctx, (u_char *)unipw, unipwLen * sizeof(*unipw));
        !           109:        MD4_Final(hash, &ctx);
        !           110: }
        !           111: 
        !           112: /*
        !           113:  * ppp_msoft_nt_challenge_response()
        !           114:  *
        !           115:  * chal                8 byte challenge
        !           116:  * password    ASCII (NOT Unicode) password
        !           117:  * hash                24 byte response
        !           118:  */
        !           119: void
        !           120: ppp_msoft_nt_challenge_response(const u_char *chal,
        !           121:        const char *password, u_char *hash)
        !           122: {
        !           123:        u_char pwHash[16];
        !           124: 
        !           125:        ppp_msoft_nt_password_hash(password, pwHash);
        !           126:        ppp_msoft_challenge_response(chal, pwHash, hash);
        !           127: }
        !           128: 
        !           129: /*
        !           130:  * ppp_msoft_challenge_response()
        !           131:  *
        !           132:  * chal                8 byte challenge
        !           133:  * pwHash      16 byte password hash
        !           134:  * hash                24 byte response
        !           135:  */
        !           136: static void
        !           137: ppp_msoft_challenge_response(const u_char *chal,
        !           138:        const char *pwHash, u_char *hash)
        !           139: {
        !           140:        u_char buf[21];
        !           141:        int i;
        !           142: 
        !           143:        /* Initialize buffer */
        !           144:        memset(&buf, 0, sizeof(buf));
        !           145:        memcpy(buf, pwHash, 16);
        !           146: 
        !           147:        /* Use DES to hash the hash */
        !           148:        for (i = 0; i < 3; i++) {
        !           149:                u_char *const key = &buf[i * 7];
        !           150:                u_char *const output = &hash[i * 8];
        !           151: 
        !           152:                ppp_msoft_des_encrypt(chal, key, output);
        !           153:        }
        !           154: }
        !           155: 
        !           156: /*
        !           157:  * ppp_msoft_des_encrypt()
        !           158:  *
        !           159:  * clear       8 byte cleartext
        !           160:  * key         7 byte key
        !           161:  * cypher      8 byte cyphertext
        !           162:  */
        !           163: static void
        !           164: ppp_msoft_des_encrypt(const u_char *clear, u_char *key0, u_char *cypher)
        !           165: {
        !           166:        des_key_schedule ks;
        !           167:        u_char key[8];
        !           168: 
        !           169:        /*
        !           170:         * Create DES key
        !           171:         *
        !           172:         * Note: we don't bother setting the parity bit because
        !           173:         * the des_set_key() algorithm does that for us. A different
        !           174:         * algorithm may care though.
        !           175:         */
        !           176:        key[0] = key0[0] & 0xfe;
        !           177:        key[1] = (key0[0] << 7) | (key0[1] >> 1);
        !           178:        key[2] = (key0[1] << 6) | (key0[2] >> 2);
        !           179:        key[3] = (key0[2] << 5) | (key0[3] >> 3);
        !           180:        key[4] = (key0[3] << 4) | (key0[4] >> 4);
        !           181:        key[5] = (key0[4] << 3) | (key0[5] >> 5);
        !           182:        key[6] = (key0[5] << 2) | (key0[6] >> 6);
        !           183:        key[7] = key0[6] << 1;
        !           184:        des_set_key((des_cblock *)key, ks);
        !           185: 
        !           186:        /* Encrypt using key */
        !           187:        des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cypher, ks, 1);
        !           188: }
        !           189: 
        !           190: /*
        !           191:  * ppp_msoft_get_start_key()
        !           192:  */
        !           193: void
        !           194: ppp_msoft_get_start_key(const u_char *chal, u_char *hash)
        !           195: {
        !           196:        u_char sha1[SHA_DIGEST_LENGTH];
        !           197:        SHA_CTX ctx;
        !           198: 
        !           199:        SHA1_Init(&ctx);
        !           200:        SHA1_Update(&ctx, hash, 16);
        !           201:        SHA1_Update(&ctx, hash, 16);
        !           202:        SHA1_Update(&ctx, chal, 8);
        !           203:        SHA1_Final(sha1, &ctx);
        !           204:        memcpy(hash, sha1, 16);
        !           205: }
        !           206: 
        !           207: /*
        !           208:  * ppp_msoft_generate_nt_response()
        !           209:  *
        !           210:  * authchal    16 byte authenticator challenge
        !           211:  * peerchal    16 byte peer challenge
        !           212:  * username    ASCII username
        !           213:  * password    ASCII (NOT Unicode) password
        !           214:  * hash                24 byte response
        !           215:  */
        !           216: void
        !           217: ppp_msoft_generate_nt_response(const u_char *authchal, const u_char *peerchal,
        !           218:        const char *username, const char *password, u_char *hash)
        !           219: {
        !           220:        u_char chal[8];
        !           221:        u_char pwHash[16];
        !           222: 
        !           223:        ppp_msoft_challenge_hash(peerchal, authchal, username, chal);
        !           224:        ppp_msoft_nt_password_hash(password, pwHash);
        !           225:        ppp_msoft_challenge_response(chal, pwHash, hash);
        !           226: }
        !           227: 
        !           228: /*
        !           229:  * ppp_msoft_challenge_hash()
        !           230:  *
        !           231:  * peerchal    16 byte peer challenge
        !           232:  * authchal    16 byte authenticator challenge
        !           233:  * username    ASCII username
        !           234:  * hash                8 byte response
        !           235:  */
        !           236: static void
        !           237: ppp_msoft_challenge_hash(const u_char *peerchal, const u_char *authchal,
        !           238:        const char *username, u_char *hash)
        !           239: {
        !           240:        u_char sha1[SHA_DIGEST_LENGTH];
        !           241:        SHA_CTX ctx;
        !           242:        const char *slash;
        !           243: 
        !           244:        /* Strip off NT domain (if any) */
        !           245:        if ((slash = strrchr(username, '\\')) != NULL)
        !           246:                username = slash + 1;
        !           247:        SHA1_Init(&ctx);
        !           248:        SHA1_Update(&ctx, peerchal, 16);
        !           249:        SHA1_Update(&ctx, authchal, 16);
        !           250:        SHA1_Update(&ctx, username, strlen(username));
        !           251:        SHA1_Final(sha1, &ctx);
        !           252:        memcpy(hash, sha1, 8);
        !           253: }
        !           254: 
        !           255: /*
        !           256:  * Compute master key for MPPE
        !           257:  */
        !           258: void
        !           259: ppp_msoft_get_master_key(const u_char *resp, u_char *hash)
        !           260: {
        !           261:        u_char sha1[SHA_DIGEST_LENGTH];
        !           262:        SHA_CTX ctx;
        !           263: 
        !           264:        SHA1_Init(&ctx);
        !           265:        SHA1_Update(&ctx, hash, 16);
        !           266:        SHA1_Update(&ctx, resp, 24);
        !           267:        SHA1_Update(&ctx, MS_MAGIC_1, 27);
        !           268:        SHA1_Final(sha1, &ctx);
        !           269:        memcpy(hash, sha1, 16);
        !           270: }
        !           271: 
        !           272: /*
        !           273:  * Compute asymmetric start key for MPPE (MS-CHAPv2 authentication)
        !           274:  *
        !           275:  * which       Zero for server xmit/client recv, 1 for server recv/client xmit
        !           276:  */
        !           277: void
        !           278: ppp_msoft_get_asymetric_start_key(int which, const u_char *master, u_char *key)
        !           279: {
        !           280:        u_char sha1[SHA_DIGEST_LENGTH];
        !           281:        u_char sha_pad[2][40];
        !           282:        SHA_CTX ctx;
        !           283: 
        !           284:        /* Generate start key */
        !           285:        memset(&sha_pad[0], 0x00, sizeof(sha_pad[0]));
        !           286:        memset(&sha_pad[1], 0xf2, sizeof(sha_pad[1]));
        !           287:        SHA1_Init(&ctx);
        !           288:        SHA1_Update(&ctx, master, 16);
        !           289:        SHA1_Update(&ctx, sha_pad[0], 40);
        !           290:        SHA1_Update(&ctx, which ? MS_MAGIC_2 : MS_MAGIC_3, 84);
        !           291:        SHA1_Update(&ctx, sha_pad[1], 40);
        !           292:        SHA1_Final(sha1, &ctx);
        !           293:        memcpy(key, sha1, 16);
        !           294: }
        !           295: 
        !           296: /*
        !           297:  * Initialize MPPE key based on MS-CHAPv1 credentials.
        !           298:  *
        !           299:  * e128                Non-zero for 128 bit key, zero for 64 bit key.
        !           300:  * pass                Originating side's password
        !           301:  * chal                Answering side's challenge
        !           302:  * key         16 byte output buffer
        !           303:  */
        !           304: void
        !           305: ppp_msoft_init_key_v1(int e128,
        !           306:        const char *pass, const u_char *chal, u_char *key)
        !           307: {
        !           308:        if (e128) {                                     /* 128 bit key */
        !           309:                u_char hash[16];
        !           310:                MD4_CTX ctx;
        !           311: 
        !           312:                ppp_msoft_nt_password_hash(pass, hash);
        !           313:                MD4_Init(&ctx);
        !           314:                MD4_Update(&ctx, hash, 16);
        !           315:                MD4_Final(hash, &ctx);
        !           316:                ppp_msoft_get_start_key(chal, hash);
        !           317:                memcpy(key, hash, 16);
        !           318:        } else                                          /* 40 or 56 bit key */
        !           319:                ppp_msoft_lm_password_hash(pass, key);
        !           320: }
        !           321: 
        !           322: /*
        !           323:  * Initialize MPPE key based on MS-CHAPv2 credentials.
        !           324:  *
        !           325:  * which       Zero for server xmit/client recv, 1 for server recv/client xmit
        !           326:  * pass                Originating side's password
        !           327:  * resp                Answering side's challenge response hash
        !           328:  * key         16 byte output buffer
        !           329:  */
        !           330: void
        !           331: ppp_msoft_init_key_v2(int which,
        !           332:        const char *pass, const u_char *resp, u_char *key)
        !           333: {
        !           334:        u_char hash[16];
        !           335:        MD4_CTX ctx;
        !           336: 
        !           337:        ppp_msoft_nt_password_hash(pass, hash);
        !           338:        MD4_Init(&ctx);
        !           339:        MD4_Update(&ctx, hash, 16);
        !           340:        MD4_Final(hash, &ctx);
        !           341:        ppp_msoft_get_master_key(resp, hash);
        !           342:        ppp_msoft_get_asymetric_start_key(which, hash, key);
        !           343: }
        !           344: 
        !           345: /*
        !           346:  * Generate response to MS-CHAPv2 piggy-backed challenge.
        !           347:  *
        !           348:  * "authresp" must point to a 20 byte buffer.
        !           349:  */
        !           350: void
        !           351: ppp_msoft_generate_authenticator_response(const char *password,
        !           352:        const u_char *ntresp, const u_char *peerchal,
        !           353:        const u_char *authchal, const char *username, u_char *authresp)
        !           354: {
        !           355:        u_char hash[16];
        !           356:        u_char digest[SHA_DIGEST_LENGTH];
        !           357:        u_char chal[8];
        !           358:        MD4_CTX md4ctx;
        !           359:        SHA_CTX shactx;
        !           360: 
        !           361:        ppp_msoft_nt_password_hash(password, hash);
        !           362: 
        !           363:        MD4_Init(&md4ctx);
        !           364:        MD4_Update(&md4ctx, hash, 16);
        !           365:        MD4_Final(hash, &md4ctx);
        !           366: 
        !           367:        SHA1_Init(&shactx);
        !           368:        SHA1_Update(&shactx, hash, 16);
        !           369:        SHA1_Update(&shactx, ntresp, 24);
        !           370:        SHA1_Update(&shactx, MS_AR_MAGIC_1, 39);
        !           371:        SHA1_Final(digest, &shactx);
        !           372: 
        !           373:        ppp_msoft_challenge_hash(peerchal, authchal, username, chal);
        !           374: 
        !           375:        SHA1_Init(&shactx);
        !           376:        SHA1_Update(&shactx, digest, sizeof(digest));
        !           377:        SHA1_Update(&shactx, chal, 8);
        !           378:        SHA1_Update(&shactx, MS_AR_MAGIC_2, 41);
        !           379:        SHA1_Final(authresp, &shactx);
        !           380: }
        !           381: 
        !           382: /*
        !           383:  * Verify server's piggy-backed response.
        !           384:  *
        !           385:  * Returns 1 if OK, otherwise zero.
        !           386:  */
        !           387: int
        !           388: ppp_msoft_check_authenticator_response(const char *password,
        !           389:        const u_char *ntresp, const u_char *peerchal, const u_char *authchal,
        !           390:        const char *username, const char *rechash)
        !           391: {
        !           392:        char authresp[43];
        !           393: 
        !           394:        ppp_msoft_generate_authenticator_response(password, ntresp,
        !           395:            peerchal, authchal, username, authresp);
        !           396:        return (strcmp(rechash, authresp) == 0);
        !           397: }
        !           398: 
        !           399: 

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