
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@18845 ec53bebd-3082-4978-b11e-865c3cabbd6b
804 lines
20 KiB
C
804 lines
20 KiB
C
/*
|
|
* Copyright (c) 2006 Kungliga Tekniska Högskolan
|
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "krb5_locl.h"
|
|
RCSID("$Id$");
|
|
#include "digest_asn1.h"
|
|
|
|
struct krb5_digest {
|
|
char *cbtype;
|
|
char *cbbinding;
|
|
|
|
DigestInit init;
|
|
DigestInitReply initReply;
|
|
DigestRequest request;
|
|
DigestResponse response;
|
|
};
|
|
|
|
krb5_error_code
|
|
krb5_digest_alloc(krb5_context context, krb5_digest *digest)
|
|
{
|
|
krb5_digest d;
|
|
|
|
d = calloc(1, sizeof(*d));
|
|
if (d == NULL) {
|
|
*digest = NULL;
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest = d;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
krb5_digest_free(krb5_digest digest)
|
|
{
|
|
if (digest == NULL)
|
|
return;
|
|
free_DigestInit(&digest->init);
|
|
free_DigestInitReply(&digest->initReply);
|
|
free_DigestRequest(&digest->request);
|
|
free_DigestResponse(&digest->response);
|
|
memset(digest, 0, sizeof(*digest));
|
|
free(digest);
|
|
return;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_server_cb(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *type,
|
|
const char *binding)
|
|
{
|
|
if (digest->init.channel) {
|
|
krb5_set_error_string(context, "server channel binding already set");
|
|
return EINVAL;
|
|
}
|
|
digest->init.channel = calloc(1, sizeof(*digest->init.channel));
|
|
if (digest->init.channel == NULL)
|
|
goto error;
|
|
|
|
digest->init.channel->cb_type = strdup(type);
|
|
if (digest->init.channel->cb_type == NULL)
|
|
goto error;
|
|
|
|
digest->init.channel->cb_binding = strdup(binding);
|
|
if (digest->init.channel->cb_binding == NULL)
|
|
goto error;
|
|
return 0;
|
|
error:
|
|
if (digest->init.channel) {
|
|
free(digest->init.channel->cb_type);
|
|
free(digest->init.channel->cb_binding);
|
|
free(digest->init.channel);
|
|
digest->init.channel = NULL;
|
|
}
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_type(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *type)
|
|
{
|
|
if (digest->init.type) {
|
|
krb5_set_error_string(context, "client type already set");
|
|
return EINVAL;
|
|
}
|
|
digest->init.type = strdup(type);
|
|
if (digest->init.type == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_hostname(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *hostname)
|
|
{
|
|
if (digest->init.hostname) {
|
|
krb5_set_error_string(context, "server hostname already set");
|
|
return EINVAL;
|
|
}
|
|
digest->init.hostname = malloc(sizeof(*digest->init.hostname));
|
|
if (digest->init.hostname == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->init.hostname = strdup(hostname);
|
|
if (*digest->init.hostname == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->init.hostname);
|
|
digest->init.hostname = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *
|
|
krb5_digest_get_server_nonce(krb5_context context,
|
|
krb5_digest digest)
|
|
{
|
|
return digest->initReply.nonce;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_server_nonce(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *nonce)
|
|
{
|
|
if (digest->request.serverNonce) {
|
|
krb5_set_error_string(context, "nonce already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.serverNonce = strdup(nonce);
|
|
if (digest->request.serverNonce == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *
|
|
krb5_digest_get_opaque(krb5_context context,
|
|
krb5_digest digest)
|
|
{
|
|
return digest->initReply.opaque;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_opaque(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *opaque)
|
|
{
|
|
if (digest->request.opaque) {
|
|
krb5_set_error_string(context, "opaque already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.opaque = strdup(opaque);
|
|
if (digest->request.opaque == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *
|
|
krb5_digest_get_identifier(krb5_context context,
|
|
krb5_digest digest)
|
|
{
|
|
if (digest->initReply.identifier == NULL)
|
|
return NULL;
|
|
return *digest->initReply.identifier;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_identifier(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *id)
|
|
{
|
|
if (digest->request.identifier) {
|
|
krb5_set_error_string(context, "identifier already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.identifier = calloc(1, sizeof(*digest->request.identifier));
|
|
if (digest->request.identifier == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.identifier = strdup(id);
|
|
if (*digest->request.identifier == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.identifier);
|
|
digest->request.identifier = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static krb5_error_code
|
|
digest_request(krb5_context context,
|
|
krb5_digest digest,
|
|
krb5_realm realm,
|
|
krb5_ccache ccache,
|
|
krb5_key_usage usage,
|
|
const DigestReqInner *ireq,
|
|
DigestRepInner *irep)
|
|
{
|
|
DigestREQ req;
|
|
DigestREP rep;
|
|
krb5_error_code ret;
|
|
krb5_data data, data2;
|
|
size_t size;
|
|
krb5_crypto crypto = NULL;
|
|
krb5_auth_context ac = NULL;
|
|
krb5_principal principal = NULL;
|
|
krb5_ccache id = NULL;
|
|
krb5_realm r = NULL;
|
|
|
|
krb5_data_zero(&data);
|
|
krb5_data_zero(&data2);
|
|
memset(&req, 0, sizeof(req));
|
|
memset(&rep, 0, sizeof(rep));
|
|
|
|
if (ccache == NULL) {
|
|
ret = krb5_cc_default(context, &id);
|
|
if (ret)
|
|
goto out;
|
|
} else
|
|
id = ccache;
|
|
|
|
if (realm == NULL) {
|
|
ret = krb5_get_default_realm(context, &r);
|
|
if (ret)
|
|
goto out;
|
|
} else
|
|
r = realm;
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
ret = krb5_make_principal(context, &principal,
|
|
r, KRB5_DIGEST_NAME, r, NULL);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length,
|
|
ireq, &size, ret);
|
|
if (ret) {
|
|
krb5_set_error_string(context,
|
|
"Failed to encode digest inner request");
|
|
goto out;
|
|
}
|
|
if (size != data.length)
|
|
krb5_abortx(context, "ASN.1 internal encoder error");
|
|
|
|
ret = krb5_mk_req_exact(context, &ac,
|
|
AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED,
|
|
principal, NULL, id, &req.apReq);
|
|
if (ret)
|
|
goto out;
|
|
|
|
{
|
|
krb5_keyblock *key;
|
|
|
|
ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
|
|
if (ret)
|
|
goto out;
|
|
if (key == NULL) {
|
|
krb5_set_error_string(context, "Digest failed to get local subkey");
|
|
ret = EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
ret = krb5_crypto_init(context, key, 0, &crypto);
|
|
krb5_free_keyblock (context, key);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
|
|
ret = krb5_encrypt_EncryptedData(context, crypto, usage,
|
|
data.data, data.length, 0,
|
|
&req.innerReq);
|
|
if (ret)
|
|
goto out;
|
|
|
|
krb5_data_free(&data);
|
|
|
|
ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length,
|
|
&req, &size, ret);
|
|
if (ret) {
|
|
krb5_set_error_string(context, "Failed to encode DigestREQest");
|
|
goto out;
|
|
}
|
|
if (size != data.length)
|
|
krb5_abortx(context, "ASN.1 internal encoder error");
|
|
|
|
ret = krb5_sendto_kdc(context, &data, &r, &data2);
|
|
if (ret)
|
|
goto out;
|
|
|
|
free_DigestResponse(&digest->response);
|
|
|
|
ret = decode_DigestREP(data2.data, data2.length, &rep, NULL);
|
|
if (ret) {
|
|
krb5_set_error_string(context, "Failed to parse digest response");
|
|
goto out;
|
|
}
|
|
|
|
{
|
|
krb5_ap_rep_enc_part *repl;
|
|
|
|
ret = krb5_rd_rep(context, ac, &rep.apRep, &repl);
|
|
if (ret)
|
|
goto out;
|
|
|
|
krb5_free_ap_rep_enc_part(context, repl);
|
|
}
|
|
{
|
|
krb5_keyblock *key;
|
|
|
|
ret = krb5_auth_con_getremotesubkey(context, ac, &key);
|
|
if (ret)
|
|
goto out;
|
|
if (key == NULL) {
|
|
ret = EINVAL;
|
|
krb5_set_error_string(context,
|
|
"Digest reply have no remote subkey");
|
|
goto out;
|
|
}
|
|
|
|
krb5_crypto_destroy(context, crypto);
|
|
ret = krb5_crypto_init(context, key, 0, &crypto);
|
|
krb5_free_keyblock (context, key);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
|
|
krb5_data_free(&data);
|
|
ret = krb5_decrypt_EncryptedData(context, crypto, usage,
|
|
&rep.innerRep, &data);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = decode_DigestRepInner(data.data, data.length, irep, NULL);
|
|
if (ret) {
|
|
krb5_set_error_string(context, "Failed to decode digest inner reply");
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
if (ccache == NULL && id)
|
|
krb5_cc_close(context, id);
|
|
if (realm == NULL && r)
|
|
free(r);
|
|
if (crypto)
|
|
krb5_crypto_destroy(context, crypto);
|
|
if (ac)
|
|
krb5_auth_con_free(context, ac);
|
|
if (principal)
|
|
krb5_free_principal(context, principal);
|
|
|
|
krb5_data_free(&data);
|
|
krb5_data_free(&data2);
|
|
|
|
free_DigestREQ(&req);
|
|
free_DigestREP(&rep);
|
|
|
|
return ret;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_init_request(krb5_context context,
|
|
krb5_digest digest,
|
|
krb5_realm realm,
|
|
krb5_ccache ccache)
|
|
{
|
|
DigestReqInner ireq;
|
|
DigestRepInner irep;
|
|
krb5_error_code ret;
|
|
|
|
memset(&ireq, 0, sizeof(ireq));
|
|
memset(&irep, 0, sizeof(irep));
|
|
|
|
if (digest->init.type == NULL) {
|
|
krb5_set_error_string(context, "Type missing from init req");
|
|
return EINVAL;
|
|
}
|
|
|
|
ireq.element = choice_DigestReqInner_init;
|
|
ireq.u.init = digest->init;
|
|
|
|
ret = digest_request(context, digest, realm, ccache,
|
|
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
|
|
if (ret)
|
|
goto out;
|
|
|
|
if (irep.element == choice_DigestRepInner_error) {
|
|
krb5_set_error_string(context, "Digest init error: %s",
|
|
irep.u.error.reason);
|
|
ret = irep.u.error.code;
|
|
goto out;
|
|
}
|
|
|
|
if (irep.element != choice_DigestRepInner_initReply) {
|
|
krb5_set_error_string(context, "digest reply not an initReply");
|
|
ret = EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply);
|
|
if (ret) {
|
|
krb5_set_error_string(context, "Failed to copy initReply");
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
free_DigestRepInner(&irep);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_client_nonce(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *nonce)
|
|
{
|
|
if (digest->request.clientNonce) {
|
|
krb5_set_error_string(context, "clientNonce already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.clientNonce =
|
|
calloc(1, sizeof(*digest->request.clientNonce));
|
|
if (digest->request.clientNonce == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.clientNonce = strdup(nonce);
|
|
if (*digest->request.clientNonce == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.clientNonce);
|
|
digest->request.clientNonce = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_digest(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *dgst)
|
|
{
|
|
if (digest->request.digest) {
|
|
krb5_set_error_string(context, "digest already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.digest = strdup(dgst);
|
|
if (digest->request.digest == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_username(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *username)
|
|
{
|
|
if (digest->request.username) {
|
|
krb5_set_error_string(context, "username already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.username = strdup(username);
|
|
if (digest->request.username == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_authid(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *authid)
|
|
{
|
|
if (digest->request.authid) {
|
|
krb5_set_error_string(context, "authid already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.authid = malloc(sizeof(*digest->request.authid));
|
|
if (digest->request.authid == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.authid = strdup(authid);
|
|
if (*digest->request.authid == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.authid);
|
|
digest->request.authid = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_authentication_user(krb5_context context,
|
|
krb5_digest digest,
|
|
krb5_principal authentication_user)
|
|
{
|
|
krb5_error_code ret;
|
|
|
|
if (digest->request.authentication_user) {
|
|
krb5_set_error_string(context, "authentication_user already set");
|
|
return EINVAL;
|
|
}
|
|
ret = krb5_copy_principal(context,
|
|
authentication_user,
|
|
&digest->request.authentication_user);
|
|
if (digest->request.authentication_user == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_realm(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *realm)
|
|
{
|
|
if (digest->request.realm) {
|
|
krb5_set_error_string(context, "realm already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.realm = malloc(sizeof(*digest->request.realm));
|
|
if (digest->request.realm == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.realm = strdup(realm);
|
|
if (*digest->request.realm == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.realm);
|
|
digest->request.realm = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_method(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *method)
|
|
{
|
|
if (digest->request.method) {
|
|
krb5_set_error_string(context, "method already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.method = malloc(sizeof(*digest->request.method));
|
|
if (digest->request.method == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.method = strdup(method);
|
|
if (*digest->request.method == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.method);
|
|
digest->request.method = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_uri(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *uri)
|
|
{
|
|
if (digest->request.uri) {
|
|
krb5_set_error_string(context, "uri already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.uri = malloc(sizeof(*digest->request.uri));
|
|
if (digest->request.uri == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.uri = strdup(uri);
|
|
if (*digest->request.uri == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.uri);
|
|
digest->request.uri = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_nonceCount(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *nonce_count)
|
|
{
|
|
if (digest->request.nonceCount) {
|
|
krb5_set_error_string(context, "nonceCount already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.nonceCount =
|
|
malloc(sizeof(*digest->request.nonceCount));
|
|
if (digest->request.nonceCount == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.nonceCount = strdup(nonce_count);
|
|
if (*digest->request.nonceCount == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.nonceCount);
|
|
digest->request.nonceCount = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_set_qop(krb5_context context,
|
|
krb5_digest digest,
|
|
const char *qop)
|
|
{
|
|
if (digest->request.qop) {
|
|
krb5_set_error_string(context, "qop already set");
|
|
return EINVAL;
|
|
}
|
|
digest->request.qop = malloc(sizeof(*digest->request.qop));
|
|
if (digest->request.qop == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
*digest->request.qop = strdup(qop);
|
|
if (*digest->request.qop == NULL) {
|
|
krb5_set_error_string(context, "out of memory");
|
|
free(digest->request.qop);
|
|
digest->request.qop = NULL;
|
|
return ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_request(krb5_context context,
|
|
krb5_digest digest,
|
|
krb5_realm realm,
|
|
krb5_ccache ccache)
|
|
{
|
|
DigestReqInner ireq;
|
|
DigestRepInner irep;
|
|
krb5_error_code ret;
|
|
|
|
memset(&ireq, 0, sizeof(ireq));
|
|
memset(&irep, 0, sizeof(irep));
|
|
|
|
ireq.element = choice_DigestReqInner_digestRequest;
|
|
ireq.u.digestRequest = digest->request;
|
|
|
|
if (digest->request.type == NULL) {
|
|
if (digest->init.type == NULL) {
|
|
krb5_set_error_string(context, "Type missing from req");
|
|
return EINVAL;
|
|
}
|
|
ireq.u.digestRequest.type = digest->init.type;
|
|
}
|
|
|
|
if (ireq.u.digestRequest.digest == NULL)
|
|
ireq.u.digestRequest.digest = "md5";
|
|
|
|
ret = digest_request(context, digest, realm, ccache,
|
|
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (irep.element == choice_DigestRepInner_error) {
|
|
krb5_set_error_string(context, "Digest response error: %s",
|
|
irep.u.error.reason);
|
|
ret = irep.u.error.code;
|
|
goto out;
|
|
}
|
|
|
|
if (irep.element != choice_DigestRepInner_response) {
|
|
krb5_set_error_string(context, "digest reply not an DigestResponse");
|
|
ret = EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
ret = copy_DigestResponse(&irep.u.response, &digest->response);
|
|
if (ret) {
|
|
krb5_set_error_string(context, "Failed to copy initReply");
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
free_DigestRepInner(&irep);
|
|
|
|
return ret;
|
|
}
|
|
|
|
const char *
|
|
krb5_digest_get_responseData(krb5_context context,
|
|
krb5_digest digest)
|
|
{
|
|
return digest->response.responseData;
|
|
}
|
|
|
|
const char *
|
|
krb5_digest_get_rsp(krb5_context context,
|
|
krb5_digest digest)
|
|
{
|
|
if (digest->response.rsp == NULL)
|
|
return NULL;
|
|
return *digest->response.rsp;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_get_tickets(krb5_context context,
|
|
krb5_digest digest,
|
|
Ticket **tickets)
|
|
{
|
|
*tickets = NULL;
|
|
return 0;
|
|
}
|
|
|
|
|
|
krb5_error_code
|
|
krb5_digest_get_client_binding(krb5_context context,
|
|
krb5_digest digest,
|
|
char **type,
|
|
char **binding)
|
|
{
|
|
if (digest->response.channel) {
|
|
*type = strdup(digest->response.channel->cb_type);
|
|
*binding = strdup(digest->response.channel->cb_binding);
|
|
if (*type == NULL || *binding == NULL) {
|
|
free(*type);
|
|
free(*binding);
|
|
krb5_set_error_string(context, "out of memory");
|
|
return ENOMEM;
|
|
}
|
|
} else {
|
|
*type = NULL;
|
|
*binding = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code
|
|
krb5_digest_get_a1_hash(krb5_context context,
|
|
krb5_digest digest,
|
|
krb5_data *data)
|
|
{
|
|
krb5_error_code ret;
|
|
|
|
krb5_data_zero(data);
|
|
if (digest->response.hash_a1 == NULL)
|
|
return 0;
|
|
ret = der_copy_octet_string(digest->response.hash_a1, data);
|
|
if (ret)
|
|
krb5_clear_error_string(context);
|
|
|
|
return ret;
|
|
}
|