diff options
| author | 2010-06-03 16:41:12 +0000 | |
|---|---|---|
| committer | 2010-06-03 16:41:12 +0000 | |
| commit | 45ae9d61c58ed01739444dfabb70017cfe21192b (patch) | |
| tree | 88115785c36b98a40f000bd458a542325b7141cd /sbin/iked/chap_ms.c | |
| parent | typo in a comment (diff) | |
| download | wireguard-openbsd-45ae9d61c58ed01739444dfabb70017cfe21192b.tar.xz wireguard-openbsd-45ae9d61c58ed01739444dfabb70017cfe21192b.zip | |
Import iked, a new implementation of the IKEv2 protocol.
iked(8) is an automatic keying daemon for IPsec, like isakmpd(8), that
IPsec creates flows and SAs automatically. Unlike isakmpd, iked(8)
implements the newer IKEv2 protocol instead of IKEv1/ISAKMP. The
daemon is still work-in-progress and not enabled in the builds, but is
already able to establish IKEv2 sessions with some other IKEv2
implementations as a responder.
with lots of help and debugging by jsg@
ok deraadt@
Diffstat (limited to 'sbin/iked/chap_ms.c')
| -rw-r--r-- | sbin/iked/chap_ms.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/sbin/iked/chap_ms.c b/sbin/iked/chap_ms.c new file mode 100644 index 00000000000..50975c62864 --- /dev/null +++ b/sbin/iked/chap_ms.c @@ -0,0 +1,412 @@ +/* $OpenBSD: chap_ms.c,v 1.1 2010/06/03 16:41:12 reyk Exp $ */ +/* $vantronix: chap_ms.c,v 1.7 2010/06/02 12:22:58 reyk Exp $ */ + +/* + * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net> + * Copyright (c) 1997 - 2001 Brian Somers <brian@Awfulhak.org> + * Copyright (c) 1997 Gabor Kincses <gabor@acm.org> + * Copyright (c) 1995 Eric Rosenquist + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/cdefs.h> + +#include <ctype.h> +#include <string.h> +#include <stdio.h> + +#include <openssl/evp.h> +#include <openssl/des.h> +#include <openssl/md4.h> +#include <openssl/md5.h> +#include <openssl/sha.h> + +#include "chap_ms.h" + +/* + * Documentation & specifications: + * + * MS-CHAP (CHAP80) RFC2433 + * MS-CHAP-V2 (CHAP81) RFC2759 + * MPPE key management RFC3079 + * + * Security analysis: + * Schneier/Mudge/Wagner, "MS-CHAP-v2", Oct 99 + * "It is unclear to us why this protocol is so complicated." + */ + +static u_int8_t sha1_pad1[40] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static u_int8_t sha1_pad2[40] = { + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 +}; + +u_int8_t get7bits(u_int8_t *, int); +void mschap_des_addparity(u_int8_t *, u_int8_t *); +void mschap_des_encrypt(u_int8_t *, u_int8_t *, u_int8_t *); +void mschap_challenge_response(u_int8_t *, u_int8_t *, u_int8_t *); + +u_int8_t +get7bits(u_int8_t *in, int start) +{ + u_int word; + + word = (u_int)in[start / 8] << 8; + word |= (u_int)in[start / 8 + 1]; + word >>= 15 - (start % 8 + 7); + + return (word & 0xfe); +} + +/* IN 56 bit DES key missing parity bits + OUT 64 bit DES key with parity bits added */ +void +mschap_des_addparity(u_int8_t *key, u_int8_t *des_key) +{ + des_key[0] = get7bits(key, 0); + des_key[1] = get7bits(key, 7); + des_key[2] = get7bits(key, 14); + des_key[3] = get7bits(key, 21); + des_key[4] = get7bits(key, 28); + des_key[5] = get7bits(key, 35); + des_key[6] = get7bits(key, 42); + des_key[7] = get7bits(key, 49); + + DES_set_odd_parity((des_cblock *)des_key); +} + +void +mschap_des_encrypt(u_int8_t *clear, u_int8_t *key, u_int8_t *cipher) +{ + des_cblock des_key; + des_key_schedule key_schedule; + + mschap_des_addparity(key, des_key); + + DES_set_key(&des_key, &key_schedule); + DES_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, + &key_schedule, 1); +} + +void +mschap_challenge_response(u_int8_t *challenge, u_int8_t *pwhash, + u_int8_t *response) +{ + u_int8_t padpwhash[21]; + + bzero(&padpwhash, sizeof(padpwhash)); + memcpy(padpwhash, pwhash, MSCHAP_HASH_SZ); + + mschap_des_encrypt(challenge, padpwhash + 0, response + 0); + mschap_des_encrypt(challenge, padpwhash + 7, response + 8); + mschap_des_encrypt(challenge, padpwhash + 14, response + 16); +} + +void +mschap_ntpassword_hash(u_int8_t *in, int inlen, u_int8_t *hash) +{ + EVP_MD_CTX ctx; + u_int mdlen; + + EVP_DigestInit(&ctx, EVP_md4()); + EVP_DigestUpdate(&ctx, in, inlen); + EVP_DigestFinal(&ctx, hash, &mdlen); +} + +void +mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, + u_int8_t *username, int usernamelen, u_int8_t *challenge) +{ + EVP_MD_CTX ctx; + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + u_int8_t *name; + + if ((name = strrchr(username, '\\')) == NULL) + name = username; + else + name++; + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, peer_challenge, MSCHAPV2_CHALLENGE_SZ); + EVP_DigestUpdate(&ctx, auth_challenge, MSCHAPV2_CHALLENGE_SZ); + EVP_DigestUpdate(&ctx, name, strlen(name)); + EVP_DigestFinal(&ctx, md, &mdlen); + + memcpy(challenge, md, MSCHAP_CHALLENGE_SZ); +} + +void +mschap_nt_response(u_int8_t *auth_challenge, u_int8_t *peer_challenge, + u_int8_t *username, int usernamelen, u_int8_t *password, int passwordlen, + u_int8_t *response) +{ + u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; + u_int8_t password_hash[MSCHAP_HASH_SZ]; + + mschap_challenge_hash(peer_challenge, auth_challenge, + username, usernamelen, challenge); + + mschap_ntpassword_hash(password, passwordlen, password_hash); + mschap_challenge_response(challenge, password_hash, response); +} + +void +mschap_auth_response(u_int8_t *password, int passwordlen, + u_int8_t *ntresponse, u_int8_t *auth_challenge, u_int8_t *peer_challenge, + u_int8_t *username, int usernamelen, u_int8_t *auth_response) +{ + EVP_MD_CTX ctx; + u_int8_t password_hash[MSCHAP_HASH_SZ]; + u_int8_t password_hash2[MSCHAP_HASH_SZ]; + u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; + u_int8_t md[SHA_DIGEST_LENGTH], *ptr; + u_int mdlen; + int i; + const u_int8_t hex[] = "0123456789ABCDEF"; + static u_int8_t magic1[39] = { + 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 + }; + static u_int8_t magic2[41] = { + 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E + }; + + mschap_ntpassword_hash(password, passwordlen, password_hash); + mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, password_hash2, sizeof(password_hash2)); + EVP_DigestUpdate(&ctx, ntresponse, 24); + EVP_DigestUpdate(&ctx, magic1, 39); + EVP_DigestFinal(&ctx, md, &mdlen); + + mschap_challenge_hash(peer_challenge, auth_challenge, + username, usernamelen, challenge); + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, md, sizeof(md)); + EVP_DigestUpdate(&ctx, challenge, sizeof(challenge)); + EVP_DigestUpdate(&ctx, magic2, 41); + EVP_DigestFinal(&ctx, md, &mdlen); + + /* + * Encode the value of 'Digest' as "S=" followed by + * 40 ASCII hexadecimal digits and return it in + * AuthenticatorResponse. + * For example, + * "S=0123456789ABCDEF0123456789ABCDEF01234567" + */ + ptr = auth_response; + *ptr++ = 'S'; + *ptr++ = '='; + for (i = 0; i < SHA_DIGEST_LENGTH; i++) { + *ptr++ = hex[md[i] >> 4]; + *ptr++ = hex[md[i] & 0x0f]; + } +} + +void +mschap_masterkey(u_int8_t *password_hash2, u_int8_t *ntresponse, + u_int8_t *masterkey) +{ + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + EVP_MD_CTX ctx; + static u_int8_t magic1[27] = { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 + }; + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, password_hash2, MSCHAP_HASH_SZ); + EVP_DigestUpdate(&ctx, ntresponse, 24); + EVP_DigestUpdate(&ctx, magic1, 27); + EVP_DigestFinal(&ctx, md, &mdlen); + + memcpy(masterkey, md, 16); +} + +void +mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, + int sessionkeylen, int issend, int isserver) +{ + EVP_MD_CTX ctx; + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + u_int8_t *s; + static u_int8_t magic2[84] = { + 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, + 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x2e + }; + static u_int8_t magic3[84] = { + 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e + }; + + if (issend) + s = isserver ? magic3 : magic2; + else + s = isserver ? magic2 : magic3; + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, masterkey, 16); + EVP_DigestUpdate(&ctx, sha1_pad1, 40); + EVP_DigestUpdate(&ctx, s, 84); + EVP_DigestUpdate(&ctx, sha1_pad2, 40); + EVP_DigestFinal(&ctx, md, &mdlen); + + memcpy(sessionkey, md, sessionkeylen); +} + +void +mschap_msk(u_int8_t *password, int passwordlen, + u_int8_t *ntresponse, u_int8_t *msk) +{ + u_int8_t password_hash[MSCHAP_HASH_SZ]; + u_int8_t password_hash2[MSCHAP_HASH_SZ]; + u_int8_t masterkey[MSCHAP_MASTERKEY_SZ]; + u_int8_t sendkey[MSCHAP_MASTERKEY_SZ]; + u_int8_t recvkey[MSCHAP_MASTERKEY_SZ]; + + mschap_ntpassword_hash(password, passwordlen, password_hash); + mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); + + mschap_masterkey(password_hash2, ntresponse, masterkey); + mschap_asymetric_startkey(masterkey, recvkey, sizeof(recvkey), 0, 1); + mschap_asymetric_startkey(masterkey, sendkey, sizeof(sendkey), 1, 1); + + /* 16 bytes receive key + 16 bytes send key + 32 bytes 0 padding */ + bzero(msk, MSCHAP_MSK_SZ); + memcpy(msk, &recvkey, sizeof(recvkey)); + memcpy(msk + sizeof(recvkey), &sendkey, sizeof(sendkey)); +} + +void +mschap_newkey(u_int8_t *startkey, u_int8_t *sessionkey, + long sessionkeylen, u_int8_t *key) +{ + EVP_MD_CTX ctx; + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, startkey, sessionkeylen); + EVP_DigestUpdate(&ctx, sha1_pad1, sizeof(sha1_pad1)); + EVP_DigestUpdate(&ctx, sessionkey, sessionkeylen); + EVP_DigestUpdate(&ctx, sha1_pad2, sizeof(sha1_pad2)); + EVP_DigestFinal(&ctx, md, &mdlen); + + memcpy(key, md, sessionkeylen); +} + +void +mschap_nt(u_int8_t *password_hash, u_int8_t *challenge) +{ + u_int8_t response[24]; + + mschap_challenge_response(challenge, password_hash, response); + memcpy(password_hash, response, sizeof(response)); + password_hash[24] = 1; /* NT-style response */ +} + +void +mschap_lanman(u_int8_t *digest, u_int8_t *challenge, u_int8_t *secret) +{ + static u_int8_t salt[] = "KGS!@#$%"; /* RASAPI32.dll */ + u_int8_t SECRET[14], *ptr, *end; + u_int8_t hash[MSCHAP_HASH_SZ]; + + end = SECRET + sizeof(SECRET); + for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) + *ptr = toupper(*secret); + if (ptr < end) + memset(ptr, '\0', end - ptr); + + mschap_des_encrypt(salt, SECRET, hash); + mschap_des_encrypt(salt, SECRET + 7, hash + 8); + + mschap_challenge_response(challenge, hash, digest); +} + +void +mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, + const u_int8_t *authenticator, const u_int8_t *secret) +{ + EVP_MD_CTX ctx; + u_int8_t b[MD5_DIGEST_LENGTH], p[32]; + u_int i, mdlen; + + EVP_DigestInit(&ctx, EVP_md5()); + EVP_DigestUpdate(&ctx, secret, strlen(secret)); + EVP_DigestUpdate(&ctx, authenticator, 16); + EVP_DigestUpdate(&ctx, crypted, 2); + EVP_DigestFinal(&ctx, b, &mdlen); + + for(i = 0; i < mdlen; i++) { + p[i] = b[i] ^ crypted[i+2]; + } + + EVP_DigestInit(&ctx, EVP_md5()); + EVP_DigestUpdate(&ctx, secret, strlen(secret)); + EVP_DigestUpdate(&ctx, crypted + 2, mdlen); + EVP_DigestFinal(&ctx, b, &mdlen); + + for(i = 0; i < mdlen; i++) { + p[i+16] = b[i] ^ crypted[i+18]; + } + + memcpy(plain, p+1, 16); +} |
