58
55
int longhorn = 0; /* Talking to a Longhorn server? */
58
* Return true if we should use ContentInfo rather than SignedData. This
59
* happens if we are talking to what might be an old (pre-6112) MIT KDC and
60
* we're using anonymous.
63
use_content_info(krb5_context context, pkinit_req_context req,
64
krb5_principal client)
68
if (krb5_principal_compare_any_realm(context, client,
69
krb5_anonymous_principal()))
60
74
static krb5_error_code
61
75
pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
62
76
pkinit_req_context reqctx, krb5_timestamp ctsec,
71
85
krb5_kdc_req *request, const krb5_data *as_rep,
72
86
krb5_keyblock *key_block, krb5_enctype etype, krb5_data *);
74
static void pkinit_client_plugin_fini(krb5_context context, void *blob);
88
static void pkinit_client_plugin_fini(krb5_context context,
89
krb5_clpreauth_moddata moddata);
76
91
static krb5_error_code
77
92
pa_pkinit_gen_req(krb5_context context,
264
279
auth_pack->pkAuthenticator.paChecksum = *cksum;
265
280
auth_pack->clientDHNonce.length = 0;
266
281
auth_pack->clientPublicValue = info;
282
auth_pack->supportedKDFs = (krb5_octet_data **) supported_kdf_alg_ids;
268
284
/* add List of CMS algorithms */
269
285
retval = create_krb5_supportedCMSTypes(context, plgctx->cryptoctx,
349
/* For the new protocol, we support anonymous. */
350
if (krb5_principal_compare_any_realm(context, client,
351
krb5_anonymous_principal())) {
365
if (use_content_info(context, reqctx, client)) {
352
366
retval = cms_contentinfo_create(context, plgctx->cryptoctx,
353
367
reqctx->cryptoctx, reqctx->idctx,
354
368
CMS_SIGN_CLIENT, (unsigned char *)
781
retval = pkinit_octetstring2key(context, etype, client_key,
782
client_key_len, key_block);
784
pkiDebug("failed to create key pkinit_octetstring2key %s\n",
785
error_message(retval));
797
/* If we have a KDF algorithm ID, call the algorithm agility KDF... */
798
if (kdc_reply->u.dh_Info.kdfID) {
799
secret.length = client_key_len;
800
secret.data = client_key;
802
retval = pkinit_alg_agility_kdf(context, &secret,
803
kdc_reply->u.dh_Info.kdfID,
805
request->server, etype,
806
(krb5_octet_data *)encoded_request,
807
(krb5_octet_data *)as_rep,
811
pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n",
812
error_message(retval));
816
/* ...otherwise, use the older octetstring2key function. */
819
retval = pkinit_octetstring2key(context, etype, client_key,
820
client_key_len, key_block);
822
pkiDebug("failed to create key pkinit_octetstring2key %s\n",
823
error_message(retval));
977
1016
static krb5_error_code
978
pkinit_client_process(krb5_context context,
979
void *plugin_context,
980
void *request_context,
1017
pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
1018
krb5_clpreauth_modreq modreq,
981
1019
krb5_get_init_creds_opt *gic_opt,
982
preauth_get_client_data_proc get_data_proc,
983
struct _krb5_preauth_client_rock *rock,
984
krb5_kdc_req *request,
985
krb5_data *encoded_request_body,
1020
krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
1021
krb5_kdc_req *request, krb5_data *encoded_request_body,
986
1022
krb5_data *encoded_previous_request,
987
1023
krb5_pa_data *in_padata,
988
krb5_prompter_fct prompter,
990
preauth_get_as_key_proc gak_fct,
993
krb5_data *s2kparams,
994
krb5_keyblock *as_key,
1024
krb5_prompter_fct prompter, void *prompter_data,
995
1025
krb5_pa_data ***out_padata)
997
1027
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
998
1028
krb5_enctype enctype = -1;
999
krb5_data *cdata = NULL;
1000
1029
int processing_request = 0;
1001
pkinit_context plgctx = (pkinit_context)plugin_context;
1002
pkinit_req_context reqctx = (pkinit_req_context)request_context;
1003
krb5_keyblock *armor_key = NULL;
1030
pkinit_context plgctx = (pkinit_context)moddata;
1031
pkinit_req_context reqctx = (pkinit_req_context)modreq;
1032
krb5_keyblock *armor_key = cb->fast_armor(context, rock), as_key;
1005
1034
pkiDebug("pkinit_client_process %p %p %p %p\n",
1006
1035
context, plgctx, reqctx, request);
1008
1037
/* Remove (along with armor_key) when FAST PKINIT is settled. */
1009
retval = fast_get_armor_key(context, get_data_proc, rock, &armor_key);
1010
if (retval == 0 && armor_key != NULL) {
1011
/* Don't use PKINIT if also using FAST. */
1012
krb5_free_keyblock(context, armor_key);
1038
/* Don't use PKINIT if also using FAST. */
1039
if (armor_key != NULL)
1016
1042
if (plgctx == NULL || reqctx == NULL)
1019
1045
switch ((int) in_padata->pa_type) {
1046
case KRB5_PADATA_PKINIT_KX:
1047
reqctx->rfc6112_kdc = 1;
1020
1049
case KRB5_PADATA_PK_AS_REQ:
1021
1050
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
1022
1051
processing_request = 1;
1062
1091
* Get the enctype of the reply.
1064
retval = (*get_data_proc)(context, rock,
1065
krb5plugin_preauth_client_get_etype, &cdata);
1067
pkiDebug("get_data_proc returned %d (%s)\n",
1068
retval, error_message(retval));
1071
enctype = *((krb5_enctype *)cdata->data);
1072
(*get_data_proc)(context, rock,
1073
krb5plugin_preauth_client_free_etype, &cdata);
1093
enctype = cb->get_etype(context, rock);
1074
1094
retval = pa_pkinit_parse_rep(context, plgctx, reqctx, request,
1075
in_padata, enctype, as_key,
1095
in_padata, enctype, &as_key,
1076
1096
encoded_previous_request);
1098
retval = cb->set_as_key(context, rock, &as_key);
1079
1101
pkiDebug("pkinit_client_process: returning %d (%s)\n",
1084
1106
static krb5_error_code
1085
pkinit_client_tryagain(krb5_context context,
1086
void *plugin_context,
1087
void *request_context,
1107
pkinit_client_tryagain(krb5_context context, krb5_clpreauth_moddata moddata,
1108
krb5_clpreauth_modreq modreq,
1088
1109
krb5_get_init_creds_opt *gic_opt,
1089
preauth_get_client_data_proc get_data_proc,
1090
struct _krb5_preauth_client_rock *rock,
1091
krb5_kdc_req *request,
1092
krb5_data *encoded_request_body,
1110
krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
1111
krb5_kdc_req *request, krb5_data *encoded_request_body,
1093
1112
krb5_data *encoded_previous_request,
1094
krb5_pa_data *in_padata,
1095
krb5_error *err_reply,
1096
krb5_prompter_fct prompter,
1097
void *prompter_data,
1098
preauth_get_as_key_proc gak_fct,
1101
krb5_data *s2kparams,
1102
krb5_keyblock *as_key,
1113
krb5_pa_data *in_padata, krb5_error *err_reply,
1114
krb5_prompter_fct prompter, void *prompter_data,
1103
1115
krb5_pa_data ***out_padata)
1105
1117
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1106
pkinit_context plgctx = (pkinit_context)plugin_context;
1107
pkinit_req_context reqctx = (pkinit_req_context)request_context;
1118
pkinit_context plgctx = (pkinit_context)moddata;
1119
pkinit_req_context reqctx = (pkinit_req_context)modreq;
1108
1120
krb5_typed_data **typed_data = NULL;
1109
1121
krb5_data scratch;
1110
1122
krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
1190
1202
pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
1204
if (patype == KRB5_PADATA_PKINIT_KX)
1205
return PA_INFO|PA_PSEUDO;
1192
1206
return PA_REAL;
1210
* We want to be notified about KRB5_PADATA_PKINIT_KX in addition to the actual
1211
* pkinit patypes because RFC 6112 requires anonymous KDCs to send it. We use
1212
* that to determine whether to use the broken MIT 1.9 behavior of sending
1213
* ContentInfo rather than SignedData or the RFC 6112 behavior
1195
1215
static krb5_preauthtype supported_client_pa_types[] = {
1196
1216
KRB5_PADATA_PK_AS_REP,
1197
1217
KRB5_PADATA_PK_AS_REQ,
1198
1218
KRB5_PADATA_PK_AS_REP_OLD,
1199
1219
KRB5_PADATA_PK_AS_REQ_OLD,
1220
KRB5_PADATA_PKINIT_KX,
1204
1225
pkinit_client_req_init(krb5_context context,
1205
void *plugin_context,
1206
void **request_context)
1226
krb5_clpreauth_moddata moddata,
1227
krb5_clpreauth_modreq *modreq_out)
1208
1229
krb5_error_code retval = ENOMEM;
1209
1230
pkinit_req_context reqctx = NULL;
1210
pkinit_context plgctx = plugin_context;
1231
pkinit_context plgctx = (pkinit_context)moddata;
1212
*request_context = NULL;
1214
1235
reqctx = malloc(sizeof(*reqctx));
1215
1236
if (reqctx == NULL)
1267
pkinit_client_req_fini(krb5_context context,
1268
void *plugin_context,
1269
void *request_context)
1288
pkinit_client_req_fini(krb5_context context, krb5_clpreauth_moddata moddata,
1289
krb5_clpreauth_modreq modreq)
1271
pkinit_req_context reqctx = request_context;
1291
pkinit_req_context reqctx = (pkinit_req_context)modreq;
1273
1293
pkiDebug("%s: received reqctx at %p\n", __FUNCTION__, reqctx);
1274
1294
if (reqctx == NULL)
1349
*moddata_out = (krb5_clpreauth_moddata)ctx;
1330
1351
pkiDebug("%s: returning plgctx at %p\n", __FUNCTION__, ctx);
1334
pkinit_client_plugin_fini(context, ctx);
1355
pkinit_client_plugin_fini(context, (krb5_clpreauth_moddata)ctx);
1340
pkinit_client_plugin_fini(krb5_context context, void *blob)
1361
pkinit_client_plugin_fini(krb5_context context, krb5_clpreauth_moddata moddata)
1342
pkinit_context ctx = blob;
1363
pkinit_context ctx = (pkinit_context)moddata;
1344
1365
if (ctx == NULL || ctx->magic != PKINIT_CTX_MAGIC) {
1345
1366
pkiDebug("pkinit_lib_fini: got bad plgctx (%p)!\n", ctx);
1427
1448
static krb5_error_code
1428
pkinit_client_gic_opt(krb5_context context,
1429
void *plugin_context,
1449
pkinit_client_gic_opt(krb5_context context, krb5_clpreauth_moddata moddata,
1430
1450
krb5_get_init_creds_opt *gic_opt,
1431
1451
const char *attr,
1432
1452
const char *value)
1434
1454
krb5_error_code retval;
1435
pkinit_context plgctx = plugin_context;
1455
pkinit_context plgctx = (pkinit_context)moddata;
1437
1457
pkiDebug("(pkinit) received '%s' = '%s'\n", attr, value);
1438
1458
retval = handle_gic_opt(context, plgctx, attr, value);
1445
/* Only necessary for static plugin linking support. */
1446
#include "k5-plugin.h"
1448
struct krb5plugin_preauth_client_ftable_v1
1449
PLUGIN_SYMBOL_NAME(krb5_preauth, preauthentication_client_1) = {
1450
"pkinit", /* name */
1451
supported_client_pa_types, /* pa_type_list */
1452
NULL, /* enctype_list */
1453
pkinit_client_plugin_init, /* (*init) */
1454
pkinit_client_plugin_fini, /* (*fini) */
1455
pkinit_client_get_flags, /* (*flags) */
1456
pkinit_client_req_init, /* (*client_req_init) */
1457
pkinit_client_req_fini, /* (*client_req_fini) */
1458
pkinit_client_process, /* (*process) */
1459
pkinit_client_tryagain, /* (*tryagain) */
1460
pkinit_client_gic_opt /* (*gic_opt) */
1466
clpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
1467
krb5_plugin_vtable vtable);
1470
clpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
1471
krb5_plugin_vtable vtable)
1473
krb5_clpreauth_vtable vt;
1476
return KRB5_PLUGIN_VER_NOTSUPP;
1477
vt = (krb5_clpreauth_vtable)vtable;
1478
vt->name = "pkinit";
1479
vt->pa_type_list = supported_client_pa_types;
1480
vt->init = pkinit_client_plugin_init;
1481
vt->fini = pkinit_client_plugin_fini;
1482
vt->flags = pkinit_client_get_flags;
1483
vt->request_init = pkinit_client_req_init;
1484
vt->request_fini = pkinit_client_req_fini;
1485
vt->process = pkinit_client_process;
1486
vt->tryagain = pkinit_client_tryagain;
1487
vt->gic_opts = pkinit_client_gic_opt;