int decode_EtypeList(const unsigned char *p, size_t len, EtypeList *data, size_t *size) { size_t ret = 0, reallen; size_t l; int e; memset(data, 0, sizeof(*data)); reallen = 0; e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,&reallen, &l); FORW; if(len < reallen) return ASN1_OVERRUN; len = reallen; { size_t origlen = len; int oldret = ret; ret = 0; (data)->len = 0; (data)->val = NULL; while(ret < origlen) { (data)->len++; (data)->val = realloc((data)->val, sizeof(*((data)->val)) * (data)->len); e = decode_integer(p, len, &(data)->val[(data)->len-1], &l); FORW; len = origlen - ret; } ret += oldret; } if(size) *size = ret; return 0; fail: free_EtypeList(data); return e; }
static krb5_error_code make_etypelist(krb5_context context, krb5_authdata **auth_data) { EtypeList etypes; krb5_error_code ret; krb5_authdata ad; u_char *buf; size_t len = 0; size_t buf_size; ret = _krb5_init_etype(context, KRB5_PDU_NONE, &etypes.len, &etypes.val, NULL); if (ret) return ret; ASN1_MALLOC_ENCODE(EtypeList, buf, buf_size, &etypes, &len, ret); if (ret) { free_EtypeList(&etypes); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); free_EtypeList(&etypes); ALLOC_SEQ(&ad, 1); if (ad.val == NULL) { free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ad.val[0].ad_type = KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION; ad.val[0].ad_data.length = len; ad.val[0].ad_data.data = buf; ASN1_MALLOC_ENCODE(AD_IF_RELEVANT, buf, buf_size, &ad, &len, ret); if (ret) { free_AuthorizationData(&ad); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); free_AuthorizationData(&ad); ALLOC(*auth_data, 1); if (*auth_data == NULL) { free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ALLOC_SEQ(*auth_data, 1); if ((*auth_data)->val == NULL) { free(*auth_data); free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } (*auth_data)->val[0].ad_type = KRB5_AUTHDATA_IF_RELEVANT; (*auth_data)->val[0].ad_data.length = len; (*auth_data)->val[0].ad_data.data = buf; return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_verify_ap_req2(krb5_context context, krb5_auth_context *auth_context, krb5_ap_req *ap_req, krb5_const_principal server, krb5_keyblock *keyblock, krb5_flags flags, krb5_flags *ap_req_options, krb5_ticket **ticket, krb5_key_usage usage) { krb5_ticket *t; krb5_auth_context ac; krb5_error_code ret; EtypeList etypes; memset(&etypes, 0, sizeof(etypes)); if(ticket) *ticket = NULL; if (auth_context && *auth_context) { ac = *auth_context; } else { ret = krb5_auth_con_init(context, &ac); if (ret) return ret; } t = calloc(1, sizeof(*t)); if (t == NULL) { ret = ENOMEM; krb5_clear_error_message(context); goto out; } if (ap_req->ap_options.use_session_key && ac->keyblock){ ret = krb5_decrypt_ticket(context, &ap_req->ticket, ac->keyblock, &t->ticket, flags); krb5_free_keyblock(context, ac->keyblock); ac->keyblock = NULL; }else ret = krb5_decrypt_ticket(context, &ap_req->ticket, keyblock, &t->ticket, flags); if(ret) goto out; ret = _krb5_principalname2krb5_principal(context, &t->server, ap_req->ticket.sname, ap_req->ticket.realm); if (ret) goto out; ret = _krb5_principalname2krb5_principal(context, &t->client, t->ticket.cname, t->ticket.crealm); if (ret) goto out; ret = decrypt_authenticator(context, &t->ticket.key, &ap_req->authenticator, ac->authenticator, usage); if (ret) goto out; { krb5_principal p1, p2; krb5_boolean res; _krb5_principalname2krb5_principal(context, &p1, ac->authenticator->cname, ac->authenticator->crealm); _krb5_principalname2krb5_principal(context, &p2, t->ticket.cname, t->ticket.crealm); res = krb5_principal_compare(context, p1, p2); krb5_free_principal(context, p1); krb5_free_principal(context, p2); if (!res) { ret = KRB5KRB_AP_ERR_BADMATCH; krb5_clear_error_message(context); goto out; } } /* check addresses */ if (t->ticket.caddr && ac->remote_address && !krb5_address_search(context, ac->remote_address, t->ticket.caddr)) { ret = KRB5KRB_AP_ERR_BADADDR; krb5_clear_error_message(context); goto out; } /* check timestamp in authenticator */ { krb5_timestamp now; krb5_timeofday(context, &now); if (krb5_time_abs(ac->authenticator->ctime, now) > context->max_skew) { ret = KRB5KRB_AP_ERR_SKEW; krb5_clear_error_message(context); goto out; } } if (ac->authenticator->seq_number) krb5_auth_con_setremoteseqnumber(context, ac, *ac->authenticator->seq_number); /* XXX - Xor sequence numbers */ if (ac->authenticator->subkey) { ret = krb5_auth_con_setremotesubkey(context, ac, ac->authenticator->subkey); if (ret) goto out; } ret = find_etypelist(context, ac, &etypes); if (ret) goto out; ac->keytype = (krb5_keytype)ETYPE_NULL; if (etypes.val) { size_t i; for (i = 0; i < etypes.len; i++) { if (krb5_enctype_valid(context, etypes.val[i]) == 0) { ac->keytype = etypes.val[i]; break; } } } /* save key */ ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock); if (ret) goto out; if (ap_req_options) { *ap_req_options = 0; if (ac->keytype != ETYPE_NULL) *ap_req_options |= AP_OPTS_USE_SUBKEY; if (ap_req->ap_options.use_session_key) *ap_req_options |= AP_OPTS_USE_SESSION_KEY; if (ap_req->ap_options.mutual_required) *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; } if(ticket) *ticket = t; else krb5_free_ticket(context, t); if (auth_context) { if (*auth_context == NULL) *auth_context = ac; } else krb5_auth_con_free(context, ac); free_EtypeList(&etypes); return 0; out: free_EtypeList(&etypes); if (t) krb5_free_ticket(context, t); if (auth_context == NULL || *auth_context == NULL) krb5_auth_con_free(context, ac); return ret; }