mech-rpa.c revision 87cc5e9025e7fb6408f0de64c48d2d2897773ba5
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen/*
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * Compuserve RPA authentication mechanism.
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * This program is free software; you can redistribute it and/or modify
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * it under the terms of the GNU Lesser General Public License as published
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * by the Free Software Foundation; either version 2 of the License, or
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen * (at your option) any later version.
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen#include "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: */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *pwd_md5;
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;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *session_key;
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,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *digest)
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);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->pwd_md5, 16);
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);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->pwd_md5, 16);
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,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char *digest)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen struct md5_context ctx;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char tmp[16];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char z[48];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen int i;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen memset(z, 0, sizeof(z));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_init(&ctx);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->pwd_md5, 16);
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);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->pwd_md5, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_final(&ctx, tmp);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen for (i = 0; i < 16; i++)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen tmp[i] = request->session_key[i] ^ tmp[i];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_init(&ctx);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->pwd_md5, 16);
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->session_key, 16);
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);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen md5_update(&ctx, tmp, 16);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen md5_update(&ctx, request->pwd_md5, 16);
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
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic int
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainenrpa_parse_token1(const void *data, size_t data_size, const char **error)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *end = ((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
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic char *
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenrpa_parse_username(pool_t pool, const char *username)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const char *p = strrchr(username, '@');
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return p == NULL ? p_strdup(pool, username) :
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p_strdup_until(pool, username, p);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic int
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;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *end = ((unsigned char *)data) + data_size;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *p;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const char *user;
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
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo 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
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen user = t_strndup(p, len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen p += len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen auth_request->user = rpa_parse_username(request->pool, user);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->username_ucs2be = ucs2be_str(request->pool, auth_request->user,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen &request->username_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
63969c244e8973a61760a98a23b127827d3d652cTimo Sirainenstatic const unsigned char *
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenmech_rpa_build_token2(struct rpa_auth_request *request,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const char *realms, size_t *size)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int realms_len;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned int length;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_t *buf;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char timestamp[RPA_TIMESTAMP_LEN / 2];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen realms_len = strlen(realms);
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);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append(buf, realms, realms_len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *size = buffer_get_used_size(buf);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo 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 unsigned int length = sizeof(rpa_oid) + 17 + 17 + 1;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_t *buf;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen unsigned char server_response[16];
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 */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->session_key = p_malloc(request->pool, 16);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen random_fill(request->session_key, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Server authentication response */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen rpa_server_response(request, server_response);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append(buf, server_response, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 16);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buffer_append(buf, request->session_key, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen /* Status, 0 - success */
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_append_c(buf, 0);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen *size = buffer_get_used_size(buf);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return buffer_free_without_data(buf);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenrpa_credentials_callback(const char *credentials,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen struct auth_request *auth_request)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request =
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (struct rpa_auth_request *)auth_request;
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen unsigned char response[16];
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen buffer_t *hash_buffer;
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen const unsigned char *token4;
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen size_t token4_size;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen if (credentials == NULL) {
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen mech_auth_finish(auth_request, NULL, 0, FALSE);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return;
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->pwd_md5 = p_malloc(request->pool, 16);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen hash_buffer = buffer_create_data(request->pool, request->pwd_md5, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen hex_to_binary(credentials, hash_buffer);
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen rpa_user_response(request, response);
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen if (memcmp(response, request->user_response, 16) != 0) {
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen mech_auth_finish(auth_request, NULL, 0, FALSE);
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen return;
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen }
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen token4 = mech_rpa_build_token4(request, &token4_size);
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE,
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen token4, token4_size);
defc2cef0658ea5abe145111336ecc2274eecdb8Timo Sirainen request->phase = 2;
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)) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (verbose) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen i_info("rpa(%s): invalid token 1, %s",
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen get_log_prefix(auth_request), error);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_auth_finish(auth_request, NULL, 0, FALSE);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
87cc5e9025e7fb6408f0de64c48d2d2897773ba5Timo Sirainen service = t_str_lcase(auth_request->service);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen token2 = mech_rpa_build_token2(request, t_strconcat(service, "@",
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen my_hostname, NULL), &token2_size);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->service_ucs2be = ucs2be_str(request->pool, service,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen &request->service_len);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen request->realm_ucs2be = ucs2be_str(request->pool, my_hostname,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen &request->realm_len);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen 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)) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (verbose) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen i_info("rpa(%s): invalid token 3, %s",
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen get_log_prefix(auth_request), error);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_auth_finish(auth_request, NULL, 0, FALSE);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen if (!mech_fix_username(auth_request->user, &error)) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (verbose) {
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen i_info("rpa(%s): %s",
9abfe876fa81576f130f3f82f622ae936c21a716Timo Sirainen get_log_prefix(auth_request), error);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_auth_finish(auth_request, NULL, 0, FALSE);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen passdb->lookup_credentials(auth_request, PASSDB_CREDENTIALS_RPA,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo 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 int ret = TRUE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if ((data_size != sizeof(client_ack)) ||
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (memcmp(data, client_ack, sizeof(client_ack)) != 0)) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen if (verbose) {
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen i_info("rpa(%s): invalid token 5 or client rejects us",
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen get_log_prefix(auth_request));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen ret = FALSE;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_auth_finish(auth_request, NULL, 0, ret);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_continue(struct auth_request *auth_request,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen const unsigned char *data, size_t data_size,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_callback_t *callback)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct rpa_auth_request *request =
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen (struct rpa_auth_request *)auth_request;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen auth_request->callback = callback;
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:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_auth_finish(auth_request, NULL, 0, FALSE);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen break;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen }
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenmech_rpa_auth_initial(struct auth_request *auth_request,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen const unsigned char *data __attr_unused__,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen size_t data_size __attr_unused__,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_callback_t *callback)
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE, NULL, 0);
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
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (request->pwd_md5 != NULL)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen safe_memset(request->pwd_md5, 0, 16);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen pool_unref(auth_request->pool);
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen}
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo 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
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen pool = pool_alloconly_create("rpa_auth_request", 256);
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.refcount = 1;
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
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen MEMBER(passdb_need_plain) FALSE,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen MEMBER(passdb_need_credentials) TRUE,
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mech_rpa_auth_new,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_initial,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_continue,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_rpa_auth_free
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen};