|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* plugins/preauth/spake/groups.c - SPAKE group interfaces */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright (C) 2015 by the Massachusetts Institute of Technology.
|
|
Packit |
fd8b60 |
* All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fd8b60 |
* modification, are permitted provided that the following conditions
|
|
Packit |
fd8b60 |
* are met:
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* * Redistributions of source code must retain the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* * Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer in
|
|
Packit |
fd8b60 |
* the documentation and/or other materials provided with the
|
|
Packit |
fd8b60 |
* distribution.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
fd8b60 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
fd8b60 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
Packit |
fd8b60 |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
Packit |
fd8b60 |
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
Packit |
fd8b60 |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
Packit |
fd8b60 |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
fd8b60 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
fd8b60 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
Packit |
fd8b60 |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
fd8b60 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
Packit |
fd8b60 |
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* The SPAKE2 algorithm works as follows:
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 1. The parties agree on a group, a base element G, and constant elements M
|
|
Packit |
fd8b60 |
* and N. In this mechanism, these parameters are determined by the
|
|
Packit |
fd8b60 |
* registered group number.
|
|
Packit |
fd8b60 |
* 2. Both parties derive a scalar value w from the initial key.
|
|
Packit |
fd8b60 |
* 3. The first party (the KDC, in this mechanism) chooses a random secret
|
|
Packit |
fd8b60 |
* scalar x and sends T=xG+wM.
|
|
Packit |
fd8b60 |
* 4. The second party (the client, in this mechanism) chooses a random
|
|
Packit |
fd8b60 |
* secret scalar y and sends S=yG+wN.
|
|
Packit |
fd8b60 |
* 5. The first party computes K=x(S-wN).
|
|
Packit |
fd8b60 |
* 6. The second party computes the same value as K=y(T-wM).
|
|
Packit |
fd8b60 |
* 7. Both parties derive a key from a random oracle whose input incorporates
|
|
Packit |
fd8b60 |
* the party identities, w, T, S, and K.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* We implement the algorithm using a vtable for each group, where the primary
|
|
Packit |
fd8b60 |
* vtable methods are "keygen" (corresponding to step 3 or 4) and "result"
|
|
Packit |
fd8b60 |
* (corresponding to step 5 or 6). We use the term "private scalar" to refer
|
|
Packit |
fd8b60 |
* to x or y, and "public element" to refer to S or T.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "iana.h"
|
|
Packit |
fd8b60 |
#include "trace.h"
|
|
Packit |
fd8b60 |
#include "groups.h"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define DEFAULT_GROUPS_CLIENT "edwards25519"
|
|
Packit |
fd8b60 |
#define DEFAULT_GROUPS_KDC ""
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef struct groupent_st {
|
|
Packit |
fd8b60 |
const groupdef *gdef;
|
|
Packit |
fd8b60 |
groupdata *gdata;
|
|
Packit |
fd8b60 |
} groupent;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
struct groupstate_st {
|
|
Packit |
fd8b60 |
krb5_boolean is_kdc;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Permitted and groups, from configuration */
|
|
Packit |
fd8b60 |
int32_t *permitted;
|
|
Packit |
fd8b60 |
size_t npermitted;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Optimistic challenge group, from configuration */
|
|
Packit |
fd8b60 |
int32_t challenge_group;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Lazily-initialized list of gdata objects. */
|
|
Packit |
fd8b60 |
groupent *data;
|
|
Packit |
fd8b60 |
size_t ndata;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
extern groupdef builtin_edwards25519;
|
|
Packit |
fd8b60 |
#ifdef SPAKE_OPENSSL
|
|
Packit |
fd8b60 |
extern groupdef ossl_P256;
|
|
Packit |
fd8b60 |
extern groupdef ossl_P384;
|
|
Packit |
fd8b60 |
extern groupdef ossl_P521;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static const groupdef *groupdefs[] = {
|
|
Packit |
fd8b60 |
&builtin_edwards25519,
|
|
Packit |
fd8b60 |
#ifdef SPAKE_OPENSSL
|
|
Packit |
fd8b60 |
&ossl_P256,
|
|
Packit |
fd8b60 |
&ossl_P384,
|
|
Packit |
fd8b60 |
&ossl_P521,
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
NULL
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Find a groupdef structure by group number. Return NULL on failure. */
|
|
Packit |
fd8b60 |
static const groupdef *
|
|
Packit |
fd8b60 |
find_gdef(int32_t group)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
size_t i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = 0; groupdefs[i] != NULL; i++) {
|
|
Packit |
fd8b60 |
if (groupdefs[i]->reg->id == group)
|
|
Packit |
fd8b60 |
return groupdefs[i];
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return NULL;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Find a group number by name. Return 0 on failure. */
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
find_gnum(const char *name)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
size_t i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = 0; groupdefs[i] != NULL; i++) {
|
|
Packit |
fd8b60 |
if (strcasecmp(name, groupdefs[i]->reg->name) == 0)
|
|
Packit |
fd8b60 |
return groupdefs[i]->reg->id;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static krb5_boolean
|
|
Packit |
fd8b60 |
in_grouplist(const int32_t *list, size_t count, int32_t group)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
size_t i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = 0; i < count; i++) {
|
|
Packit |
fd8b60 |
if (list[i] == group)
|
|
Packit |
fd8b60 |
return TRUE;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Retrieve a group data object for group within gstate, lazily initializing it
|
|
Packit |
fd8b60 |
* if necessary. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
get_gdata(krb5_context context, groupstate *gstate, const groupdef *gdef,
|
|
Packit |
fd8b60 |
groupdata **gdata_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code ret;
|
|
Packit |
fd8b60 |
groupent *ent, *newptr;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*gdata_out = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Look for an existing entry. */
|
|
Packit |
fd8b60 |
for (ent = gstate->data; ent < gstate->data + gstate->ndata; ent++) {
|
|
Packit |
fd8b60 |
if (ent->gdef == gdef) {
|
|
Packit |
fd8b60 |
*gdata_out = ent->gdata;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Make a new entry. */
|
|
Packit |
fd8b60 |
newptr = realloc(gstate->data, (gstate->ndata + 1) * sizeof(groupent));
|
|
Packit |
fd8b60 |
if (newptr == NULL)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
gstate->data = newptr;
|
|
Packit |
fd8b60 |
ent = &gstate->data[gstate->ndata];
|
|
Packit |
fd8b60 |
ent->gdef = gdef;
|
|
Packit |
fd8b60 |
ent->gdata = NULL;
|
|
Packit |
fd8b60 |
if (gdef->init != NULL) {
|
|
Packit |
fd8b60 |
ret = gdef->init(context, gdef, &ent->gdata);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
gstate->ndata++;
|
|
Packit |
fd8b60 |
*gdata_out = ent->gdata;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Destructively parse str into a list of group numbers. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
parse_groups(krb5_context context, char *str, int32_t **list_out,
|
|
Packit |
fd8b60 |
size_t *count_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const char *const delim = " \t\r\n,";
|
|
Packit |
fd8b60 |
char *token, *save = NULL;
|
|
Packit |
fd8b60 |
int32_t group, *newptr, *list = NULL;
|
|
Packit |
fd8b60 |
size_t count = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*list_out = NULL;
|
|
Packit |
fd8b60 |
*count_out = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Walk through the words in profstr. */
|
|
Packit |
fd8b60 |
for (token = strtok_r(str, delim, &save); token != NULL;
|
|
Packit |
fd8b60 |
token = strtok_r(NULL, delim, &save)) {
|
|
Packit |
fd8b60 |
group = find_gnum(token);
|
|
Packit |
fd8b60 |
if (!group) {
|
|
Packit |
fd8b60 |
TRACE_SPAKE_UNKNOWN_GROUP(context, token);
|
|
Packit |
fd8b60 |
continue;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (in_grouplist(list, count, group))
|
|
Packit |
fd8b60 |
continue;
|
|
Packit |
fd8b60 |
newptr = realloc(list, (count + 1) * sizeof(*list));
|
|
Packit |
fd8b60 |
if (newptr == NULL) {
|
|
Packit |
fd8b60 |
free(list);
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
list = newptr;
|
|
Packit |
fd8b60 |
list[count++] = group;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*list_out = list;
|
|
Packit |
fd8b60 |
*count_out = count;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
group_init_state(krb5_context context, krb5_boolean is_kdc,
|
|
Packit |
fd8b60 |
groupstate **gstate_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code ret;
|
|
Packit |
fd8b60 |
groupstate *gstate;
|
|
Packit |
fd8b60 |
const char *defgroups;
|
|
Packit |
fd8b60 |
char *profstr1 = NULL, *profstr2 = NULL;
|
|
Packit |
fd8b60 |
int32_t *permitted = NULL, challenge_group = 0;
|
|
Packit |
fd8b60 |
size_t npermitted;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*gstate_out = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
defgroups = is_kdc ? DEFAULT_GROUPS_KDC : DEFAULT_GROUPS_CLIENT;
|
|
Packit |
fd8b60 |
ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
|
|
Packit |
fd8b60 |
KRB5_CONF_SPAKE_PREAUTH_GROUPS, NULL, defgroups,
|
|
Packit |
fd8b60 |
&profstr1);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
ret = parse_groups(context, profstr1, &permitted, &npermitted);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
if (npermitted == 0) {
|
|
Packit |
fd8b60 |
ret = KRB5_PLUGIN_OP_NOTSUPP;
|
|
Packit |
fd8b60 |
k5_setmsg(context, ret, _("No SPAKE preauth groups configured"));
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (is_kdc) {
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Check for a configured optimistic challenge group. If one is set,
|
|
Packit |
fd8b60 |
* the KDC will send a challenge in the PREAUTH_REQUIRED method data,
|
|
Packit |
fd8b60 |
* before receiving the list of supported groups.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
ret = profile_get_string(context->profile, KRB5_CONF_KDCDEFAULTS,
|
|
Packit |
fd8b60 |
KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE, NULL,
|
|
Packit |
fd8b60 |
NULL, &profstr2);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
if (profstr2 != NULL) {
|
|
Packit |
fd8b60 |
challenge_group = find_gnum(profstr2);
|
|
Packit |
fd8b60 |
if (!in_grouplist(permitted, npermitted, challenge_group)) {
|
|
Packit |
fd8b60 |
ret = KRB5_PLUGIN_OP_NOTSUPP;
|
|
Packit |
fd8b60 |
k5_setmsg(context, ret,
|
|
Packit |
fd8b60 |
_("SPAKE challenge group not a permitted group: %s"),
|
|
Packit |
fd8b60 |
profstr2);
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
gstate = k5alloc(sizeof(*gstate), &ret;;
|
|
Packit |
fd8b60 |
if (gstate == NULL)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
gstate->is_kdc = is_kdc;
|
|
Packit |
fd8b60 |
gstate->permitted = permitted;
|
|
Packit |
fd8b60 |
gstate->npermitted = npermitted;
|
|
Packit |
fd8b60 |
gstate->challenge_group = challenge_group;
|
|
Packit |
fd8b60 |
permitted = NULL;
|
|
Packit |
fd8b60 |
gstate->data = NULL;
|
|
Packit |
fd8b60 |
gstate->ndata = 0;
|
|
Packit |
fd8b60 |
*gstate_out = gstate;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cleanup:
|
|
Packit |
fd8b60 |
profile_release_string(profstr1);
|
|
Packit |
fd8b60 |
profile_release_string(profstr2);
|
|
Packit |
fd8b60 |
free(permitted);
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void
|
|
Packit |
fd8b60 |
group_free_state(groupstate *gstate)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
groupent *ent;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (ent = gstate->data; ent < gstate->data + gstate->ndata; ent++) {
|
|
Packit |
fd8b60 |
if (ent->gdata != NULL && ent->gdef->fini != NULL)
|
|
Packit |
fd8b60 |
ent->gdef->fini(ent->gdata);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
free(gstate->permitted);
|
|
Packit |
fd8b60 |
free(gstate->data);
|
|
Packit |
fd8b60 |
free(gstate);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_boolean
|
|
Packit |
fd8b60 |
group_is_permitted(groupstate *gstate, int32_t group)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return in_grouplist(gstate->permitted, gstate->npermitted, group);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void
|
|
Packit |
fd8b60 |
group_get_permitted(groupstate *gstate, int32_t **list_out, int32_t *count_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
*list_out = gstate->permitted;
|
|
Packit |
fd8b60 |
*count_out = gstate->npermitted;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_int32
|
|
Packit |
fd8b60 |
group_optimistic_challenge(groupstate *gstate)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
assert(gstate->is_kdc);
|
|
Packit |
fd8b60 |
return gstate->challenge_group;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
group_mult_len(int32_t group, size_t *len_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const groupdef *gdef;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*len_out = 0;
|
|
Packit |
fd8b60 |
gdef = find_gdef(group);
|
|
Packit |
fd8b60 |
if (gdef == NULL)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
*len_out = gdef->reg->mult_len;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
group_keygen(krb5_context context, groupstate *gstate, int32_t group,
|
|
Packit |
fd8b60 |
const krb5_data *wbytes, krb5_data *priv_out, krb5_data *pub_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code ret;
|
|
Packit |
fd8b60 |
const groupdef *gdef;
|
|
Packit |
fd8b60 |
groupdata *gdata;
|
|
Packit |
fd8b60 |
uint8_t *priv = NULL, *pub = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*priv_out = empty_data();
|
|
Packit |
fd8b60 |
*pub_out = empty_data();
|
|
Packit |
fd8b60 |
gdef = find_gdef(group);
|
|
Packit |
fd8b60 |
if (gdef == NULL || wbytes->length != gdef->reg->mult_len)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
ret = get_gdata(context, gstate, gdef, &gdata);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
priv = k5alloc(gdef->reg->mult_len, &ret;;
|
|
Packit |
fd8b60 |
if (priv == NULL)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
pub = k5alloc(gdef->reg->elem_len, &ret;;
|
|
Packit |
fd8b60 |
if (pub == NULL)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
ret = gdef->keygen(context, gdata, (uint8_t *)wbytes->data, gstate->is_kdc,
|
|
Packit |
fd8b60 |
priv, pub);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*priv_out = make_data(priv, gdef->reg->mult_len);
|
|
Packit |
fd8b60 |
*pub_out = make_data(pub, gdef->reg->elem_len);
|
|
Packit |
fd8b60 |
priv = pub = NULL;
|
|
Packit |
fd8b60 |
TRACE_SPAKE_KEYGEN(context, pub_out);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cleanup:
|
|
Packit |
fd8b60 |
zapfree(priv, gdef->reg->mult_len);
|
|
Packit |
fd8b60 |
free(pub);
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
group_result(krb5_context context, groupstate *gstate, int32_t group,
|
|
Packit |
fd8b60 |
const krb5_data *wbytes, const krb5_data *ourpriv,
|
|
Packit |
fd8b60 |
const krb5_data *theirpub, krb5_data *spakeresult_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code ret;
|
|
Packit |
fd8b60 |
const groupdef *gdef;
|
|
Packit |
fd8b60 |
groupdata *gdata;
|
|
Packit |
fd8b60 |
uint8_t *spakeresult = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*spakeresult_out = empty_data();
|
|
Packit |
fd8b60 |
gdef = find_gdef(group);
|
|
Packit |
fd8b60 |
if (gdef == NULL || wbytes->length != gdef->reg->mult_len)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
if (ourpriv->length != gdef->reg->mult_len ||
|
|
Packit |
fd8b60 |
theirpub->length != gdef->reg->elem_len)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
ret = get_gdata(context, gstate, gdef, &gdata);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
spakeresult = k5alloc(gdef->reg->elem_len, &ret;;
|
|
Packit |
fd8b60 |
if (spakeresult == NULL)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Invert is_kdc here to use the other party's constant. */
|
|
Packit |
fd8b60 |
ret = gdef->result(context, gdata, (uint8_t *)wbytes->data,
|
|
Packit |
fd8b60 |
(uint8_t *)ourpriv->data, (uint8_t *)theirpub->data,
|
|
Packit |
fd8b60 |
!gstate->is_kdc, spakeresult);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*spakeresult_out = make_data(spakeresult, gdef->reg->elem_len);
|
|
Packit |
fd8b60 |
spakeresult = NULL;
|
|
Packit |
fd8b60 |
TRACE_SPAKE_RESULT(context, spakeresult_out);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cleanup:
|
|
Packit |
fd8b60 |
zapfree(spakeresult, gdef->reg->elem_len);
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
group_hash_len(int32_t group, size_t *len_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const groupdef *gdef;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*len_out = 0;
|
|
Packit |
fd8b60 |
gdef = find_gdef(group);
|
|
Packit |
fd8b60 |
if (gdef == NULL)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
*len_out = gdef->reg->hash_len;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
group_hash(krb5_context context, groupstate *gstate, int32_t group,
|
|
Packit |
fd8b60 |
const krb5_data *dlist, size_t ndata, uint8_t *result_out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code ret;
|
|
Packit |
fd8b60 |
const groupdef *gdef;
|
|
Packit |
fd8b60 |
groupdata *gdata;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
gdef = find_gdef(group);
|
|
Packit |
fd8b60 |
if (gdef == NULL)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
ret = get_gdata(context, gstate, gdef, &gdata);
|
|
Packit |
fd8b60 |
if (ret)
|
|
Packit |
fd8b60 |
return ret;
|
|
Packit |
fd8b60 |
return gdef->hash(context, gdata, dlist, ndata, result_out);
|
|
Packit |
fd8b60 |
}
|