a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen/*
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * Compuserve RPA authentication mechanism.
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *
e074ffeaee1ce283bd42f167c6810e3d013f8218Timo Sirainen * This software is released under the MIT license.
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-common.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "mech.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "passdb.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "str.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "strfuncs.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "safe-memset.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "randgen.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "buffer.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "hostpid.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "hex-binary.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "md5.h"
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstruct rpa_auth_request {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen struct auth_request auth_request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen pool_t pool;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen int phase;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* cached: */
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned char pwd_md5[MD5_RESULTLEN];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen size_t service_len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *service_ucs2be;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen size_t username_len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *username_ucs2be;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen size_t realm_len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *realm_ucs2be;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* requested: */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *service_challenge;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *service_timestamp;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* received: */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int user_challenge_len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *user_challenge;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *user_response;
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned char session_key[16];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen};
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#define RPA_SCHALLENGE_LEN 32
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#define RPA_UCHALLENGE_LEN 16
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#define RPA_TIMESTAMP_LEN 14
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#define ASN1_APPLICATION 0x60
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen/* Object id encoded using ASN.1 DER */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic const unsigned char rpa_oid[] = {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x73, 0x01, 0x01
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen};
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenvoid *ucs2be_str(pool_t pool, const char *str, size_t *size);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen/*
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * Compute client -> server authentication response.
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void rpa_user_response(struct rpa_auth_request *request,
9625595c47c665f5aee57ebfcb1fcbe9ad1bf3a0Martti Rannanjärvi unsigned char digest[STATIC_ARRAY MD5_RESULTLEN])
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen struct md5_context ctx;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char z[48];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen memset(z, 0, sizeof(z));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_init(&ctx);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->pwd_md5, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_update(&ctx, z, sizeof(z));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->username_ucs2be, request->username_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_ucs2be, request->service_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->realm_ucs2be, request->realm_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->user_challenge, request->user_challenge_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_challenge, RPA_SCHALLENGE_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_timestamp, RPA_TIMESTAMP_LEN);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->pwd_md5, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_final(&ctx, digest);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen/*
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * Compute server -> client authentication response.
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void rpa_server_response(struct rpa_auth_request *request,
9625595c47c665f5aee57ebfcb1fcbe9ad1bf3a0Martti Rannanjärvi unsigned char digest[STATIC_ARRAY MD5_RESULTLEN])
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen struct md5_context ctx;
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned char tmp[MD5_RESULTLEN];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char z[48];
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned int i;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen memset(z, 0, sizeof(z));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_init(&ctx);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->pwd_md5, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_update(&ctx, z, sizeof(z));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_ucs2be, request->service_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->username_ucs2be, request->username_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->realm_ucs2be, request->realm_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_challenge, RPA_SCHALLENGE_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->user_challenge, request->user_challenge_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_timestamp, RPA_TIMESTAMP_LEN);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->pwd_md5, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_final(&ctx, tmp);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen for (i = 0; i < sizeof(tmp); i++)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen tmp[i] = request->session_key[i] ^ tmp[i];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_init(&ctx);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->pwd_md5, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_update(&ctx, z, sizeof(z));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_ucs2be, request->service_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->username_ucs2be, request->username_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->realm_ucs2be, request->realm_len);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->session_key, sizeof(request->session_key));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_challenge, RPA_SCHALLENGE_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->user_challenge, request->user_challenge_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->service_timestamp, RPA_TIMESTAMP_LEN);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, tmp, sizeof(tmp));
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen md5_update(&ctx, request->pwd_md5, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_final(&ctx, digest);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic const unsigned char *
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenrpa_check_message(const unsigned char *data, const unsigned char *end,
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen const char **error)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *p = data;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int len = 0;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p + 2 > end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "message too short";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return NULL;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (*p++ != ASN1_APPLICATION) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "invalid data type";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return NULL;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if ((*p & 0x80) != 0) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int nbytes = *p++ & 0x7f;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen while (nbytes-- > 0) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p >= end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "invalid structure length";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return NULL;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen len = (len << 8) | *p++;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen } else
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen len = *p++;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if ((size_t)(end - p) != len) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "structure length disagrees with data size";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return NULL;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p + sizeof(rpa_oid) > end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "not enough space for object id";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return NULL;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (memcmp(p, rpa_oid, sizeof(rpa_oid)) != 0) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "invalid object id";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return NULL;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return p + sizeof(rpa_oid);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainenrpa_parse_token1(const void *data, size_t data_size, const char **error)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const unsigned char *end = ((const unsigned char *) data) + data_size;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *p;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int version_lo, version_hi;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p = rpa_check_message(data, end, error);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p == NULL)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p + 6 > end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "message too short";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen version_lo = p[0] + (p[1] << 8);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen version_hi = p[2] + (p[3] << 8);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if ((version_lo > 3) || (version_hi < 3)) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "protocol version mismatch";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p += 4;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if ((p[0] != 0) || (p[1] != 1)) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "invalid message flags";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p += 2;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p != end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "unneeded data found";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return TRUE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic unsigned int
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenrpa_read_buffer(pool_t pool, const unsigned char **data,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *end, unsigned char **buffer)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *p = *data;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p > end)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return 0;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen len = *p++;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p + len > end)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return 0;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *buffer = p_malloc(pool, len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen memcpy(*buffer, p, len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *data += 1 + len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenrpa_parse_token3(struct rpa_auth_request *request, const void *data,
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen size_t data_size, const char **error)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct auth_request *auth_request = &request->auth_request;
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const unsigned char *end = ((const unsigned char *)data) + data_size;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *p;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int len;
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen const char *user, *realm;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p = rpa_check_message(data, end, error);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p == NULL)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Read username@realm */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p + 2 > end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "message too short";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
e065490f54101777ff1b5771499dc24361d5d14dTimo Sirainen len = (p[0] << 8) + p[1];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p + 2 + len > end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "message too short";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p += 2;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen user = t_strndup(p, len);
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen realm = strrchr(user, '@');
7b4259e30aca35f80a490d0eaa6e7190e129585dTimo Sirainen if (realm == NULL) {
7b4259e30aca35f80a490d0eaa6e7190e129585dTimo Sirainen *error = "missing realm";
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen return FALSE;
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen }
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen user = t_strdup_until(user, realm++);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p += len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen if (!auth_request_set_username(auth_request, user, error))
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->username_ucs2be = ucs2be_str(request->pool, auth_request->user,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen &request->username_len);
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen request->realm_ucs2be = ucs2be_str(request->pool, realm,
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen &request->realm_len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Read user challenge */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->user_challenge_len = rpa_read_buffer(request->pool, &p, end,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen &request->user_challenge);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (request->user_challenge_len == 0) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "invalid user challenge";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Read user response */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen len = rpa_read_buffer(request->pool, &p, end, &request->user_response);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (len != RPA_UCHALLENGE_LEN) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "invalid user response";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (p != end) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *error = "unneeded data found";
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return TRUE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenbuffer_append_asn1_length(buffer_t *buf, unsigned int length)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (length < 0x80) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, length);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen } else if (length < 0x100) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 0x81);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, length);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen } else {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 0x82);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, length >> 8);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, length & 0xff);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainenstatic void
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainenrpa_add_realm(string_t *realms, const char *realm, const char *service)
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen{
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen str_append(realms, service);
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen str_append_c(realms, '@');
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen str_append(realms, realm);
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen str_append_c(realms, ' ');
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen}
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen
63969c244e8973a61760a98a23b127827d3d652cTimo Sirainenstatic const unsigned char *
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainenmech_rpa_build_token2(struct rpa_auth_request *request, size_t *size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen const struct auth_settings *set = request->auth_request.set;
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen unsigned int realms_len, length;
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen string_t *realms;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_t *buf;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char timestamp[RPA_TIMESTAMP_LEN / 2];
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *const *tmp;
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen realms = t_str_new(64);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen for (tmp = set->realms_arr; *tmp != NULL; tmp++) {
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen rpa_add_realm(realms, *tmp, request->auth_request.service);
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen }
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen if (str_len(realms) == 0) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen rpa_add_realm(realms, *set->default_realm != '\0' ?
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen set->default_realm : my_hostname,
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen request->auth_request.service);
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen realms_len = str_len(realms) - 1;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen length = sizeof(rpa_oid) + 3 + RPA_SCHALLENGE_LEN +
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen RPA_TIMESTAMP_LEN + 2 + realms_len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buf = buffer_create_dynamic(request->pool, length + 4);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, ASN1_APPLICATION);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_asn1_length(buf, length);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append(buf, rpa_oid, sizeof(rpa_oid));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Protocol version */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 3);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 0);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Service challenge */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->service_challenge =
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen p_malloc(request->pool, RPA_SCHALLENGE_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen random_fill(request->service_challenge, RPA_SCHALLENGE_LEN);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, RPA_SCHALLENGE_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buffer_append(buf, request->service_challenge, RPA_SCHALLENGE_LEN);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Timestamp, looks like clients accept anything we send */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen random_fill(timestamp, sizeof(timestamp));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->service_timestamp = p_malloc(request->pool, RPA_TIMESTAMP_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen memcpy(request->service_timestamp,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen binary_to_hex(timestamp, sizeof(timestamp)),
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen RPA_TIMESTAMP_LEN);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buffer_append(buf, request->service_timestamp, RPA_TIMESTAMP_LEN);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Realm list */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, realms_len >> 8);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, realms_len & 0xff);
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen buffer_append(buf, str_c(realms), realms_len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
2d5d7890bd9b282eb1092fc788a2432a6c79a7adTimo Sirainen *size = buf->used;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen return buffer_free_without_data(&buf);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
63969c244e8973a61760a98a23b127827d3d652cTimo Sirainenstatic const unsigned char *
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenmech_rpa_build_token4(struct rpa_auth_request *request, size_t *size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_t *buf;
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned char server_response[MD5_RESULTLEN];
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned int length = sizeof(rpa_oid) +
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen sizeof(server_response) + 1 +
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen sizeof(request->session_key) + 1 + 1;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buf = buffer_create_dynamic(request->pool, length + 4);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, ASN1_APPLICATION);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_asn1_length(buf, length);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append(buf, rpa_oid, sizeof(rpa_oid));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Generate random session key */
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen random_fill(request->session_key, sizeof(request->session_key));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Server authentication response */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen rpa_server_response(request, server_response);
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen buffer_append_c(buf, sizeof(server_response));
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen buffer_append(buf, server_response, sizeof(server_response));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen buffer_append_c(buf, sizeof(request->session_key));
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen buffer_append(buf, request->session_key, sizeof(request->session_key));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Status, 0 - success */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 0);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
2d5d7890bd9b282eb1092fc788a2432a6c79a7adTimo Sirainen *size = buf->used;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen return buffer_free_without_data(&buf);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool verify_credentials(struct rpa_auth_request *request,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen const unsigned char *credentials, size_t size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
cbf9ab418bb8f5fb41b15fad82b47b9cd6ee8a6bTimo Sirainen unsigned char response[MD5_RESULTLEN];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen if (size != sizeof(request->pwd_md5)) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(&request->auth_request, AUTH_SUBSYS_MECH,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen "invalid credentials length");
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen return FALSE;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen memcpy(request->pwd_md5, credentials, sizeof(request->pwd_md5));
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen rpa_user_response(request, response);
ace06232cfa0e99ecca1040e8553b3216d025768Timo Sirainen return mem_equals_timing_safe(response, request->user_response, sizeof(response));
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen}
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainenstatic void
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainenrpa_credentials_callback(enum passdb_result result,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen const unsigned char *credentials, size_t size,
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen struct auth_request *auth_request)
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen{
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen struct rpa_auth_request *request =
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen (struct rpa_auth_request *)auth_request;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen const unsigned char *token4;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen size_t token4_size;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen switch (result) {
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen case PASSDB_RESULT_OK:
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen if (!verify_credentials(request, credentials, size))
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen auth_request_fail(auth_request);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen else {
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen token4 = mech_rpa_build_token4(request, &token4_size);
50782de8a9d5ebe11ee61496b4e695a1d3875230Timo Sirainen auth_request_handler_reply_continue(auth_request,
50782de8a9d5ebe11ee61496b4e695a1d3875230Timo Sirainen token4,
50782de8a9d5ebe11ee61496b4e695a1d3875230Timo Sirainen token4_size);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen request->phase = 2;
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen }
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen break;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen case PASSDB_RESULT_INTERNAL_FAILURE:
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen auth_request_internal_failure(auth_request);
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen break;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen default:
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen auth_request_fail(auth_request);
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen break;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_phase1(struct auth_request *auth_request,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen const unsigned char *data, size_t data_size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request =
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (struct rpa_auth_request *)auth_request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *token2;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen size_t token2_size;
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen const char *service, *error;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (!rpa_parse_token1(data, data_size, &error)) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_info(auth_request, AUTH_SUBSYS_MECH,
49e513d090753ccbf95560b2f3a21f081a5b6c51Timo Sirainen "invalid token 1: %s", error);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen auth_request_fail(auth_request);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
87cc5e9025e7fb6408f0de64c48d2d2897773ba5Timo Sirainen service = t_str_lcase(auth_request->service);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
5bcbe269efd7aeb8bf38a16d1e7cdaee1425576bTimo Sirainen token2 = mech_rpa_build_token2(request, &token2_size);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->service_ucs2be = ucs2be_str(request->pool, service,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen &request->service_len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
50782de8a9d5ebe11ee61496b4e695a1d3875230Timo Sirainen auth_request_handler_reply_continue(auth_request, token2, token2_size);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->phase = 1;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_phase2(struct auth_request *auth_request,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen const unsigned char *data, size_t data_size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request =
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (struct rpa_auth_request *)auth_request;
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen const char *error;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (!rpa_parse_token3(request, data, data_size, &error)) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_info(auth_request, AUTH_SUBSYS_MECH,
49e513d090753ccbf95560b2f3a21f081a5b6c51Timo Sirainen "invalid token 3: %s", error);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen auth_request_fail(auth_request);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen auth_request_lookup_credentials(auth_request, "RPA",
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen rpa_credentials_callback);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_phase3(struct auth_request *auth_request,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen const unsigned char *data, size_t data_size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen static const unsigned char client_ack[3] = { 0x60, 0x01, 0x00 };
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if ((data_size != sizeof(client_ack)) ||
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (memcmp(data, client_ack, sizeof(client_ack)) != 0)) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_info(auth_request, AUTH_SUBSYS_MECH,
49e513d090753ccbf95560b2f3a21f081a5b6c51Timo Sirainen "invalid token 5 or client rejects us");
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen auth_request_fail(auth_request);
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen } else {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen auth_request_success(auth_request, "", 0);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_continue(struct auth_request *auth_request,
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen const unsigned char *data, size_t data_size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request =
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (struct rpa_auth_request *)auth_request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen switch (request->phase) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case 0:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_phase1(auth_request, data, data_size);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen break;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case 1:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_phase2(auth_request, data, data_size);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen break;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case 2:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_phase3(auth_request, data, data_size);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen break;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen default:
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen auth_request_fail(auth_request);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen break;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_free(struct auth_request *auth_request)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request =
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (struct rpa_auth_request *)auth_request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a8672a757f6f9a610d9bf1e65bd3503904f44f1fTimo Sirainen safe_memset(request->pwd_md5, 0, sizeof(request->pwd_md5));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&auth_request->pool);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainenstatic struct auth_request *mech_rpa_auth_new(void)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen pool_t pool;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
1b81b28b2e7856748cffd7d01052a944b6c80b23Timo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"rpa_auth_request", 2048);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request = p_new(pool, struct rpa_auth_request, 1);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->pool = pool;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->phase = 0;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->auth_request.pool = pool;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return &request->auth_request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenconst struct mech_module mech_rpa = {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen "RPA",
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .flags = MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE |
ac3cf88b470320c924965622329930c2c89b8e72Timo Sirainen MECH_SEC_MUTUAL_AUTH,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .passdb_need = MECH_PASSDB_NEED_LOOKUP_CREDENTIALS,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_rpa_auth_new,
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mech_generic_auth_initial,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_continue,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_free
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen};