Annotation of embedaddon/libpdel/ppp/ppp_msoft.c, revision 1.1.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>