📄 radius.c
字号:
*/ } memcpy(pair->strvalue, ptr, attrlen); break; default: DEBUG(" %s (Unknown Type %d)\n", pair->name, pair->type); free(pair); pair = NULL; break; } if (pair) { debug_pair(pair); *tail = pair; tail = &pair->next; } ptr += attrlen; length -= attrlen; if (vendorlen > 0) vendorlen -= (attrlen + 2); } /* * Merge information from the outside world into our * random pool */ for (length = 0; length < AUTH_VECTOR_LEN; length++) { lrad_rand_pool.randmem[length] += packet->vector[length]; } lrad_rand_pool.randmem[lrad_rand_pool.randmem[0] & 0xff] += packet->id; lrad_rand_pool.randmem[lrad_rand_pool.randmem[1] & 0xff] += packet->data_len; return 0;}/* * Encode password. * * We assume that the passwd buffer passed is big enough. * RFC2138 says the password is max 128 chars, so the size * of the passwd buffer must be at least 129 characters. * Preferably it's just MAX_STRING_LEN. * * int *pwlen is updated to the new length of the encrypted * password - a multiple of 16 bytes. */#define AUTH_PASS_LEN (16)int rad_pwencode(char *passwd, int *pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1]; char digest[AUTH_VECTOR_LEN]; int i, n, secretlen; int len; /* * Pad password to multiple of AUTH_PASS_LEN bytes. */ len = *pwlen; if (len > 128) len = 128; *pwlen = len; if (len % AUTH_PASS_LEN != 0) { n = AUTH_PASS_LEN - (len % AUTH_PASS_LEN); for (i = len; n > 0; n--, i++) passwd[i] = 0; len = *pwlen = i; } else if (len == 0) { memset(passwd, 0, AUTH_PASS_LEN); *pwlen = len = AUTH_PASS_LEN; } /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); memcpy(buffer, secret, secretlen); memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN); /* * Now we can encode the password *in place* */ for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i] ^= digest[i]; if (len <= AUTH_PASS_LEN) return 0; /* * Length > AUTH_PASS_LEN, so we need to use the extended * algorithm. */ for (n = 0; n < 128 && n <= (len - AUTH_PASS_LEN); n += AUTH_PASS_LEN) { memcpy(buffer + secretlen, passwd + n, AUTH_PASS_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i + n + AUTH_PASS_LEN] ^= digest[i]; } return 0;}/* * Decode password. */int rad_pwdecode(char *passwd, int pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1]; char digest[AUTH_VECTOR_LEN]; char r[AUTH_VECTOR_LEN]; char *s; int i, n, secretlen; int rlen; /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); memcpy(buffer, secret, secretlen); memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN); /* * Now we can decode the password *in place* */ memcpy(r, passwd, AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN && i < pwlen; i++) passwd[i] ^= digest[i]; if (pwlen <= AUTH_PASS_LEN) { passwd[pwlen+1] = 0; return pwlen; } /* * Length > AUTH_PASS_LEN, so we need to use the extended * algorithm. */ rlen = ((pwlen - 1) / AUTH_PASS_LEN) * AUTH_PASS_LEN; for (n = rlen; n > 0; n -= AUTH_PASS_LEN ) { s = (n == AUTH_PASS_LEN) ? r : (passwd + n - AUTH_PASS_LEN); memcpy(buffer + secretlen, s, AUTH_PASS_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN && (i + n) < pwlen; i++) passwd[i + n] ^= digest[i]; } passwd[pwlen] = 0; return pwlen;}static unsigned int salt_offset = 0;/* * Encode Tunnel-Password attributes when sending them out on the wire. * * int *pwlen is updated to the new length of the encrypted * password - a multiple of 16 bytes. * * This is per RFC-2868 which adds a two char SALT to the initial intermediate * value MD5 hash. */int rad_tunnel_pwencode(char *passwd, int *pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3]; unsigned char digest[AUTH_VECTOR_LEN]; char* salt; int i, n, secretlen; unsigned len, n2; len = *pwlen; if (len > 127) len = 127; /* * Shift the password 3 positions right to place a salt and original * length, tag will be added automatically on packet send */ for (n=len ; n>=0 ; n--) passwd[n+3] = passwd[n]; salt = passwd; passwd += 2; /* * save original password length as first password character; */ *passwd = len; len += 1; /* * Generate salt. The RFC's say: * * The high bit of salt[0] must be set, each salt in a * packet should be unique, and they should be random * * So, we set the high bit, add in a counter, and then * add in some CSPRNG data. should be OK.. */ salt[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) | (lrad_rand() & 0x07)); salt[1] = lrad_rand(); /* * Padd password to multiple of AUTH_PASS_LEN bytes. */ n = len % AUTH_PASS_LEN; if (n) { n = AUTH_PASS_LEN - n; for (; n > 0; n--, len++) passwd[len] = 0; } /* set new password length */ *pwlen = len + 2; /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); memcpy(buffer, secret, secretlen); for (n2 = 0; n2 < len; n2+=AUTH_PASS_LEN) { if (!n2) { memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); memcpy(buffer + secretlen + AUTH_VECTOR_LEN, salt, 2); librad_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2); } else { memcpy(buffer + secretlen, passwd + n2 - AUTH_PASS_LEN, AUTH_PASS_LEN); librad_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN); } for (i = 0; i < AUTH_PASS_LEN; i++) { passwd[i + n2] ^= digest[i]; } } passwd[n2] = 0; return 0;}/* * Decode Tunnel-Password encrypted attributes. * * Defined in RFC-2868, this uses a two char SALT along with the * initial intermediate value, to differentiate it from the * above. */int rad_tunnel_pwdecode(uint8_t *passwd, int *pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3]; uint8_t digest[AUTH_VECTOR_LEN]; uint8_t decrypted[MAX_STRING_LEN + 1]; int secretlen; unsigned i, n, len; len = *pwlen; /* * We need at least a salt. */ if (len < 2) { librad_log("tunnel password is too short"); return -1; } /* * There's a salt, but no password. Or, there's a salt * and a 'data_len' octet. It's wrong, but at least we * can figure out what it means: the password is empty. * * Note that this means we ignore the 'data_len' field, * if the attribute length tells us that there's no * more data. So the 'data_len' field may be wrong, * but that's ok... */ if (len <= 3) { passwd[0] = 0; *pwlen = 0; return 0; } len -= 2; /* discount the salt */ /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); /* * Set up the initial key: * * b(1) = MD5(secret + vector + salt) */ memcpy(buffer, secret, secretlen); memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); memcpy(buffer + secretlen + AUTH_VECTOR_LEN, passwd, 2); librad_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2); /* * A quick check: decrypt the first octet of the password, * which is the 'data_len' field. Ensure it's sane. * * 'n' doesn't include the 'data_len' octet * 'len' does. */ n = passwd[2] ^ digest[0]; if (n >= len) { librad_log("tunnel password is too long for the attribute"); return -1; } /* * Loop over the data, decrypting it, and generating * the key for the next round of decryption. */ for (n = 0; n < len; n += AUTH_PASS_LEN) { for (i = 0; i < AUTH_PASS_LEN; i++) { decrypted[n + i] = passwd[n + i + 2] ^ digest[i]; /* * Encrypted password may not be aligned * on 16 octets, so we catch that here... */ if ((n + i) == len) break; } /* * Update the digest, based on * * b(n) = MD5(secret + cleartext(n-1) * * but only if there's more data... */ memcpy(buffer + secretlen, passwd + n + 2, AUTH_PASS_LEN); librad_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN); } /* * We've already validated the length of the decrypted * password. Copy it back to the caller. */ memcpy(passwd, decrypted + 1, decrypted[0]); passwd[decrypted[0]] = 0; *pwlen = decrypted[0]; return decrypted[0];}/* * Encode a CHAP password * * FIXME: might not work with Ascend because * we use vp->length, and Ascend gear likes * to send an extra '\0' in the string! */int rad_chap_encode(RADIUS_PACKET *packet, char *output, int id, VALUE_PAIR *password){ int i; char *ptr; char string[MAX_STRING_LEN * 2 + 1]; VALUE_PAIR *challenge; /* * Sanity check the input parameters */ if ((packet == NULL) || (password == NULL)) { return -1; } /* * Note that the password VP can be EITHER * a User-Password attribute (from a check-item list), * or a CHAP-Password attribute (the client asking * the library to encode it). */ i = 0; ptr = string; *ptr++ = id; i++; memcpy(ptr, password->strvalue, password->length); ptr += password->length; i += password->length; /* * Use Chap-Challenge pair if present, * Request-Authenticator otherwise. */ challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE); if (challenge) { memcpy(ptr, challenge->strvalue, challenge->length); i += challenge->length; } else { memcpy(ptr, packet->vector, AUTH_VECTOR_LEN); i += AUTH_VECTOR_LEN; } *output = id; librad_md5_calc((u_char *)output + 1, (u_char *)string, i); return 0;}/* * Create a random vector of AUTH_VECTOR_LEN bytes. */static void random_vector(uint8_t *vector){ int i; if (!lrad_pool_initialized) { memset(&lrad_rand_pool, 0, sizeof(lrad_rand_pool)); /* * Initialize the state to something, using * numbers which aren't random, but which also * aren't static. */ lrad_rand_pool.randrsl[0] = (uint32_t) &lrad_pool_initialized; lrad_rand_pool.randrsl[1] = (uint32_t) &i; lrad_rand_pool.randrsl[2] = (uint32_t) vector; lrad_randinit(&lrad_rand_pool, 1); } lrad_isaac(&lrad_rand_pool); /* * Copy the random data over. */ for (i = 0; i < AUTH_VECTOR_LEN; i++) { *(vector++) = lrad_rand_pool.randrsl[i] & 0xff; }}/* * Return a 32-bit random number. */uint32_t lrad_rand(void){ uint32_t answer; static int rand_index = 0; /* * Ensure that the pool is initialized. */ if (!lrad_pool_initialized) { uint8_t vector[AUTH_VECTOR_LEN]; random_vector(vector); } /* * Grab an entry from the pool. */ answer = lrad_rand_pool.randrsl[rand_index]; /* * Go to the next entry (wrapping around to zero). */ rand_index++; rand_index &= 0xff; /* * Every 256 numbers, churn the pool again. */ if (rand_index == 0) { lrad_isaac(&lrad_rand_pool); } return answer;}/* * Allocate a new RADIUS_PACKET */RADIUS_PACKET *rad_alloc(int newvector){ RADIUS_PACKET *rp; if ((rp = malloc(sizeof(RADIUS_PACKET))) == NULL) { librad_log("out of memory"); return NULL; } memset(rp, 0, sizeof(RADIUS_PACKET)); if (newvector) random_vector(rp->vector); return rp;}/* * Free a RADIUS_PACKET */void rad_free(RADIUS_PACKET **radius_packet_ptr){ RADIUS_PACKET *radius_packet; if (!radius_packet_ptr) return; radius_packet = *radius_packet_ptr; if (radius_packet->data) free(radius_packet->data); if (radius_packet->vps) pairfree(&radius_packet->vps); free(radius_packet); *radius_packet_ptr = NULL;}/************************************************************************* * * Function: make_secret * * Purpose: Build an encrypted secret value to return in a reply * packet. The secret is hidden by xoring with a MD5 digest * created from the shared secret and the authentication * vector. We put them into MD5 in the reverse order from * that used when encrypting passwords to RADIUS. * *************************************************************************/static void make_secret(unsigned char *digest, uint8_t *vector, const char *secret, char *value){ u_char buffer[256 + AUTH_VECTOR_LEN]; int secretLen = strlen(secret); int i; memcpy(buffer, vector, AUTH_VECTOR_LEN ); memcpy(buffer + AUTH_VECTOR_LEN, secret, secretLen ); librad_md5_calc(digest, buffer, AUTH_VECTOR_LEN + secretLen ); memset(buffer, 0, sizeof(buffer)); for ( i = 0; i < AUTH_VECTOR_LEN; i++ ) { digest[i] ^= value[i]; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -