-$Id$
Heimdal is a Kerberos 5 implementation.
s/^\s*//;
s/\s*$//;
s/\s+/ /g;
- if($_ =~ /\)$/){
+ if($_ =~ /\)$/ or $_ =~ /DEPRECATED$/){
if(!/^static/ && !/^PRIVATE/){
- if(/(.*)(__attribute__\s?\(.*\))/) {
- $attr = $2;
+ $attr = "";
+ if(m/(.*)(__attribute__\s?\(.*\))/) {
+ $attr .= " $2";
+ $_ = $1;
+ }
+ if(m/(.*)\s(\w+DEPRECATED)/) {
+ $attr .= " $2";
$_ = $1;
- } else {
- $attr = "";
}
# remove outer ()
s/\s*\(/</;
AC_DEFUN([rk_RESOLV],[
-AC_CHECK_HEADERS([arpa/nameser.h])
+AC_CHECK_HEADERS([arpa/nameser.h dns.h])
AC_CHECK_HEADERS(resolv.h, , , [AC_INCLUDES_DEFAULT
#ifdef HAVE_SYS_TYPES_H
],
[0])
+AC_FIND_FUNC_NO_LIBS(dns_search,,
+[
+#ifdef HAVE_DNS_H
+#include <dns.h>
+#endif
+],
+[0,0,0,0,0,0,0,0])
+
+
AC_FIND_FUNC(dn_expand, resolv,
[
#include <stdio.h>
krb5_storage *sp;
char *spn = NULL;
unsigned char buf[MAX_KTXT_LEN + 4 * 4];
- size_t len;
int kvno = 0;
if(!config->enable_524) {
"Failed to decrypt ticket from %s for %s", from, spn);
goto out;
}
- ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length,
- &et, &len);
+ ret = decode_EncTicketPart(et_data.data, et_data.length, &et, NULL);
krb5_data_free(&et_data);
if(ret){
kdc_log(context, config, 0,
krb5_config_get_bool_default(context, NULL,
c->enable_v4,
"kdc", "enable-524", NULL);
+#ifdef DIGEST
c->enable_digest =
krb5_config_get_bool_default(context, NULL,
FALSE,
c->enable_digest = 0;
}
}
+#endif
+#ifdef KX509
c->enable_kx509 =
krb5_config_get_bool_default(context, NULL,
FALSE,
c->enable_kx509 = FALSE;
}
}
+#endif
c->check_ticket_addresses =
krb5_config_get_bool_default(context, NULL,
"enable-pkinit",
NULL);
if (c->enable_pkinit) {
- const char *user_id, *anchors, *ocsp_file;
+ const char *user_id, *anchors, *file;
char **pool_list, **revoke_list;
user_id =
krb5_config_get_strings(context, NULL,
"kdc", "pkinit_revoke", NULL);
- ocsp_file =
- krb5_config_get_string(context, NULL,
- "kdc", "pkinit_kdc_ocsp", NULL);
- if (ocsp_file) {
- c->pkinit_kdc_ocsp_file = strdup(ocsp_file);
+ file = krb5_config_get_string(context, NULL,
+ "kdc", "pkinit_kdc_ocsp", NULL);
+ if (file) {
+ c->pkinit_kdc_ocsp_file = strdup(file);
if (c->pkinit_kdc_ocsp_file == NULL)
krb5_errx(context, 1, "out of memory");
}
+ file = krb5_config_get_string(context, NULL,
+ "kdc", "pkinit_kdc_friendly_name", NULL);
+ if (file) {
+ c->pkinit_kdc_friendly_name = strdup(file);
+ if (c->pkinit_kdc_friendly_name == NULL)
+ krb5_errx(context, 1, "out of memory");
+ }
+
+
_kdc_pk_initialize(context, c, user_id, anchors,
pool_list, revoke_list);
#include "kdc_locl.h"
#include <hex.h>
-RCSID("$Id$");
+#ifdef DIGEST
#define MS_CHAP_V2 0x20
#define CHAP_MD5 0x10
krb5_error_code
_kdc_do_digest(krb5_context context,
krb5_kdc_configuration *config,
- const DigestREQ *req, krb5_data *reply,
+ const struct DigestREQ *req, krb5_data *reply,
const char *from, struct sockaddr *addr)
{
krb5_error_code ret = 0;
memset(&ireq, 0, sizeof(ireq));
memset(&r, 0, sizeof(r));
memset(&rep, 0, sizeof(rep));
+ memset(&res, 0, sizeof(res));
kdc_log(context, config, 0, "Digest request from %s", from);
hex_encode(buf.data, buf.length, &r.u.initReply.opaque);
free(buf.data);
+ krb5_data_zero(&buf);
if (r.u.initReply.opaque == NULL) {
krb5_clear_error_message(context);
ret = ENOMEM;
ret = decode_Checksum(buf.data, buf.length, &res, NULL);
free(buf.data);
+ krb5_data_zero(&buf);
if (ret) {
- krb5_set_error_message(context, ret, "Failed to decode digest Checksum");
+ krb5_set_error_message(context, ret,
+ "Failed to decode digest Checksum");
goto out;
}
ret = krb5_verify_checksum(context, crypto,
KRB5_KU_DIGEST_OPAQUE,
buf.data, buf.length, &res);
+ free_Checksum(&res);
+ krb5_data_free(&buf);
krb5_crypto_destroy(context, crypto);
crypto = NULL;
if (ret)
krb5_set_error_message(context, ret, "NTLM storage read flags");
goto out;
}
+ krb5_storage_free(sp);
+ sp = NULL;
krb5_data_free(&buf);
if ((flags & NTLM_NEG_NTLM) == 0) {
free (client_name);
krb5_data_free(&buf);
krb5_data_free(&serverNonce);
+ free_Checksum(&res);
free_DigestREP(&rep);
free_DigestRepInner(&r);
free_DigestReqInner(&ireq);
return ret;
}
+
+#endif /* DIGEST */
#include <parse_units.h>
#include <krb5.h>
#include <krb5_locl.h>
+#ifdef DIGEST
#include <digest_asn1.h>
+#endif
+#ifdef KX509
#include <kx509_asn1.h>
+#endif
#include <hdb.h>
#include <hdb_err.h>
#include <der.h>
+#ifndef NO_NTLM
#include <heimntlm.h>
+#endif
#include <windc_plugin.h>
#undef ALLOC
#include "kdc_locl.h"
-RCSID("$Id$");
+#ifdef KRB4
#include <krb5-v4compat.h>
#include <rx.h>
krb5_storage_free (sp);
return ret;
}
+
+#endif /* KRB4 */
krb5_boolean enable_pkinit;
krb5_boolean pkinit_princ_in_cert;
char *pkinit_kdc_ocsp_file;
+ char *pkinit_kdc_friendly_name;
int pkinit_dh_min_bits;
int pkinit_require_binding;
} krb5_kdc_configuration;
+struct krb5_kdc_service {
+ unsigned int flags;
+#define KS_KRB5 1
+#define KS_NO_LENGTH 2
+ krb5_error_code (*process)(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim);
+};
+
#include <kdc-protos.h>
#endif
#include "kdc.h"
typedef struct pk_client_params pk_client_params;
+struct DigestREQ;
+struct Kx509Request;
#include <kdc-private.h>
extern sig_atomic_t exit_flag;
extern int enable_http;
+#ifdef SUPPORT_DETACH
+
#define DETACH_IS_DEFAULT FALSE
extern int detach_from_console;
+#endif
extern const struct units _kdc_digestunits[];
#include "kdc_locl.h"
-#include <krb5-v4compat.h>
+#ifdef KRB4
-RCSID("$Id$");
+#include <krb5-v4compat.h>
#ifndef swap32
static uint32_t
return 0;
}
+#endif /* KRB4 */
}
}
-static int
-only_older_enctype_p(const KDC_REQ *req)
-{
- int i;
-
- for(i = 0; i < req->req_body.etype.len; i++) {
- if (!older_enctype(req->req_body.etype.val[i]))
- return 0;
- }
- return 1;
-}
-
/*
*
*/
static krb5_error_code
get_pa_etype_info(krb5_context context,
krb5_kdc_configuration *config,
- METHOD_DATA *md, hdb_entry *client,
- ENCTYPE *etypes, unsigned int etypes_len)
+ METHOD_DATA *md, Key *ckey)
{
krb5_error_code ret = 0;
- int i, j;
- unsigned int n = 0;
ETYPE_INFO pa;
unsigned char *buf;
size_t len;
- pa.len = client->keys.len;
- if(pa.len > UINT_MAX/sizeof(*pa.val))
- return ERANGE;
- pa.val = malloc(pa.len * sizeof(*pa.val));
+ pa.len = 1;
+ pa.val = calloc(1, sizeof(pa.val[0]));
if(pa.val == NULL)
return ENOMEM;
- memset(pa.val, 0, pa.len * sizeof(*pa.val));
-
- for(i = 0; i < client->keys.len; i++) {
- for (j = 0; j < n; j++)
- if (pa.val[j].etype == client->keys.val[i].key.keytype)
- goto skip1;
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j]) {
- if (krb5_enctype_valid(context, etypes[j]) != 0)
- continue;
- if (!older_enctype(etypes[j]))
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info_entry(context,
- &pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO(&pa);
- return ret;
- }
- break;
- }
- }
- skip1:;
- }
- for(i = 0; i < client->keys.len; i++) {
- /* already added? */
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j])
- goto skip2;
- }
- if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
- continue;
- if (!older_enctype(etypes[j]))
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info_entry(context,
- &pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO(&pa);
- return ret;
- }
- skip2:;
- }
- if(n < pa.len) {
- /* stripped out dups, newer enctypes, and not valid enctypes */
- pa.len = n;
+ ret = make_etype_info_entry(context, &pa.val[0], ckey);
+ if (ret) {
+ free_ETYPE_INFO(&pa);
+ return ret;
}
ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
static krb5_error_code
get_pa_etype_info2(krb5_context context,
krb5_kdc_configuration *config,
- METHOD_DATA *md, hdb_entry *client,
- ENCTYPE *etypes, unsigned int etypes_len)
+ METHOD_DATA *md, Key *ckey)
{
krb5_error_code ret = 0;
- int i, j;
- unsigned int n = 0;
ETYPE_INFO2 pa;
unsigned char *buf;
size_t len;
- pa.len = client->keys.len;
- if(pa.len > UINT_MAX/sizeof(*pa.val))
- return ERANGE;
- pa.val = malloc(pa.len * sizeof(*pa.val));
+ pa.len = 1;
+ pa.val = calloc(1, sizeof(pa.val[0]));
if(pa.val == NULL)
return ENOMEM;
- memset(pa.val, 0, pa.len * sizeof(*pa.val));
-
- for(i = 0; i < client->keys.len; i++) {
- for (j = 0; j < n; j++)
- if (pa.val[j].etype == client->keys.val[i].key.keytype)
- goto skip1;
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j]) {
- if (krb5_enctype_valid(context, etypes[j]) != 0)
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info2_entry(&pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO2(&pa);
- return ret;
- }
- break;
- }
- }
- skip1:;
- }
- /* send enctypes that the client doesn't know about too */
- for(i = 0; i < client->keys.len; i++) {
- /* already added? */
- for(j = 0; j < etypes_len; j++) {
- if(client->keys.val[i].key.keytype == etypes[j])
- goto skip2;
- }
- if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
- continue;
- if (n >= pa.len)
- krb5_abortx(context, "internal error: n >= p.len");
- if((ret = make_etype_info2_entry(&pa.val[n++],
- &client->keys.val[i])) != 0) {
- free_ETYPE_INFO2(&pa);
- return ret;
- }
- skip2:;
- }
- if(n < pa.len) {
- /* stripped out dups, and not valid enctypes */
- pa.len = n;
+ ret = make_etype_info2_entry(&pa.val[0], ckey);
+ if (ret) {
+ free_ETYPE_INFO2(&pa);
+ return ret;
}
ASN1_MALLOC_ENCODE(ETYPE_INFO2, buf, len, &pa, &len, ret);
const KDC_REQ_BODY *b)
{
krb5_error_code ret;
- struct rk_strpool *p = NULL;
+ struct rk_strpool *p;
char *str;
int i;
+ p = rk_strpoolprintf(NULL, "%s", "Client supported enctypes: ");
+
for (i = 0; i < b->etype.len; i++) {
ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
if (ret == 0) {
if (p == NULL)
p = rk_strpoolprintf(p, "no encryption types");
- str = rk_strpoolcollect(p);
- kdc_log(context, config, 0, "Client supported enctypes: %s", str);
- free(str);
-
{
char *cet;
char *set;
if(ret == 0) {
ret = krb5_enctype_to_string(context, setype, &set);
if (ret == 0) {
- kdc_log(context, config, 5, "Using %s/%s", cet, set);
+ p = rk_strpoolprintf(p, ", using %s/%s", cet, set);
free(set);
}
free(cet);
}
if (ret != 0)
- kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
+ p = rk_strpoolprintf(p, ", using enctypes %d/%d",
+ cetype, setype);
}
+ str = rk_strpoolcollect(p);
+ kdc_log(context, config, 0, "%s", str);
+ free(str);
+
{
char fixedstr[128];
unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(),
fixedstr, sizeof(fixedstr));
if(*fixedstr)
- kdc_log(context, config, 2, "Requested flags: %s", fixedstr);
+ kdc_log(context, config, 0, "Requested flags: %s", fixedstr);
}
}
return TRUE;
}
+krb5_boolean
+_kdc_is_anonymous(krb5_context context, krb5_principal principal)
+{
+ if (principal->name.name_type != KRB5_NT_WELLKNOWN ||
+ principal->name.name_string.len != 2 ||
+ strcmp(principal->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 ||
+ strcmp(principal->name.name_string.val[1], KRB5_ANON_NAME) != 0)
+ return 0;
+ return 1;
+}
+
/*
*
*/
if (ret)
goto out;
}
+
ret = krb5_unparse_name(context, client_princ, &client_name);
}
if (ret) {
kdc_log(context, config, 0, "AS-REQ %s from %s for %s",
client_name, from, server_name);
+ /*
+ *
+ */
+
+ if (_kdc_is_anonymous(context, client_princ)) {
+ if (!b->kdc_options.request_anonymous) {
+ kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag");
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ goto out;
+ }
+ } else if (b->kdc_options.request_anonymous) {
+ kdc_log(context, config, 0,
+ "Request for a anonymous ticket with non "
+ "anonymous client name: %s", client_name);
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ goto out;
+ }
+
+ /*
+ *
+ */
+
ret = _kdc_db_fetch(context, config, client_princ,
HDB_F_GET_CLIENT | flags, NULL, &client);
if(ret){
goto out;
}
- ret = _kdc_windc_client_access(context, client, req, &e_data);
- if(ret)
- goto out;
+ memset(&et, 0, sizeof(et));
+ memset(&ek, 0, sizeof(ek));
- ret = _kdc_check_flags(context, config,
- client, client_name,
- server, server_name,
- TRUE);
- if(ret)
+ /*
+ * Find the client key for reply encryption and pa-type salt, Pick
+ * the client key upfront before the other keys because that is
+ * going to affect what enctypes we are going to use in
+ * ETYPE-INFO{,2}.
+ */
+
+ ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len,
+ &ckey, &cetype);
+ if (ret) {
+ kdc_log(context, config, 0,
+ "Client (%s) has no support for etypes", client_name);
goto out;
+ }
- memset(&et, 0, sizeof(et));
- memset(&ek, 0, sizeof(ek));
+ /*
+ * Pre-auth processing
+ */
if(req->padata){
int i;
e_text = "PKINIT certificate not allowed to "
"impersonate principal";
_kdc_pk_free_client_param(context, pkp);
-
+
kdc_log(context, config, 0, "%s", e_text);
pkp = NULL;
goto out;
}
+
found_pa = 1;
et.flags.pre_authent = 1;
kdc_log(context, config, 0,
found_pa = 1;
+ if (b->kdc_options.request_anonymous) {
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ kdc_log(context, config, 0, "ENC-TS doesn't support anon");
+ goto out;
+ }
+
ret = decode_EncryptedData(pa->padata_value.data,
pa->padata_value.length,
&enc_data,
goto out;
}
}else if (config->require_preauth
+ || b->kdc_options.request_anonymous /* hack to force anon */
|| client->entry.flags.require_preauth
|| server->entry.flags.require_preauth) {
METHOD_DATA method_data;
* both info replies (we send 'info' first in the list).
* - If the client is 'modern', because it knows about 'new'
* enctype types, then only send the 'info2' reply.
+ *
+ * Before we send the full list of etype-info data, we pick
+ * the client key we would have used anyway below, just pick
+ * that instead.
*/
- /* XXX check ret */
- if (only_older_enctype_p(req))
+ if (older_enctype(ckey->key.keytype)) {
ret = get_pa_etype_info(context, config,
- &method_data, &client->entry,
- b->etype.val, b->etype.len);
- /* XXX check ret */
- ret = get_pa_etype_info2(context, config, &method_data,
- &client->entry, b->etype.val, b->etype.len);
-
+ &method_data, ckey);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
+ }
+ ret = get_pa_etype_info2(context, config,
+ &method_data, ckey);
+ if (ret) {
+ free_METHOD_DATA(&method_data);
+ goto out;
+ }
ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
free_METHOD_DATA(&method_data);
}
/*
- * Find the client key (for preauth ENC-TS verification and reply
- * encryption). Then the best encryption type for the KDC and
- * last the best session key that shared between the client and
- * KDC runtime enctypes.
+ * Verify flags after the user been required to prove its identity
+ * with in a preauth mech.
*/
- ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len,
- &ckey, &cetype);
- if (ret) {
- kdc_log(context, config, 0,
- "Client (%s) has no support for etypes", client_name);
+ ret = _kdc_check_flags(context, config,
+ client, client_name,
+ server, server_name,
+ TRUE);
+ if(ret)
goto out;
- }
-
+
+ ret = _kdc_windc_client_access(context, client, req, &e_data);
+ if(ret)
+ goto out;
+
+ /*
+ * Selelct the best encryption type for the KDC with out regard to
+ * the client since the client never needs to read that data.
+ */
+
ret = _kdc_get_preferred_key(context, config,
server, server_name,
&setype, &skey);
rep.pvno = 5;
rep.msg_type = krb_as_rep;
- copy_Realm(&client->entry.principal->realm, &rep.crealm);
- if (f.request_anonymous)
- _kdc_make_anonymous_principalname (&rep.cname);
- else
- _krb5_principal2principalname(&rep.cname,
- client->entry.principal);
+
+ ret = copy_Realm(&client->entry.principal->realm, &rep.crealm);
+ if (ret)
+ goto out;
+ ret = _krb5_principal2principalname(&rep.cname, client->entry.principal);
+ if (ret)
+ goto out;
+
rep.ticket.tkt_vno = 5;
copy_Realm(&server->entry.principal->realm, &rep.ticket.realm);
_krb5_principal2principalname(&rep.ticket.sname,
goto out;
}
- ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
+ ret = copy_PrincipalName(&rep.cname, &et.cname);
+ if (ret)
+ goto out;
+ ret = copy_Realm(&rep.crealm, &et.crealm);
if (ret)
goto out;
- copy_PrincipalName(&rep.cname, &et.cname);
- copy_Realm(&rep.crealm, &et.crealm);
{
time_t start;
et.transited.tr_type = DOMAIN_X500_COMPRESS;
krb5_data_zero(&et.transited.contents);
- copy_EncryptionKey(&et.key, &ek.key);
-
/* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
* as 0 and as 0x80 (meaning indefinite length) apart, and is thus
* incapable of correctly decoding SEQUENCE OF's of zero length.
reply_key = &ckey->key;
#if PKINIT
if (pkp) {
+ e_text = "Failed to build PK-INIT reply";
ret = _kdc_pk_mk_pa_reply(context, config, pkp, client,
- req, req_buffer,
- &reply_key, rep.padata);
+ sessionetype, req, req_buffer,
+ &reply_key, &et.key, rep.padata);
if (ret)
goto out;
ret = _kdc_add_inital_verified_cas(context,
config,
pkp,
&et);
- if (ret)
- goto out;
- }
+ } else
+#else
+ ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
#endif
+ if (ret)
+ goto out;
+
+ ret = copy_EncryptionKey(&et.key, &ek.key);
+ if (ret)
+ goto out;
set_salt_padata (rep.padata, ckey->salt);
hdb_entry_ex *krbtgt,
krb5_enctype enctype,
krb5_const_principal server,
- KRB5SignedPathPrincipals *principals,
+ krb5_principals principals,
EncTicketPart *tkt)
{
krb5_error_code ret;
size_t size;
if (server && principals) {
- ret = add_KRB5SignedPathPrincipals(principals, server);
+ ret = add_Principals(principals, server);
if (ret)
return ret;
}
krb5_kdc_configuration *config,
hdb_entry_ex *krbtgt,
EncTicketPart *tkt,
- KRB5SignedPathPrincipals **delegated,
+ krb5_principals *delegated,
int *signedpath)
{
krb5_error_code ret;
return ENOMEM;
}
- ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated);
+ ret = copy_Principals(*delegated, sp.delegated);
if (ret) {
free_KRB5SignedPath(&sp);
free(*delegated);
krb5_principal client_principal,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
- KRB5SignedPathPrincipals *spp,
+ krb5_principals spp,
const krb5_data *rspac,
const METHOD_DATA *enc_pa_data,
const char **e_text,
krb5_keyblock *subkey;
krb5_data ad;
- ret = krb5_auth_con_getremotesubkey(context,
- ac,
- &subkey);
+ ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
if(ret){
krb5_auth_con_free(context, ac);
kdc_log(context, config, 0, "Failed to get remote subkey: %s",
goto out;
}
ret = krb5_crypto_init(context, subkey, 0, &crypto);
+ krb5_free_keyblock(context, subkey);
if (ret) {
krb5_auth_con_free(context, ac);
kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
goto out;
}
- krb5_free_keyblock(context, subkey);
ALLOC(*auth_data);
if (*auth_data == NULL) {
krb5_auth_con_free(context, ac);
hdb_entry_ex *server = NULL, *client = NULL;
krb5_realm ref_realm = NULL;
EncTicketPart *tgt = &ticket->ticket;
- KRB5SignedPathPrincipals *spp = NULL;
- Key *tkey;
+ krb5_principals spp = NULL;
const EncryptionKey *ekey;
krb5_keyblock sessionkey;
krb5_kvno kvno;
krb5_data rspac;
- int cross_realm = 0;
METHOD_DATA enc_pa_data;
char opt_str[128];
int signedpath = 0;
+ Key *tkey;
+
memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
krb5_data_zero(&rspac);
kdc_log(context, config, 1, "Client not found in database: %s: %s",
cpn, krb5_get_err_text(context, ret));
-
- cross_realm = 1;
}
/*
break;
if(i == b->etype.len) {
kdc_log(context, config, 0,
- "Addition ticket have not matching etypes", spp);
+ "Addition ticket have not matching etypes");
krb5_clear_error_message(context);
- return KRB5KDC_ERR_ETYPE_NOSUPP;
+ ret = KRB5KDC_ERR_ETYPE_NOSUPP;
+ goto out;
}
etype = b->etype.val[i];
kvno = 0;
if(ret) {
kdc_log(context, config, 0,
"Server (%s) has no support for etypes", spn);
- return ret;
+ goto out;
}
ekey = &skey->key;
kvno = server->entry.kvno;
goto out;
}
- /*
- * Validate authoriation data
- */
-
/*
* Check that service is in the same realm as the krbtgt. If it's
* not the same, it's someone that is using a uni-directional trust
goto out;
}
- /* check PAC if there is one */
+ /*
+ * Validate authoriation data
+ */
ret = hdb_enctype2key(context, &krbtgt->entry,
krbtgt_etype, &tkey);
if(ret) {
kdc_log(context, config, 0,
- "Failed to find key for krbtgt PAC check");
+ "Failed to find key for krbtgt PAC check");
goto out;
}
#include <rfc2459_asn1.h>
#include <hx509.h>
-RCSID("$Id$");
+#ifdef KX509
/*
*
*/
krb5_error_code
-_kdc_try_kx509_request(void *ptr, size_t len, Kx509Request *req, size_t *size)
+_kdc_try_kx509_request(void *ptr, size_t len, struct Kx509Request *req, size_t *size)
{
if (len < 4)
return -1;
krb5_keyblock *key,
Kx509Response *rep)
{
+ krb5_error_code ret;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
- HMAC_Init_ex(&ctx,
- key->keyvalue.data, key->keyvalue.length,
+ HMAC_Init_ex(&ctx, key->keyvalue.data, key->keyvalue.length,
EVP_sha1(), NULL);
- rep->hash->length = HMAC_size(&ctx);
- rep->hash->data = malloc(rep->hash->length);
- if (rep->hash->data == NULL) {
+ ret = krb5_data_alloc(rep->hash, HMAC_size(&ctx));
+ if (ret) {
HMAC_CTX_cleanup(&ctx);
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
krb5_error_code
_kdc_do_kx509(krb5_context context,
krb5_kdc_configuration *config,
- const Kx509Request *req, krb5_data *reply,
+ const struct Kx509Request *req, krb5_data *reply,
const char *from, struct sockaddr *addr)
{
krb5_error_code ret;
return 0;
}
+
+#endif /* KX509 */
struct pk_client_params {
enum krb5_pk_type type;
- BIGNUM *dh_public_key;
+ enum { USE_RSA, USE_DH, USE_ECDH } keyex;
+ union {
+ struct {
+ BIGNUM *public_key;
+ DH *key;
+ } dh;
+#ifdef HAVE_OPENSSL
+ struct {
+ EC_KEY *public_key;
+ EC_KEY *key;
+ } ecdh;
+#endif
+ } u;
hx509_cert cert;
unsigned nonce;
- DH *dh;
EncryptionKey reply_key;
char *dh_group_name;
hx509_peer_info peer;
_kdc_pk_free_client_param(krb5_context context,
pk_client_params *client_params)
{
+ if (client_params == NULL)
+ return;
if (client_params->cert)
hx509_cert_free(client_params->cert);
- if (client_params->dh)
- DH_free(client_params->dh);
- if (client_params->dh_public_key)
- BN_free(client_params->dh_public_key);
+ if (client_params->keyex == USE_DH) {
+ if (client_params->u.dh.key)
+ DH_free(client_params->u.dh.key);
+ if (client_params->u.dh.public_key)
+ BN_free(client_params->u.dh.public_key);
+ }
+#ifdef HAVE_OPENSSL
+ if (client_params->keyex == USE_ECDH) {
+ if (client_params->u.ecdh.key)
+ EC_KEY_free(client_params->u.ecdh.key);
+ if (client_params->u.ecdh.public_key)
+ EC_KEY_free(client_params->u.ecdh.public_key);
+ }
+#endif
krb5_free_keyblock_contents(context, &client_params->reply_key);
if (client_params->dh_group_name)
free(client_params->dh_group_name);
}
static krb5_error_code
-generate_dh_keyblock(krb5_context context, pk_client_params *client_params,
- krb5_enctype enctype, krb5_keyblock *reply_key)
+generate_dh_keyblock(krb5_context context,
+ pk_client_params *client_params,
+ krb5_enctype enctype)
{
unsigned char *dh_gen_key = NULL;
krb5_keyblock key;
memset(&key, 0, sizeof(key));
- if (!DH_generate_key(client_params->dh)) {
- ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "Can't generate Diffie-Hellman keys");
- goto out;
- }
- if (client_params->dh_public_key == NULL) {
- ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "dh_public_key");
- goto out;
- }
+ if (client_params->keyex == USE_DH) {
- dh_gen_keylen = DH_size(client_params->dh);
- size = BN_num_bytes(client_params->dh->p);
- if (size < dh_gen_keylen)
- size = dh_gen_keylen;
+ if (client_params->u.dh.public_key == NULL) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret, "public_key");
+ goto out;
+ }
- dh_gen_key = malloc(size);
- if (dh_gen_key == NULL) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, "malloc: out of memory");
- goto out;
- }
- memset(dh_gen_key, 0, size - dh_gen_keylen);
+ if (!DH_generate_key(client_params->u.dh.key)) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ "Can't generate Diffie-Hellman keys");
+ goto out;
+ }
+
+ dh_gen_keylen = DH_size(client_params->u.dh.key);
+ size = BN_num_bytes(client_params->u.dh.key->p);
+ if (size < dh_gen_keylen)
+ size = dh_gen_keylen;
+
+ dh_gen_key = malloc(size);
+ if (dh_gen_key == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, "malloc: out of memory");
+ goto out;
+ }
+ memset(dh_gen_key, 0, size - dh_gen_keylen);
+
+ dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
+ client_params->u.dh.public_key,
+ client_params->u.dh.key);
+ if (dh_gen_keylen == -1) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ "Can't compute Diffie-Hellman key");
+ goto out;
+ }
+ ret = 0;
+#ifdef HAVE_OPENSSL
+ } else if (client_params->keyex == USE_ECDH) {
+
+ if (client_params->u.ecdh.public_key == NULL) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret, "public_key");
+ goto out;
+ }
+
+ client_params->u.ecdh.key = EC_KEY_new();
+ if (client_params->u.ecdh.key == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ EC_KEY_set_group(client_params->u.ecdh.key,
+ EC_KEY_get0_group(client_params->u.ecdh.public_key));
- dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
- client_params->dh_public_key,
- client_params->dh);
- if (dh_gen_keylen == -1) {
+ if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8;
+ dh_gen_key = malloc(size);
+ if (dh_gen_key == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret,
+ N_("malloc: out of memory", ""));
+ goto out;
+ }
+
+ dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
+ EC_KEY_get0_public_key(client_params->u.ecdh.public_key),
+ client_params->u.ecdh.key, NULL);
+ ret = 0;
+#endif
+ } else {
ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "Can't compute Diffie-Hellman key");
+ krb5_set_error_message(context, ret,
+ "Diffie-Hellman not selected keys");
goto out;
}
enctype,
dh_gen_key, dh_gen_keylen,
NULL, NULL,
- reply_key);
+ &client_params->reply_key);
out:
if (dh_gen_key)
memset(&dhparam, 0, sizeof(dhparam));
- if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) {
- krb5_set_error_message(context, KRB5_BADMSGTYPE,
- "PKINIT invalid oid in clientPublicValue");
- return KRB5_BADMSGTYPE;
+ if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
+ ret = KRB5_BADMSGTYPE;
+ krb5_set_error_message(context, ret,
+ "PKINIT: subjectPublicKey not aligned "
+ "to 8 bit boundary");
+ goto out;
}
if (dh_key_info->algorithm.parameters == NULL) {
goto out;
}
- if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
- ret = KRB5_BADMSGTYPE;
- krb5_set_error_message(context, ret,
- "PKINIT: subjectPublicKey not aligned "
- "to 8 bit boundary");
- goto out;
- }
-
-
ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits,
&dhparam.p, &dhparam.g, &dhparam.q, moduli,
&client_params->dh_group_name);
return ret;
}
- client_params->dh_public_key = integer_to_BN(context,
- "subjectPublicKey",
- &glue);
+ client_params->u.dh.public_key = integer_to_BN(context,
+ "subjectPublicKey",
+ &glue);
der_free_heim_integer(&glue);
- if (client_params->dh_public_key == NULL) {
+ if (client_params->u.dh.public_key == NULL) {
ret = KRB5_BADMSGTYPE;
goto out;
}
}
- client_params->dh = dh;
+ client_params->u.dh.key = dh;
dh = NULL;
ret = 0;
return ret;
}
+#ifdef HAVE_OPENSSL
+static krb5_error_code
+get_ecdh_param(krb5_context context,
+ krb5_kdc_configuration *config,
+ SubjectPublicKeyInfo *dh_key_info,
+ pk_client_params *client_params)
+{
+ ECParameters ecp;
+ EC_KEY *public = NULL;
+ krb5_error_code ret;
+ const unsigned char *p;
+ size_t len;
+ int nid;
+
+ if (dh_key_info->algorithm.parameters == NULL) {
+ krb5_set_error_message(context, KRB5_BADMSGTYPE,
+ "PKINIT missing algorithm parameter "
+ "in clientPublicValue");
+ return KRB5_BADMSGTYPE;
+ }
+
+ memset(&ecp, 0, sizeof(ecp));
+
+ ret = decode_ECParameters(dh_key_info->algorithm.parameters->data,
+ dh_key_info->algorithm.parameters->length, &ecp, &len);
+ if (ret)
+ goto out;
+
+ if (ecp.element != choice_ECParameters_namedCurve) {
+ ret = KRB5_BADMSGTYPE;
+ goto out;
+ }
+
+ if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0)
+ nid = NID_X9_62_prime256v1;
+ else {
+ ret = KRB5_BADMSGTYPE;
+ goto out;
+ }
+
+ /* XXX verify group is ok */
+
+ public = EC_KEY_new_by_curve_name(nid);
+
+ p = dh_key_info->subjectPublicKey.data;
+ len = dh_key_info->subjectPublicKey.length / 8;
+ if (o2i_ECPublicKey(&public, &p, len) == NULL) {
+ ret = KRB5_BADMSGTYPE;
+ krb5_set_error_message(context, ret,
+ "PKINIT failed to decode ECDH key");
+ goto out;
+ }
+ client_params->u.ecdh.public_key = public;
+ public = NULL;
+
+ out:
+ if (public)
+ EC_KEY_free(public);
+ free_ECParameters(&ecp);
+ return ret;
+}
+#endif
+
krb5_error_code
_kdc_pk_rd_padata(krb5_context context,
krb5_kdc_configuration *config,
type = "PK-INIT-Win2k";
+ if (req->req_body.kdc_options.request_anonymous) {
+ ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
+ krb5_set_error_message(context, ret,
+ "Anon not supported in RSA mode");
+ goto out;
+ }
+
ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
pa->padata_value.length,
&r,
free_PA_PK_AS_REQ_Win2k(&r);
if (ret) {
krb5_set_error_message(context, ret,
- "Can't decode PK-AS-REQ: %d", ret);
+ "Can't unwrap ContentInfo(win): %d", ret);
goto out;
}
&r,
NULL);
if (ret) {
- krb5_set_error_message(context, ret, "Can't decode PK-AS-REQ: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't decode PK-AS-REQ: %d", ret);
goto out;
}
0, NULL,
&client_params->client_anchors);
if (ret) {
- krb5_set_error_message(context, ret, "Can't allocate client anchors: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't allocate client anchors: %d",
+ ret);
goto out;
}
}
ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
free_IssuerAndSerialNumber(&iasn);
- if (ret)
+ if (ret) {
+ hx509_query_free(kdc_identity->hx509ctx, q);
continue;
+ }
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
{
hx509_certs signer_certs;
+ int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */
+
+ if (req->req_body.kdc_options.request_anonymous)
+ flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
ret = hx509_cms_verify_signed(kdc_identity->hx509ctx,
kdc_identity->verify_ctx,
+ flags,
signed_content.data,
signed_content.length,
NULL,
goto out;
}
- ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs,
- &client_params->cert);
- hx509_certs_free(&signer_certs);
+ if (signer_certs) {
+ ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs,
+ &client_params->cert);
+ hx509_certs_free(&signer_certs);
+ }
if (ret)
goto out;
}
&ap,
NULL);
if (ret) {
- krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't decode AuthPack: %d", ret);
goto out;
}
if (ap.clientPublicValue) {
ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "DH not supported for windows");
+ krb5_set_error_message(context, ret,
+ "DH not supported for windows");
goto out;
}
free_AuthPack_Win2k(&ap);
&ap,
NULL);
if (ret) {
- krb5_set_error_message(context, ret, "can't decode AuthPack: %d", ret);
+ krb5_set_error_message(context, ret,
+ "Can't decode AuthPack: %d", ret);
free_AuthPack(&ap);
goto out;
}
+ if (req->req_body.kdc_options.request_anonymous &&
+ ap.clientPublicValue == NULL) {
+ free_AuthPack(&ap);
+ ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
+ krb5_set_error_message(context, ret,
+ "Anon not supported in RSA mode");
+ goto out;
+ }
+
ret = pk_check_pkauthenticator(context,
&ap.pkAuthenticator,
req);
client_params->nonce = ap.pkAuthenticator.nonce;
if (ap.clientPublicValue) {
- ret = get_dh_param(context, config,
- ap.clientPublicValue, client_params);
+ if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) {
+ client_params->keyex = USE_DH;
+ ret = get_dh_param(context, config,
+ ap.clientPublicValue, client_params);
+#ifdef HAVE_OPENSSL
+ } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
+ client_params->keyex = USE_ECDH;
+ ret = get_ecdh_param(context, config,
+ ap.clientPublicValue, client_params);
+#endif
+ } else {
+ ret = KRB5_BADMSGTYPE;
+ krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
+ }
if (ret) {
free_AuthPack(&ap);
goto out;
}
- }
+ } else
+ client_params->keyex = USE_RSA;
if (ap.supportedCMSTypes) {
ret = hx509_peer_info_alloc(kdc_identity->hx509ctx,
krb5_data_free(&eContent);
der_free_oid(&eContentType);
der_free_oid(&contentInfoOid);
- if (ret)
- _kdc_pk_free_client_param(context, client_params);
- else
+ if (ret) {
+ _kdc_pk_free_client_param(context, client_params);
+ } else
*ret_params = client_params;
return ret;
}
const KDC_REQ *req,
const krb5_data *req_buffer,
krb5_keyblock *reply_key,
- ContentInfo *content_info)
+ ContentInfo *content_info,
+ hx509_cert *kdc_cert)
{
const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL;
krb5_error_code ret;
krb5_data_zero(&buf);
krb5_data_zero(&signed_data);
+ *kdc_cert = NULL;
+
/*
* If the message client is a win2k-type but it send pa data
* 09-binding it expects a IETF (checksum) reply so there can be
goto out;
hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
- hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+ if (config->pkinit_kdc_friendly_name)
+ hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
client_params->client_anchors,
kdc_identity->certpool,
&signed_data);
- hx509_cert_free(cert);
+ *kdc_cert = cert;
}
krb5_data_free(&buf);
}
ret = hx509_cms_envelope_1(kdc_identity->hx509ctx,
- 0,
+ HX509_CMS_EV_NO_KU_CHECK,
client_params->cert,
signed_data.data, signed_data.length,
envelopedAlg,
oid_id_pkcs7_envelopedData(),
content_info);
out:
+ if (ret && *kdc_cert) {
+ hx509_cert_free(*kdc_cert);
+ *kdc_cert = NULL;
+ }
+
krb5_data_free(&buf);
krb5_data_free(&signed_data);
return ret;
static krb5_error_code
pk_mk_pa_reply_dh(krb5_context context,
- DH *kdc_dh,
+ krb5_kdc_configuration *config,
pk_client_params *client_params,
- krb5_keyblock *reply_key,
ContentInfo *content_info,
hx509_cert *kdc_cert)
{
ContentInfo contentinfo;
krb5_error_code ret;
size_t size;
- heim_integer i;
memset(&contentinfo, 0, sizeof(contentinfo));
memset(&dh_info, 0, sizeof(dh_info));
- krb5_data_zero(&buf);
krb5_data_zero(&signed_data);
+ krb5_data_zero(&buf);
*kdc_cert = NULL;
- ret = BN_to_integer(context, kdc_dh->pub_key, &i);
- if (ret)
- return ret;
+ if (client_params->keyex == USE_DH) {
+ DH *kdc_dh = client_params->u.dh.key;
+ heim_integer i;
- ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
- if (ret) {
- krb5_set_error_message(context, ret, "ASN.1 encoding of "
- "DHPublicKey failed (%d)", ret);
- return ret;
- }
- if (buf.length != size)
- krb5_abortx(context, "Internal ASN.1 encoder error");
-
- dh_info.subjectPublicKey.length = buf.length * 8;
- dh_info.subjectPublicKey.data = buf.data;
+ ret = BN_to_integer(context, kdc_dh->pub_key, &i);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
+ der_free_heim_integer(&i);
+ if (ret) {
+ krb5_set_error_message(context, ret, "ASN.1 encoding of "
+ "DHPublicKey failed (%d)", ret);
+ return ret;
+ }
+ if (buf.length != size)
+ krb5_abortx(context, "Internal ASN.1 encoder error");
+
+ dh_info.subjectPublicKey.length = buf.length * 8;
+ dh_info.subjectPublicKey.data = buf.data;
+ krb5_data_zero(&buf);
+ } else if (client_params->keyex == USE_ECDH) {
+#ifdef HAVE_OPENSSL
+ unsigned char *p;
+ int len;
+
+ len = i2o_ECPublicKey(client_params->u.ecdh.key, NULL);
+ if (len <= 0)
+ abort();
+
+ p = malloc(len);
+ if (p == NULL)
+ abort();
+
+ dh_info.subjectPublicKey.length = len * 8;
+ dh_info.subjectPublicKey.data = p;
+
+ len = i2o_ECPublicKey(client_params->u.ecdh.key, &p);
+ if (len <= 0)
+ abort();
+#else
+ return ENOMEM;
+#endif
+ } else
+ krb5_abortx(context, "no keyex selected ?");
+
dh_info.nonce = client_params->nonce;
ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
goto out;
hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
- hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+ if (config->pkinit_kdc_friendly_name)
+ hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
krb5_kdc_configuration *config,
pk_client_params *client_params,
const hdb_entry_ex *client,
+ krb5_enctype sessionetype,
const KDC_REQ *req,
const krb5_data *req_buffer,
krb5_keyblock **reply_key,
+ krb5_keyblock *sessionkey,
METHOD_DATA *md)
{
krb5_error_code ret;
pa_type = KRB5_PADATA_PK_AS_REP;
- if (client_params->dh == NULL) {
+ if (client_params->keyex == USE_RSA) {
ContentInfo info;
type = "enckey";
req,
req_buffer,
&client_params->reply_key,
- &info);
+ &info,
+ &kdc_cert);
if (ret) {
free_PA_PK_AS_REP(&rep);
goto out;
if (rep.u.encKeyPack.length != size)
krb5_abortx(context, "Internal ASN.1 encoder error");
+ ret = krb5_generate_random_keyblock(context, sessionetype,
+ sessionkey);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ goto out;
+ }
+
} else {
ContentInfo info;
- type = "dh";
+ switch (client_params->keyex) {
+ case USE_DH: type = "dh"; break;
+ case USE_ECDH: type = "ecdh"; break;
+ default: krb5_abortx(context, "unknown keyex"); break;
+ }
+
if (client_params->dh_group_name)
other = client_params->dh_group_name;
rep.element = choice_PA_PK_AS_REP_dhInfo;
- ret = generate_dh_keyblock(context, client_params, enctype,
- &client_params->reply_key);
+ ret = generate_dh_keyblock(context, client_params, enctype);
if (ret)
return ret;
- ret = pk_mk_pa_reply_dh(context, client_params->dh,
+ ret = pk_mk_pa_reply_dh(context, config,
client_params,
- &client_params->reply_key,
&info,
&kdc_cert);
ret);
free_ContentInfo(&info);
if (ret) {
- krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
+ krb5_set_error_message(context, ret,
+ "encoding of Key ContentInfo "
"failed %d", ret);
free_PA_PK_AS_REP(&rep);
goto out;
if (rep.u.encKeyPack.length != size)
krb5_abortx(context, "Internal ASN.1 encoder error");
- }
- if (ret) {
- free_PA_PK_AS_REP(&rep);
- goto out;
+ /* XXX KRB-FX-CF2 */
+ ret = krb5_generate_random_keyblock(context, sessionetype,
+ sessionkey);
+ if (ret) {
+ free_PA_PK_AS_REP(&rep);
+ goto out;
+ }
+
+ /* XXX Add PA-PKINIT-KX */
+
}
ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
free_PA_PK_AS_REP(&rep);
if (ret) {
- krb5_set_error_message(context, ret, "encode PA-PK-AS-REP failed %d",
- ret);
+ krb5_set_error_message(context, ret,
+ "encode PA-PK-AS-REP failed %d", ret);
goto out;
}
if (len != size)
PA_PK_AS_REP_Win2k rep;
ContentInfo info;
- if (client_params->dh) {
+ if (client_params->keyex != USE_RSA) {
ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret, "Windows PK-INIT doesn't support DH");
+ krb5_set_error_message(context, ret,
+ "Windows PK-INIT doesn't support DH");
goto out;
}
req,
req_buffer,
&client_params->reply_key,
- &info);
+ &info,
+ &kdc_cert);
if (ret) {
free_PA_PK_AS_REP_Win2k(&rep);
goto out;
if (len != size)
krb5_abortx(context, "Internal ASN.1 encoder error");
+ ret = krb5_generate_random_keyblock(context, sessionetype,
+ sessionkey);
+ if (ret)
+ goto out;
+
} else
krb5_abortx(context, "PK-INIT internal error");
ret = krb5_padata_add(context, md, pa_type, buf, len);
if (ret) {
- krb5_set_error_message(context, ret, "failed adding PA-PK-AS-REP %d", ret);
+ krb5_set_error_message(context, ret,
+ "Failed adding PA-PK-AS-REP %d", ret);
free(buf);
goto out;
}
hx509_name name;
int i;
+ if (client_params->cert == NULL) {
+
+ *subject_name = strdup("anonymous client client");
+ if (*subject_name == NULL)
+ return ENOMEM;
+ return 0;
+ }
+
ret = hx509_cert_get_base_subject(kdc_identity->hx509ctx,
client_params->cert,
&name);
ret = _krb5_pk_load_id(context,
&kdc_identity,
+ 0,
user_id,
anchors,
pool,
}
hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
- hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+ if (config->pkinit_kdc_friendly_name)
+ hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
ret = hx509_certs_find(kdc_identity->hx509ctx,
kdc_identity->certs,
hx509_query_free(kdc_identity->hx509ctx, q);
if (ret == 0) {
if (hx509_cert_check_eku(kdc_identity->hx509ctx, cert,
- oid_id_pkkdcekuoid(), 0))
- krb5_warnx(context, "WARNING Found KDC certificate "
+ oid_id_pkkdcekuoid(), 0)) {
+ hx509_name name;
+ char *str;
+ ret = hx509_cert_get_subject(cert, &name);
+ hx509_name_to_string(name, &str);
+ krb5_warnx(context, "WARNING Found KDC certificate (%s)"
"is missing the PK-INIT KDC EKU, this is bad for "
- "interoperability.");
+ "interoperability.", str);
+ hx509_name_free(&name);
+ free(str);
+ }
hx509_cert_free(cert);
} else
krb5_warnx(context, "PKINIT: failed to find a signing "
#include "kdc_locl.h"
-RCSID("$Id$");
-
/*
*
*/
_kdc_now = *tv;
}
+static krb5_error_code
+kdc_as_req(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ krb5_error_code ret;
+ KDC_REQ req;
+ size_t len;
+
+ ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &req, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_as_rep(context, config, &req, req_buffer,
+ reply, from, addr, datagram_reply);
+ free_AS_REQ(&req);
+ return ret;
+}
+
+
+static krb5_error_code
+kdc_tgs_req(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ krb5_error_code ret;
+ KDC_REQ req;
+ size_t len;
+
+ ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_tgs_rep(context, config, &req, reply,
+ from, addr, datagram_reply);
+ free_TGS_REQ(&req);
+ return ret;
+}
+
+#ifdef DIGEST
+
+static krb5_error_code
+kdc_digest(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ DigestREQ digestreq;
+ krb5_error_code ret;
+ size_t len;
+
+ ret = decode_DigestREQ(req_buffer->data, req_buffer->length,
+ &digestreq, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
+ free_DigestREQ(&digestreq);
+ return ret;
+}
+
+#endif
+
+#ifdef KX509
+
+static krb5_error_code
+kdc_kx509(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ Kx509Request kx509req;
+ krb5_error_code ret;
+ size_t len;
+
+ ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length,
+ &kx509req, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
+ free_Kx509Request(&kx509req);
+ return ret;
+}
+
+#endif
+
+
+#ifdef KRB4
+
+static krb5_error_code
+kdc_524(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ krb5_error_code ret;
+ Ticket ticket;
+ size_t len;
+
+ ret = decode_Ticket(req_buffer->data, req_buffer->length, &ticket, &len);
+ if (ret)
+ return ret;
+
+ *claim = 1;
+
+ ret = _kdc_do_524(context, config, &ticket, reply, from, addr);
+ free_Ticket(&ticket);
+ return ret;
+}
+
+static krb5_error_code
+kdc_krb4(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ if (_kdc_maybe_version4(req_buffer->data, req_buffer->length) == 0)
+ return -1;
+
+ *claim = 1;
+
+ return _kdc_do_version4(context, config,
+ req_buffer->data, req_buffer->length,
+ reply, from,
+ (struct sockaddr_in*)addr);
+}
+
+static krb5_error_code
+kdc_kaserver(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_data *req_buffer,
+ krb5_data *reply,
+ const char *from,
+ struct sockaddr *addr,
+ int datagram_reply,
+ int *claim)
+{
+ if (config->enable_kaserver == 0)
+ return -1;
+
+ *claim = 1;
+
+ return _kdc_do_kaserver(context, config,
+ req_buffer->data, req_buffer->length,
+ reply, from,
+ (struct sockaddr_in*)addr);
+}
+
+#endif /* KRB4 */
+
+
+static struct krb5_kdc_service services[] = {
+ { KS_KRB5, kdc_as_req },
+ { KS_KRB5, kdc_tgs_req },
+#ifdef DIGEST
+ { 0, kdc_digest },
+#endif
+#ifdef KX509
+ { 0, kdc_kx509 },
+#endif
+#ifdef KRB4
+ { 0, kdc_524 },
+ { KS_NO_LENGTH, kdc_krb4 },
+ { 0, kdc_kaserver },
+#endif
+ { 0, NULL }
+};
+
/*
* handle the request in `buf, len', from `addr' (or `from' as a string),
* sending a reply in `reply'.
struct sockaddr *addr,
int datagram_reply)
{
- KDC_REQ req;
- Ticket ticket;
- DigestREQ digestreq;
- Kx509Request kx509req;
krb5_error_code ret;
- size_t i;
-
- if(decode_AS_REQ(buf, len, &req, &i) == 0){
- krb5_data req_buffer;
+ unsigned int i;
+ krb5_data req_buffer;
+ int claim = 0;
+
+ req_buffer.data = buf;
+ req_buffer.length = len;
- req_buffer.data = buf;
- req_buffer.length = len;
-
- ret = _kdc_as_rep(context, config, &req, &req_buffer,
- reply, from, addr, datagram_reply);
- free_AS_REQ(&req);
- return ret;
- }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
- ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
- free_TGS_REQ(&req);
- return ret;
- }else if(decode_Ticket(buf, len, &ticket, &i) == 0){
- ret = _kdc_do_524(context, config, &ticket, reply, from, addr);
- free_Ticket(&ticket);
- return ret;
- }else if(decode_DigestREQ(buf, len, &digestreq, &i) == 0){
- ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
- free_DigestREQ(&digestreq);
- return ret;
- } else if (_kdc_try_kx509_request(buf, len, &kx509req, &i) == 0) {
- ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
- free_Kx509Request(&kx509req);
- return ret;
- } else if(_kdc_maybe_version4(buf, len)){
- *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */
- ret = _kdc_do_version4(context, config, buf, len, reply, from,
- (struct sockaddr_in*)addr);
- return ret;
- } else if (config->enable_kaserver) {
- ret = _kdc_do_kaserver(context, config, buf, len, reply, from,
- (struct sockaddr_in*)addr);
- return ret;
+ for (i = 0; services[i].process != NULL; i++) {
+ ret = (*services[i].process)(context, config, &req_buffer,
+ reply, from, addr, datagram_reply,
+ &claim);
+ if (claim) {
+ if (services[i].flags & KS_NO_LENGTH)
+ *prependlength = 0;
+ return ret;
+ }
}
-
+
return -1;
}
struct sockaddr *addr,
int datagram_reply)
{
- KDC_REQ req;
krb5_error_code ret;
- size_t i;
+ unsigned int i;
+ krb5_data req_buffer;
+ int claim = 0;
+
+ req_buffer.data = buf;
+ req_buffer.length = len;
- if(decode_AS_REQ(buf, len, &req, &i) == 0){
- krb5_data req_buffer;
-
- req_buffer.data = buf;
- req_buffer.length = len;
-
- ret = _kdc_as_rep(context, config, &req, &req_buffer,
- reply, from, addr, datagram_reply);
- free_AS_REQ(&req);
- return ret;
- }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
- ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply);
- free_TGS_REQ(&req);
- return ret;
+ for (i = 0; services[i].process != NULL; i++) {
+ if ((services[i].flags & KS_KRB5) == 0)
+ continue;
+ ret = (*services[i].process)(context, config, &req_buffer,
+ reply, from, addr, datagram_reply,
+ &claim);
+ if (claim)
+ return ret;
}
+
return -1;
}
*/
#include "kuser_locl.h"
-RCSID("$Id$");
+#ifndef HEIMDAL_SMALLER
#include "krb5-v4compat.h"
+#endif
+
+struct krb5_dh_moduli;
+struct AlgorithmIdentifier;
+struct _krb5_krb_auth_data;
+#include <krb5-private.h>
+#ifndef NO_NTLM
#include "heimntlm.h"
+#endif
int forwardable_flag = -1;
int proxiable_flag = -1;
char *server_str = NULL;
char *cred_cache = NULL;
char *start_str = NULL;
+static int switch_cache_flags = 1;
struct getarg_strings etype_str;
int use_keytab = 0;
char *keytab_str = NULL;
int fcache_version;
char *password_file = NULL;
char *pk_user_id = NULL;
+int pk_enterprise_flag = 0;
char *pk_x509_anchors = NULL;
int pk_use_enckey = 0;
static int canonicalize_flag = 0;
+static int enterprise_flag = 0;
static int ok_as_delegate_flag = 0;
static int use_referrals_flag = 0;
static int windows_flag = 0;
+#ifndef NO_NTLM
static char *ntlm_domain;
+#endif
static struct getargs args[] = {
{ "canonicalize",0, arg_flag, &canonicalize_flag,
NP_("canonicalize client principal", "") },
+
+ { "enterprise",0, arg_flag, &enterprise_flag,
+ NP_("parse principal as a KRB5-NT-ENTERPRISE name", "") },
#ifdef PKINIT
+ { "pk-enterprise", 0, arg_flag, &pk_enterprise_flag,
+ NP_("use enterprise name from certificate", "") },
+
{ "pk-user", 'C', arg_string, &pk_user_id,
NP_("principal's public/private/certificate identifier", ""), "id" },
{ "pk-use-enckey", 0, arg_flag, &pk_use_enckey,
NP_("Use RSA encrypted reply (instead of DH)", "") },
#endif
+#ifndef NO_NTLM
{ "ntlm-domain", 0, arg_string, &ntlm_domain,
NP_("NTLM domain", ""), "domain" },
+#endif
+
+ { "change-default", 0, arg_negative_flag, &switch_cache_flags,
+ NP_("switch the default cache to the new credentials cache", "") },
{ "ok-as-delegate", 0, arg_flag, &ok_as_delegate_flag,
NP_("honor ok-as-delegate on tickets", "") },
else if (out)
flags.b.proxiable = out->flags.b.proxiable;
- if (anonymous_flag != -1)
+ if (anonymous_flag)
flags.b.request_anonymous = anonymous_flag;
if(life)
in.times.endtime = time(NULL) + life;
if(get_v4_tgt)
do_524init(context, cache, out, NULL);
#endif
+#ifndef NO_AFS
if(do_afslog && k_hasafs())
krb5_afslog(context, cache, NULL, NULL);
+#endif
}
krb5_free_creds (context, out);
return ret;
}
+#ifndef NO_NTLM
+
static krb5_error_code
store_ntlmkey(krb5_context context, krb5_ccache id,
const char *domain, struct ntlm_buf *buf)
free(name);
return ret;
}
+#endif
static krb5_error_code
get_new_tickets(krb5_context context,
krb5_deltat renew = 0;
char *renewstr = NULL;
krb5_enctype *enctype = NULL;
- struct ntlm_buf ntlmkey;
krb5_ccache tempccache;
-
+#ifndef NO_NTLM
+ struct ntlm_buf ntlmkey;
memset(&ntlmkey, 0, sizeof(ntlmkey));
+#endif
passwd[0] = '\0';
if (password_file) {
krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag);
if(proxiable_flag != -1)
krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag);
- if(anonymous_flag != -1)
+ if(anonymous_flag)
krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag);
if (pac_flag != -1)
krb5_get_init_creds_opt_set_pac_request(context, opt,
pac_flag ? TRUE : FALSE);
if (canonicalize_flag)
krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE);
- if (pk_user_id) {
+ if (pk_enterprise_flag && windows_flag)
+ krb5_get_init_creds_opt_set_win2k(context, opt, TRUE);
+ if (pk_user_id || anonymous_flag) {
ret = krb5_get_init_creds_opt_set_pkinit(context, opt,
principal,
pk_user_id,
pk_x509_anchors,
NULL,
NULL,
- pk_use_enckey ? 2 : 0,
+ pk_use_enckey ? 2 : 0 |
+ anonymous_flag ? 4 : 0,
krb5_prompter_posix,
NULL,
passwd);
server_str,
opt);
krb5_kt_close(context, kt);
- } else if (pk_user_id) {
+ } else if (pk_user_id || anonymous_flag) {
ret = krb5_get_init_creds_password (context,
&cred,
principal,
opt);
}
krb5_get_init_creds_opt_free(context, opt);
+#ifndef NO_NTLM
if (ntlm_domain && passwd[0])
heim_ntlm_nt_key(passwd, &ntlmkey);
+#endif
memset(passwd, 0, sizeof(passwd));
switch(ret){
if (ret)
krb5_err (context, 1, ret, "krb5_cc_move");
+ if (switch_cache_flags)
+ krb5_cc_switch(context, ccache);
+
+#ifndef NO_NTLM
if (ntlm_domain && ntlmkey.data)
store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey);
+#endif
if (ok_as_delegate_flag || windows_flag || use_referrals_flag) {
unsigned char d = 0;
if(get_v4_tgt || convert_524)
do_524init(ctx->context, ctx->ccache, NULL, server_str);
#endif
+#ifndef NO_AFS
if(do_afslog && k_hasafs())
krb5_afslog(ctx->context, ctx->ccache, NULL, NULL);
+#endif
expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal,
server_str) / 2;
argc -= optidx;
argv += optidx;
- if (canonicalize_flag)
+ if (canonicalize_flag || enterprise_flag)
parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
- if (argv[0]) {
- ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal);
+ if (pk_enterprise_flag) {
+ ret = _krb5_pk_enterprise_cert(context, pk_user_id,
+ argv[0], &principal);
if (ret)
- krb5_err (context, 1, ret, "krb5_parse_name");
- } else {
- ret = krb5_get_default_principal (context, &principal);
+ krb5_err(context, 1, ret, "krb5_pk_enterprise_certs");
+
+ } else if (anonymous_flag) {
+
+ ret = krb5_make_principal(context, &principal, argv[0],
+ KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME,
+ NULL);
if (ret)
- krb5_err (context, 1, ret, "krb5_get_default_principal");
+ krb5_err(context, 1, ret, "krb5_build_principal");
+ krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);
+
+ } else {
+ if (argv[0]) {
+ ret = krb5_parse_name_flags (context, argv[0], parseflags,
+ &principal);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_parse_name");
+ } else {
+ ret = krb5_get_default_principal (context, &principal);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_get_default_principal");
+ }
}
if(fcache_version)
if (ret)
krb5_err (context, 1, ret, N_("resolving credentials cache", ""));
+#ifndef NO_AFS
if(argc > 1 && k_hasafs ())
k_setpag();
+#endif
if (lifetime) {
int tmp = parse_time (lifetime, "s");
if(get_v4_tgt || convert_524)
do_524init(context, ccache, NULL, server_str);
#endif
+#ifndef NO_AFS
if(do_afslog && k_hasafs())
krb5_afslog(context, ccache, NULL, NULL);
+#endif
if(argc > 1) {
struct renew_ctx ctx;
time_t timeout;
#ifndef HEIMDAL_SMALLER
_krb5_krb_dest_tkt(context, krb4_cc_name);
#endif
+#ifndef NO_AFS
if(k_hasafs())
k_unlog();
+#endif
} else {
krb5_cc_close (context, ccache);
ret = 0;
#ifndef __KUSER_LOCL_H__
#define __KUSER_LOCL_H__
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_SYS_IOCCOM_H
#include <sys/ioccom.h>
#endif
+#ifndef NO_AFS
#include <kafs.h>
+#endif
#include "crypto-headers.h" /* for UI_UTIL_read_pw_string */
#ifdef HAVE_LOCALE_H
+++ /dev/null
--- From RFC 3369 --
--- $Id$ --
-
-CMS DEFINITIONS ::= BEGIN
-
-IMPORTS CertificateSerialNumber, AlgorithmIdentifier, Name,
- Attribute, Certificate, Name, SubjectKeyIdentifier FROM rfc2459
- heim_any, heim_any_set FROM heim;
-
-id-pkcs7 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- us(840) rsadsi(113549) pkcs(1) pkcs7(7) }
-
-id-pkcs7-data OBJECT IDENTIFIER ::= { id-pkcs7 1 }
-id-pkcs7-signedData OBJECT IDENTIFIER ::= { id-pkcs7 2 }
-id-pkcs7-envelopedData OBJECT IDENTIFIER ::= { id-pkcs7 3 }
-id-pkcs7-signedAndEnvelopedData OBJECT IDENTIFIER ::= { id-pkcs7 4 }
-id-pkcs7-digestedData OBJECT IDENTIFIER ::= { id-pkcs7 5 }
-id-pkcs7-encryptedData OBJECT IDENTIFIER ::= { id-pkcs7 6 }
-
-CMSVersion ::= INTEGER {
- CMSVersion_v0(0),
- CMSVersion_v1(1),
- CMSVersion_v2(2),
- CMSVersion_v3(3),
- CMSVersion_v4(4)
-}
-
-DigestAlgorithmIdentifier ::= AlgorithmIdentifier
-DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
-SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
-
-ContentType ::= OBJECT IDENTIFIER
-MessageDigest ::= OCTET STRING
-
-ContentInfo ::= SEQUENCE {
- contentType ContentType,
- content [0] EXPLICIT heim_any OPTIONAL -- DEFINED BY contentType
-}
-
-EncapsulatedContentInfo ::= SEQUENCE {
- eContentType ContentType,
- eContent [0] EXPLICIT OCTET STRING OPTIONAL
-}
-
-CertificateSet ::= SET OF heim_any
-
-CertificateList ::= Certificate
-
-CertificateRevocationLists ::= SET OF CertificateList
-
-IssuerAndSerialNumber ::= SEQUENCE {
- issuer Name,
- serialNumber CertificateSerialNumber
-}
-
--- RecipientIdentifier is same as SignerIdentifier,
--- lets glue them togheter and save some bytes and share code for them
-
-CMSIdentifier ::= CHOICE {
- issuerAndSerialNumber IssuerAndSerialNumber,
- subjectKeyIdentifier [0] SubjectKeyIdentifier
-}
-
-SignerIdentifier ::= CMSIdentifier
-RecipientIdentifier ::= CMSIdentifier
-
---- CMSAttributes are the combined UnsignedAttributes and SignedAttributes
---- to store space and share code
-
-CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX)
-
-SignatureValue ::= OCTET STRING
-
-SignerInfo ::= SEQUENCE {
- version CMSVersion,
- sid SignerIdentifier,
- digestAlgorithm DigestAlgorithmIdentifier,
- signedAttrs [0] IMPLICIT -- CMSAttributes --
- SET OF Attribute OPTIONAL,
- signatureAlgorithm SignatureAlgorithmIdentifier,
- signature SignatureValue,
- unsignedAttrs [1] IMPLICIT -- CMSAttributes --
- SET OF Attribute OPTIONAL
-}
-
-SignerInfos ::= SET OF SignerInfo
-
-SignedData ::= SEQUENCE {
- version CMSVersion,
- digestAlgorithms DigestAlgorithmIdentifiers,
- encapContentInfo EncapsulatedContentInfo,
- certificates [0] IMPLICIT -- CertificateSet --
- SET OF heim_any OPTIONAL,
- crls [1] IMPLICIT -- CertificateRevocationLists --
- heim_any OPTIONAL,
- signerInfos SignerInfos
-}
-
-OriginatorInfo ::= SEQUENCE {
- certs [0] IMPLICIT -- CertificateSet --
- SET OF heim_any OPTIONAL,
- crls [1] IMPLICIT --CertificateRevocationLists --
- heim_any OPTIONAL
-}
-
-KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-
-EncryptedKey ::= OCTET STRING
-
-KeyTransRecipientInfo ::= SEQUENCE {
- version CMSVersion, -- always set to 0 or 2
- rid RecipientIdentifier,
- keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
- encryptedKey EncryptedKey
-}
-
-RecipientInfo ::= KeyTransRecipientInfo
-
-RecipientInfos ::= SET OF RecipientInfo
-
-EncryptedContent ::= OCTET STRING
-
-EncryptedContentInfo ::= SEQUENCE {
- contentType ContentType,
- contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
- encryptedContent [0] IMPLICIT OCTET STRING OPTIONAL
-}
-
-UnprotectedAttributes ::= SET OF Attribute -- SIZE (1..MAX)
-
-CMSEncryptedData ::= SEQUENCE {
- version CMSVersion,
- encryptedContentInfo EncryptedContentInfo,
- unprotectedAttrs [1] IMPLICIT -- UnprotectedAttributes --
- heim_any OPTIONAL
-}
-
-EnvelopedData ::= SEQUENCE {
- version CMSVersion,
- originatorInfo [0] IMPLICIT -- OriginatorInfo -- heim_any OPTIONAL,
- recipientInfos RecipientInfos,
- encryptedContentInfo EncryptedContentInfo,
- unprotectedAttrs [1] IMPLICIT -- UnprotectedAttributes --
- heim_any OPTIONAL
-}
-
--- Data ::= OCTET STRING
-
-CMSRC2CBCParameter ::= SEQUENCE {
- rc2ParameterVersion INTEGER (0..4294967295),
- iv OCTET STRING -- exactly 8 octets
-}
-
-CMSCBCParameter ::= OCTET STRING
-
-END
error_code MIN_CONSTRAINT, "ASN.1 too few elements"
error_code MAX_CONSTRAINT, "ASN.1 too many elements"
error_code EXACT_CONSTRAINT, "ASN.1 wrong number of elements"
+error_code INDEF_OVERRUN, "ASN.1 BER indefinte encoding overrun"
+error_code INDEF_UNDERRUN, "ASN.1 BER indefinte encoding underun"
end
#include "der_locl.h"
-RCSID("$Id$");
-
-#include <version.h>
-
/*
* All decoding functions take a pointer `p' to first position in
* which to read, from the left, `len' which means the maximum number
return 0;
}
+int
+der_get_octet_string_ber (const unsigned char *p, size_t len,
+ heim_octet_string *data, size_t *size)
+{
+ int e;
+ Der_type type;
+ Der_class class;
+ unsigned int tag, depth = 0;
+ size_t l, datalen, oldlen = len;
+
+ data->length = 0;
+ data->data = NULL;
+
+ while (len) {
+ e = der_get_tag (p, len, &class, &type, &tag, &l);
+ if (e) goto out;
+ if (class != ASN1_C_UNIV) {
+ e = ASN1_BAD_ID;
+ goto out;
+ }
+ if (type == PRIM && tag == UT_EndOfContent) {
+ if (depth == 0)
+ break;
+ depth--;
+ }
+ if (tag != UT_OctetString) {
+ e = ASN1_BAD_ID;
+ goto out;
+ }
+
+ p += l;
+ len -= l;
+ e = der_get_length (p, len, &datalen, &l);
+ if (e) goto out;
+ p += l;
+ len -= l;
+
+ if (datalen > len)
+ return ASN1_OVERRUN;
+
+ if (type == PRIM) {
+ void *ptr;
+
+ ptr = realloc(data->data, data->length + datalen);
+ if (ptr == NULL) {
+ e = ENOMEM;
+ goto out;
+ }
+ data->data = ptr;
+ memcpy(((unsigned char *)data->data) + data->length, p, datalen);
+ data->length += datalen;
+ } else
+ depth++;
+
+ p += datalen;
+ len -= datalen;
+ }
+ if (depth != 0)
+ return ASN1_INDEF_OVERRUN;
+ if(size) *size = oldlen - len;
+ return 0;
+ out:
+ free(data->data);
+ data->data = NULL;
+ data->length = 0;
+ return e;
+}
+
+
int
der_get_heim_integer (const unsigned char *p, size_t len,
heim_integer *data, size_t *size)
der_match_tag (const unsigned char *p, size_t len,
Der_class class, Der_type type,
unsigned int tag, size_t *size)
+{
+ Der_type thistype;
+ int e;
+
+ e = der_match_tag2(p, len, class, &thistype, tag, size);
+ if (e) return e;
+ if (thistype != type) return ASN1_BAD_ID;
+ return 0;
+}
+
+int
+der_match_tag2 (const unsigned char *p, size_t len,
+ Der_class class, Der_type *type,
+ unsigned int tag, size_t *size)
{
size_t l;
Der_class thisclass;
- Der_type thistype;
unsigned int thistag;
int e;
- e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l);
+ e = der_get_tag (p, len, &thisclass, type, &thistag, &l);
if (e) return e;
- if (class != thisclass || type != thistype)
+ if (class != thisclass)
return ASN1_BAD_ID;
if(tag > thistag)
return ASN1_MISPLACED_FIELD;
int
der_match_tag_and_length (const unsigned char *p, size_t len,
- Der_class class, Der_type type, unsigned int tag,
+ Der_class class, Der_type *type, unsigned int tag,
size_t *length_ret, size_t *size)
{
size_t l, ret = 0;
int e;
- e = der_match_tag (p, len, class, type, tag, &l);
+ e = der_match_tag2 (p, len, class, type, tag, &l);
if (e) return e;
p += l;
len -= l;
return 0;
}
+
+
/*
* Old versions of DCE was based on a very early beta of the MIT code,
* which used MAVROS for ASN.1 encoding. MAVROS had the interesting
data->data = malloc(len - 1);
if (data->data == NULL && (len - 1) != 0)
return ENOMEM;
- memcpy (data->data, p + 1, len - 1);
- data->length -= p[0];
+ /* copy data is there is data to copy */
+ if (len - 1 != 0) {
+ memcpy (data->data, p + 1, len - 1);
+ data->length -= p[0];
+ }
if(size) *size = len;
return 0;
}
#ifndef __DER_LOCL_H__
#define __DER_LOCL_H__
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-#endif
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
return ASN1_OVERFLOW;
e = der_get_length(p + l, len - l, &length, &len_len);
if (e) return e;
- if (length + len_len + l > len)
- return ASN1_OVERFLOW;
-
+ if (length == ASN1_INDEFINITE) {
+ if (len < len_len + l)
+ return ASN1_OVERFLOW;
+ length = len - (len_len + l);
+ } else {
+ if (len < length + len_len + l)
+ return ASN1_OVERFLOW;
+ }
+
data->data = malloc(length + len_len + l);
if (data->data == NULL)
return ENOMEM;
data->length = length + len_len + l;
memcpy(data->data, p, length + len_len + l);
-
+
if (size)
*size = length + len_len + l;
}
}
-static void
+void
generate_header_of_codefile(const char *name)
{
char *filename;
}
-static void
+void
close_codefile(void)
{
if (codefile == NULL)
struct objid *o, **list;
unsigned int i, len;
- generate_header_of_codefile(s->gen_name);
+ if (!one_code_file)
+ generate_header_of_codefile(s->gen_name);
len = 0;
for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
}
fprintf (headerfile, "} */\n");
- fprintf (headerfile, "const heim_oid *oid_%s(void);\n\n",
+ fprintf (headerfile, "const heim_oid *oid_%s(void);\n",
+ s->gen_name);
+ fprintf (headerfile,
+ "extern const heim_oid asn1_oid_%s;\n\n",
s->gen_name);
+
fprintf (codefile, "static unsigned oid_%s_variable_num[%d] = {",
s->gen_name, len);
for (i = len ; i > 0; i--) {
}
fprintf(codefile, "};\n");
- fprintf (codefile, "static const heim_oid oid_%s_variable = "
+ fprintf (codefile, "const heim_oid asn1_oid_%s = "
"{ %d, oid_%s_variable_num };\n\n",
s->gen_name, len, s->gen_name);
fprintf (codefile, "const heim_oid *oid_%s(void)\n"
"{\n"
- "return &oid_%s_variable;\n"
+ "return &asn1_oid_%s;\n"
"}\n\n",
s->gen_name, s->gen_name);
- close_codefile();
+ free(list);
+
+ if (!one_code_file)
+ close_codefile();
break;
}
void
generate_type (const Symbol *s)
{
- generate_header_of_codefile(s->gen_name);
+ if (!one_code_file)
+ generate_header_of_codefile(s->gen_name);
generate_type_header (s);
generate_type_encode (s);
generate_type_seq (s);
generate_glue (s->type, s->gen_name);
fprintf(headerfile, "\n\n");
- close_codefile();
+
+ if (!one_code_file) {
+ fprintf(codefile, "\n\n");
+ close_codefile();
+ }
}
static int
decode_type (const char *name, const Type *t, int optional,
- const char *forwstr, const char *tmpstr)
+ const char *forwstr, const char *tmpstr, const char *dertype)
{
switch (t->type) {
case TType: {
decode_primitive ("enumerated", name, forwstr);
break;
case TOctetString:
+ if (dertype) {
+ fprintf(codefile,
+ "if (%s == CONS) {\n",
+ dertype);
+ decode_primitive("octet_string_ber", name, forwstr);
+ fprintf(codefile,
+ "} else {\n");
+ }
decode_primitive ("octet_string", name, forwstr);
+ if (dertype)
+ fprintf(codefile, "}\n");
if (t->range)
range_check(name, "length", forwstr, t->range);
break;
name, m->gen_name);
if (s == NULL)
errx(1, "malloc");
- decode_type (s, m->type, m->optional, forwstr, m->gen_name);
+ decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL);
free (s);
}
"%s = calloc(1, sizeof(*%s));\n"
"if (%s == NULL) { e = ENOMEM; %s; }\n",
s, s, s, forwstr);
- decode_type (s, m->type, 0, forwstr, m->gen_name);
+ decode_type (s, m->type, 0, forwstr, m->gen_name, NULL);
free (s);
fprintf(codefile, "members |= (1 << %d);\n", memno);
asprintf (&sname, "%s_s_of", tmpstr);
if (sname == NULL)
errx(1, "malloc");
- decode_type (n, t->subtype, 0, forwstr, sname);
+ decode_type (n, t->subtype, 0, forwstr, sname, NULL);
fprintf (codefile,
"(%s)->len++;\n"
"len = %s_origlen - ret;\n"
decode_primitive ("general_string", name, forwstr);
break;
case TTag:{
- char *tname;
+ char *tname, *typestring;
+ char *ide = NULL;
+
+ asprintf(&typestring, "%s_type", tmpstr);
fprintf(codefile,
"{\n"
- "size_t %s_datalen, %s_oldlen;\n",
- tmpstr, tmpstr);
- if(dce_fix)
+ "size_t %s_datalen, %s_oldlen;\n"
+ "Der_type %s;\n",
+ tmpstr, tmpstr, typestring);
+ if(support_ber)
fprintf(codefile,
- "int dce_fix;\n");
- fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, %s, %s, "
+ "int is_indefinite;\n");
+
+ fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, "
"&%s_datalen, &l);\n",
classname(t->tag.tagclass),
- is_primitive_type(t->subtype->type) ? "PRIM" : "CONS",
+ typestring,
valuename(t->tag.tagclass, t->tag.tagvalue),
tmpstr);
+
+ /* XXX hardcode for now */
+ if (support_ber && t->subtype->type == TOctetString) {
+ ide = typestring;
+ } else {
+ fprintf(codefile,
+ "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n",
+ typestring,
+ is_primitive_type(t->subtype->type) ? "PRIM" : "CONS");
+ }
+
if(optional) {
fprintf(codefile,
"if(e) {\n"
"p += l; len -= l; ret += l;\n"
"%s_oldlen = len;\n",
tmpstr);
- if(dce_fix)
+ if(support_ber)
fprintf (codefile,
- "if((dce_fix = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
- "{ e = ASN1_BAD_FORMAT; %s; }\n",
- tmpstr, forwstr);
+ "if((is_indefinite = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
+ "{ e = ASN1_BAD_FORMAT; %s; }\n"
+ "if (is_indefinite) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }",
+ tmpstr, forwstr, forwstr);
else
fprintf(codefile,
"if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
asprintf (&tname, "%s_Tag", tmpstr);
if (tname == NULL)
errx(1, "malloc");
- decode_type (name, t->subtype, 0, forwstr, tname);
- if(dce_fix)
+ decode_type (name, t->subtype, 0, forwstr, tname, ide);
+ if(support_ber)
fprintf(codefile,
- "if(dce_fix){\n"
- "e = der_match_tag_and_length (p, len, "
- "(Der_class)0,(Der_type)0, UT_EndOfContent, "
+ "if(is_indefinite){\n"
+ "len += 2;\n"
+ "e = der_match_tag_and_length(p, len, "
+ "(Der_class)0, &%s, UT_EndOfContent, "
"&%s_datalen, &l);\n"
- "if(e) %s;\np += l; len -= l; ret += l;\n"
- "} else \n", tmpstr, forwstr);
+ "if(e) %s;\n"
+ "p += l; len -= l; ret += l;\n"
+ "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n"
+ "} else \n",
+ typestring,
+ tmpstr,
+ forwstr,
+ typestring, forwstr);
fprintf(codefile,
"len = %s_oldlen - %s_datalen;\n",
tmpstr, tmpstr);
fprintf(codefile,
"}\n");
free(tname);
+ free(typestring);
break;
}
case TChoice: {
name, m->gen_name);
if (s == NULL)
errx(1, "malloc");
- decode_type (s, m->type, m->optional, forwstr, m->gen_name);
+ decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL);
fprintf(codefile,
"(%s)->element = %s;\n",
name, m->label);
fprintf (codefile, "\n");
fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
- decode_type ("data", s->type, 0, "goto fail", "Top");
+ decode_type ("data", s->type, 0, "goto fail", "Top", NULL);
if (preserve)
fprintf (codefile,
"data->_save.data = calloc(1, ret);\n"
#ifndef __GEN_LOCL_H__
#define __GEN_LOCL_H__
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int preserve_type(const char *);
int seq_type(const char *);
+void generate_header_of_codefile(const char *);
+void close_codefile(void);
+
+
extern FILE *headerfile, *codefile, *logfile;
-extern int dce_fix;
+extern int support_ber;
extern int rfc1510_bitstring;
+extern int one_code_file;
extern int error_flag;
+++ /dev/null
--- $Id$
-
-KERBEROS5 DEFINITIONS ::=
-BEGIN
-
-NAME-TYPE ::= INTEGER {
- KRB5_NT_UNKNOWN(0), -- Name type not known
- KRB5_NT_PRINCIPAL(1), -- Just the name of the principal as in
- KRB5_NT_SRV_INST(2), -- Service and other unique instance (krbtgt)
- KRB5_NT_SRV_HST(3), -- Service with host name as instance
- KRB5_NT_SRV_XHST(4), -- Service with host as remaining components
- KRB5_NT_UID(5), -- Unique ID
- KRB5_NT_X500_PRINCIPAL(6), -- PKINIT
- KRB5_NT_SMTP_NAME(7), -- Name in form of SMTP email name
- KRB5_NT_ENTERPRISE_PRINCIPAL(10), -- Windows 2000 UPN
- KRB5_NT_ENT_PRINCIPAL_AND_ID(-130), -- Windows 2000 UPN and SID
- KRB5_NT_MS_PRINCIPAL(-128), -- NT 4 style name
- KRB5_NT_MS_PRINCIPAL_AND_ID(-129) -- NT style name and SID
-}
-
--- message types
-
-MESSAGE-TYPE ::= INTEGER {
- krb-as-req(10), -- Request for initial authentication
- krb-as-rep(11), -- Response to KRB_AS_REQ request
- krb-tgs-req(12), -- Request for authentication based on TGT
- krb-tgs-rep(13), -- Response to KRB_TGS_REQ request
- krb-ap-req(14), -- application request to server
- krb-ap-rep(15), -- Response to KRB_AP_REQ_MUTUAL
- krb-safe(20), -- Safe (checksummed) application message
- krb-priv(21), -- Private (encrypted) application message
- krb-cred(22), -- Private (encrypted) message to forward credentials
- krb-error(30) -- Error response
-}
-
-
--- pa-data types
-
-PADATA-TYPE ::= INTEGER {
- KRB5-PADATA-NONE(0),
- KRB5-PADATA-TGS-REQ(1),
- KRB5-PADATA-AP-REQ(1),
- KRB5-PADATA-ENC-TIMESTAMP(2),
- KRB5-PADATA-PW-SALT(3),
- KRB5-PADATA-ENC-UNIX-TIME(5),
- KRB5-PADATA-SANDIA-SECUREID(6),
- KRB5-PADATA-SESAME(7),
- KRB5-PADATA-OSF-DCE(8),
- KRB5-PADATA-CYBERSAFE-SECUREID(9),
- KRB5-PADATA-AFS3-SALT(10),
- KRB5-PADATA-ETYPE-INFO(11),
- KRB5-PADATA-SAM-CHALLENGE(12), -- (sam/otp)
- KRB5-PADATA-SAM-RESPONSE(13), -- (sam/otp)
- KRB5-PADATA-PK-AS-REQ-19(14), -- (PKINIT-19)
- KRB5-PADATA-PK-AS-REP-19(15), -- (PKINIT-19)
- KRB5-PADATA-PK-AS-REQ-WIN(15), -- (PKINIT - old number)
- KRB5-PADATA-PK-AS-REQ(16), -- (PKINIT-25)
- KRB5-PADATA-PK-AS-REP(17), -- (PKINIT-25)
- KRB5-PADATA-PA-PK-OCSP-RESPONSE(18),
- KRB5-PADATA-ETYPE-INFO2(19),
- KRB5-PADATA-USE-SPECIFIED-KVNO(20),
- KRB5-PADATA-SVR-REFERRAL-INFO(20), --- old ms referral number
- KRB5-PADATA-SAM-REDIRECT(21), -- (sam/otp)
- KRB5-PADATA-GET-FROM-TYPED-DATA(22),
- KRB5-PADATA-SAM-ETYPE-INFO(23),
- KRB5-PADATA-SERVER-REFERRAL(25),
- KRB5-PADATA-TD-KRB-PRINCIPAL(102), -- PrincipalName
- KRB5-PADATA-PK-TD-TRUSTED-CERTIFIERS(104), -- PKINIT
- KRB5-PADATA-PK-TD-CERTIFICATE-INDEX(105), -- PKINIT
- KRB5-PADATA-TD-APP-DEFINED-ERROR(106), -- application specific
- KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER
- KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER
- KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com
- KRB5-PADATA-S4U2SELF(129),
- KRB5-PADATA-EPAC(130), -- EPAK
- KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to
- -- tell KDC that is supports
- -- the asCheckSum in the
- -- PK-AS-REP
- KRB5-PADATA-CLIENT-CANONICALIZED(133) --
-}
-
-AUTHDATA-TYPE ::= INTEGER {
- KRB5-AUTHDATA-IF-RELEVANT(1),
- KRB5-AUTHDATA-INTENDED-FOR_SERVER(2),
- KRB5-AUTHDATA-INTENDED-FOR-APPLICATION-CLASS(3),
- KRB5-AUTHDATA-KDC-ISSUED(4),
- KRB5-AUTHDATA-AND-OR(5),
- KRB5-AUTHDATA-MANDATORY-TICKET-EXTENSIONS(6),
- KRB5-AUTHDATA-IN-TICKET-EXTENSIONS(7),
- KRB5-AUTHDATA-MANDATORY-FOR-KDC(8),
- KRB5-AUTHDATA-INITIAL-VERIFIED-CAS(9),
- KRB5-AUTHDATA-OSF-DCE(64),
- KRB5-AUTHDATA-SESAME(65),
- KRB5-AUTHDATA-OSF-DCE-PKI-CERTID(66),
- KRB5-AUTHDATA-WIN2K-PAC(128),
- KRB5-AUTHDATA-GSS-API-ETYPE-NEGOTIATION(129), -- Authenticator only
- KRB5-AUTHDATA-SIGNTICKET-OLD(-17),
- KRB5-AUTHDATA-SIGNTICKET(142)
-}
-
--- checksumtypes
-
-CKSUMTYPE ::= INTEGER {
- CKSUMTYPE_NONE(0),
- CKSUMTYPE_CRC32(1),
- CKSUMTYPE_RSA_MD4(2),
- CKSUMTYPE_RSA_MD4_DES(3),
- CKSUMTYPE_DES_MAC(4),
- CKSUMTYPE_DES_MAC_K(5),
- CKSUMTYPE_RSA_MD4_DES_K(6),
- CKSUMTYPE_RSA_MD5(7),
- CKSUMTYPE_RSA_MD5_DES(8),
- CKSUMTYPE_RSA_MD5_DES3(9),
- CKSUMTYPE_SHA1_OTHER(10),
- CKSUMTYPE_HMAC_SHA1_DES3(12),
- CKSUMTYPE_SHA1(14),
- CKSUMTYPE_HMAC_SHA1_96_AES_128(15),
- CKSUMTYPE_HMAC_SHA1_96_AES_256(16),
- CKSUMTYPE_GSSAPI(0x8003),
- CKSUMTYPE_HMAC_MD5(-138), -- unofficial microsoft number
- CKSUMTYPE_HMAC_MD5_ENC(-1138) -- even more unofficial
-}
-
---enctypes
-ENCTYPE ::= INTEGER {
- ETYPE_NULL(0),
- ETYPE_DES_CBC_CRC(1),
- ETYPE_DES_CBC_MD4(2),
- ETYPE_DES_CBC_MD5(3),
- ETYPE_DES3_CBC_MD5(5),
- ETYPE_OLD_DES3_CBC_SHA1(7),
- ETYPE_SIGN_DSA_GENERATE(8),
- ETYPE_ENCRYPT_RSA_PRIV(9),
- ETYPE_ENCRYPT_RSA_PUB(10),
- ETYPE_DES3_CBC_SHA1(16), -- with key derivation
- ETYPE_AES128_CTS_HMAC_SHA1_96(17),
- ETYPE_AES256_CTS_HMAC_SHA1_96(18),
- ETYPE_ARCFOUR_HMAC_MD5(23),
- ETYPE_ARCFOUR_HMAC_MD5_56(24),
- ETYPE_ENCTYPE_PK_CROSS(48),
--- some "old" windows types
- ETYPE_ARCFOUR_MD4(-128),
- ETYPE_ARCFOUR_HMAC_OLD(-133),
- ETYPE_ARCFOUR_HMAC_OLD_EXP(-135),
--- these are for Heimdal internal use
- ETYPE_DES_CBC_NONE(-0x1000),
- ETYPE_DES3_CBC_NONE(-0x1001),
- ETYPE_DES_CFB64_NONE(-0x1002),
- ETYPE_DES_PCBC_NONE(-0x1003),
- ETYPE_DIGEST_MD5_NONE(-0x1004), -- private use, lukeh@padl.com
- ETYPE_CRAM_MD5_NONE(-0x1005) -- private use, lukeh@padl.com
-}
-
-
-
-
--- this is sugar to make something ASN1 does not have: unsigned
-
-krb5uint32 ::= INTEGER (0..4294967295)
-krb5int32 ::= INTEGER (-2147483648..2147483647)
-
-KerberosString ::= GeneralString
-
-Realm ::= GeneralString
-PrincipalName ::= SEQUENCE {
- name-type[0] NAME-TYPE,
- name-string[1] SEQUENCE OF GeneralString
-}
-
--- this is not part of RFC1510
-Principal ::= SEQUENCE {
- name[0] PrincipalName,
- realm[1] Realm
-}
-
-HostAddress ::= SEQUENCE {
- addr-type[0] krb5int32,
- address[1] OCTET STRING
-}
-
--- This is from RFC1510.
---
--- HostAddresses ::= SEQUENCE OF SEQUENCE {
--- addr-type[0] krb5int32,
--- address[1] OCTET STRING
--- }
-
--- This seems much better.
-HostAddresses ::= SEQUENCE OF HostAddress
-
-
-KerberosTime ::= GeneralizedTime -- Specifying UTC time zone (Z)
-
-AuthorizationDataElement ::= SEQUENCE {
- ad-type[0] krb5int32,
- ad-data[1] OCTET STRING
-}
-
-AuthorizationData ::= SEQUENCE OF AuthorizationDataElement
-
-APOptions ::= BIT STRING {
- reserved(0),
- use-session-key(1),
- mutual-required(2)
-}
-
-TicketFlags ::= BIT STRING {
- reserved(0),
- forwardable(1),
- forwarded(2),
- proxiable(3),
- proxy(4),
- may-postdate(5),
- postdated(6),
- invalid(7),
- renewable(8),
- initial(9),
- pre-authent(10),
- hw-authent(11),
- transited-policy-checked(12),
- ok-as-delegate(13),
- anonymous(14)
-}
-
-KDCOptions ::= BIT STRING {
- reserved(0),
- forwardable(1),
- forwarded(2),
- proxiable(3),
- proxy(4),
- allow-postdate(5),
- postdated(6),
- unused7(7),
- renewable(8),
- unused9(9),
- unused10(10),
- unused11(11),
- request-anonymous(14),
- canonicalize(15),
- constrained-delegation(16), -- ms extension
- disable-transited-check(26),
- renewable-ok(27),
- enc-tkt-in-skey(28),
- renew(30),
- validate(31)
-}
-
-LR-TYPE ::= INTEGER {
- LR_NONE(0), -- no information
- LR_INITIAL_TGT(1), -- last initial TGT request
- LR_INITIAL(2), -- last initial request
- LR_ISSUE_USE_TGT(3), -- time of newest TGT used
- LR_RENEWAL(4), -- time of last renewal
- LR_REQUEST(5), -- time of last request (of any type)
- LR_PW_EXPTIME(6), -- expiration time of password
- LR_ACCT_EXPTIME(7) -- expiration time of account
-}
-
-LastReq ::= SEQUENCE OF SEQUENCE {
- lr-type[0] LR-TYPE,
- lr-value[1] KerberosTime
-}
-
-
-EncryptedData ::= SEQUENCE {
- etype[0] ENCTYPE, -- EncryptionType
- kvno[1] krb5int32 OPTIONAL,
- cipher[2] OCTET STRING -- ciphertext
-}
-
-EncryptionKey ::= SEQUENCE {
- keytype[0] krb5int32,
- keyvalue[1] OCTET STRING
-}
-
--- encoded Transited field
-TransitedEncoding ::= SEQUENCE {
- tr-type[0] krb5int32, -- must be registered
- contents[1] OCTET STRING
-}
-
-Ticket ::= [APPLICATION 1] SEQUENCE {
- tkt-vno[0] krb5int32,
- realm[1] Realm,
- sname[2] PrincipalName,
- enc-part[3] EncryptedData
-}
--- Encrypted part of ticket
-EncTicketPart ::= [APPLICATION 3] SEQUENCE {
- flags[0] TicketFlags,
- key[1] EncryptionKey,
- crealm[2] Realm,
- cname[3] PrincipalName,
- transited[4] TransitedEncoding,
- authtime[5] KerberosTime,
- starttime[6] KerberosTime OPTIONAL,
- endtime[7] KerberosTime,
- renew-till[8] KerberosTime OPTIONAL,
- caddr[9] HostAddresses OPTIONAL,
- authorization-data[10] AuthorizationData OPTIONAL
-}
-
-Checksum ::= SEQUENCE {
- cksumtype[0] CKSUMTYPE,
- checksum[1] OCTET STRING
-}
-
-Authenticator ::= [APPLICATION 2] SEQUENCE {
- authenticator-vno[0] krb5int32,
- crealm[1] Realm,
- cname[2] PrincipalName,
- cksum[3] Checksum OPTIONAL,
- cusec[4] krb5int32,
- ctime[5] KerberosTime,
- subkey[6] EncryptionKey OPTIONAL,
- seq-number[7] krb5uint32 OPTIONAL,
- authorization-data[8] AuthorizationData OPTIONAL
-}
-
-PA-DATA ::= SEQUENCE {
- -- might be encoded AP-REQ
- padata-type[1] PADATA-TYPE,
- padata-value[2] OCTET STRING
-}
-
-ETYPE-INFO-ENTRY ::= SEQUENCE {
- etype[0] ENCTYPE,
- salt[1] OCTET STRING OPTIONAL,
- salttype[2] krb5int32 OPTIONAL
-}
-
-ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY
-
-ETYPE-INFO2-ENTRY ::= SEQUENCE {
- etype[0] ENCTYPE,
- salt[1] KerberosString OPTIONAL,
- s2kparams[2] OCTET STRING OPTIONAL
-}
-
-ETYPE-INFO2 ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY
-
-METHOD-DATA ::= SEQUENCE OF PA-DATA
-
-TypedData ::= SEQUENCE {
- data-type[0] krb5int32,
- data-value[1] OCTET STRING OPTIONAL
-}
-
-TYPED-DATA ::= SEQUENCE SIZE (1..MAX) OF TypedData
-
-KDC-REQ-BODY ::= SEQUENCE {
- kdc-options[0] KDCOptions,
- cname[1] PrincipalName OPTIONAL, -- Used only in AS-REQ
- realm[2] Realm, -- Server's realm
- -- Also client's in AS-REQ
- sname[3] PrincipalName OPTIONAL,
- from[4] KerberosTime OPTIONAL,
- till[5] KerberosTime OPTIONAL,
- rtime[6] KerberosTime OPTIONAL,
- nonce[7] krb5int32,
- etype[8] SEQUENCE OF ENCTYPE, -- EncryptionType,
- -- in preference order
- addresses[9] HostAddresses OPTIONAL,
- enc-authorization-data[10] EncryptedData OPTIONAL,
- -- Encrypted AuthorizationData encoding
- additional-tickets[11] SEQUENCE OF Ticket OPTIONAL
-}
-
-KDC-REQ ::= SEQUENCE {
- pvno[1] krb5int32,
- msg-type[2] MESSAGE-TYPE,
- padata[3] METHOD-DATA OPTIONAL,
- req-body[4] KDC-REQ-BODY
-}
-
-AS-REQ ::= [APPLICATION 10] KDC-REQ
-TGS-REQ ::= [APPLICATION 12] KDC-REQ
-
--- padata-type ::= PA-ENC-TIMESTAMP
--- padata-value ::= EncryptedData - PA-ENC-TS-ENC
-
-PA-ENC-TS-ENC ::= SEQUENCE {
- patimestamp[0] KerberosTime, -- client's time
- pausec[1] krb5int32 OPTIONAL
-}
-
--- draft-brezak-win2k-krb-authz-01
-PA-PAC-REQUEST ::= SEQUENCE {
- include-pac[0] BOOLEAN -- Indicates whether a PAC
- -- should be included or not
-}
-
--- PacketCable provisioning server location, PKT-SP-SEC-I09-030728.pdf
-PROV-SRV-LOCATION ::= GeneralString
-
-KDC-REP ::= SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE,
- padata[2] METHOD-DATA OPTIONAL,
- crealm[3] Realm,
- cname[4] PrincipalName,
- ticket[5] Ticket,
- enc-part[6] EncryptedData
-}
-
-AS-REP ::= [APPLICATION 11] KDC-REP
-TGS-REP ::= [APPLICATION 13] KDC-REP
-
-EncKDCRepPart ::= SEQUENCE {
- key[0] EncryptionKey,
- last-req[1] LastReq,
- nonce[2] krb5int32,
- key-expiration[3] KerberosTime OPTIONAL,
- flags[4] TicketFlags,
- authtime[5] KerberosTime,
- starttime[6] KerberosTime OPTIONAL,
- endtime[7] KerberosTime,
- renew-till[8] KerberosTime OPTIONAL,
- srealm[9] Realm,
- sname[10] PrincipalName,
- caddr[11] HostAddresses OPTIONAL,
- encrypted-pa-data[12] METHOD-DATA OPTIONAL
-}
-
-EncASRepPart ::= [APPLICATION 25] EncKDCRepPart
-EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart
-
-AP-REQ ::= [APPLICATION 14] SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE,
- ap-options[2] APOptions,
- ticket[3] Ticket,
- authenticator[4] EncryptedData
-}
-
-AP-REP ::= [APPLICATION 15] SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE,
- enc-part[2] EncryptedData
-}
-
-EncAPRepPart ::= [APPLICATION 27] SEQUENCE {
- ctime[0] KerberosTime,
- cusec[1] krb5int32,
- subkey[2] EncryptionKey OPTIONAL,
- seq-number[3] krb5uint32 OPTIONAL
-}
-
-KRB-SAFE-BODY ::= SEQUENCE {
- user-data[0] OCTET STRING,
- timestamp[1] KerberosTime OPTIONAL,
- usec[2] krb5int32 OPTIONAL,
- seq-number[3] krb5uint32 OPTIONAL,
- s-address[4] HostAddress OPTIONAL,
- r-address[5] HostAddress OPTIONAL
-}
-
-KRB-SAFE ::= [APPLICATION 20] SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE,
- safe-body[2] KRB-SAFE-BODY,
- cksum[3] Checksum
-}
-
-KRB-PRIV ::= [APPLICATION 21] SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE,
- enc-part[3] EncryptedData
-}
-EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE {
- user-data[0] OCTET STRING,
- timestamp[1] KerberosTime OPTIONAL,
- usec[2] krb5int32 OPTIONAL,
- seq-number[3] krb5uint32 OPTIONAL,
- s-address[4] HostAddress OPTIONAL, -- sender's addr
- r-address[5] HostAddress OPTIONAL -- recip's addr
-}
-
-KRB-CRED ::= [APPLICATION 22] SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE, -- KRB_CRED
- tickets[2] SEQUENCE OF Ticket,
- enc-part[3] EncryptedData
-}
-
-KrbCredInfo ::= SEQUENCE {
- key[0] EncryptionKey,
- prealm[1] Realm OPTIONAL,
- pname[2] PrincipalName OPTIONAL,
- flags[3] TicketFlags OPTIONAL,
- authtime[4] KerberosTime OPTIONAL,
- starttime[5] KerberosTime OPTIONAL,
- endtime[6] KerberosTime OPTIONAL,
- renew-till[7] KerberosTime OPTIONAL,
- srealm[8] Realm OPTIONAL,
- sname[9] PrincipalName OPTIONAL,
- caddr[10] HostAddresses OPTIONAL
-}
-
-EncKrbCredPart ::= [APPLICATION 29] SEQUENCE {
- ticket-info[0] SEQUENCE OF KrbCredInfo,
- nonce[1] krb5int32 OPTIONAL,
- timestamp[2] KerberosTime OPTIONAL,
- usec[3] krb5int32 OPTIONAL,
- s-address[4] HostAddress OPTIONAL,
- r-address[5] HostAddress OPTIONAL
-}
-
-KRB-ERROR ::= [APPLICATION 30] SEQUENCE {
- pvno[0] krb5int32,
- msg-type[1] MESSAGE-TYPE,
- ctime[2] KerberosTime OPTIONAL,
- cusec[3] krb5int32 OPTIONAL,
- stime[4] KerberosTime,
- susec[5] krb5int32,
- error-code[6] krb5int32,
- crealm[7] Realm OPTIONAL,
- cname[8] PrincipalName OPTIONAL,
- realm[9] Realm, -- Correct realm
- sname[10] PrincipalName, -- Correct name
- e-text[11] GeneralString OPTIONAL,
- e-data[12] OCTET STRING OPTIONAL
-}
-
-ChangePasswdDataMS ::= SEQUENCE {
- newpasswd[0] OCTET STRING,
- targname[1] PrincipalName OPTIONAL,
- targrealm[2] Realm OPTIONAL
-}
-
-EtypeList ::= SEQUENCE OF krb5int32
- -- the client's proposed enctype list in
- -- decreasing preference order, favorite choice first
-
-krb5-pvno krb5int32 ::= 5 -- current Kerberos protocol version number
-
--- transited encodings
-
-DOMAIN-X500-COMPRESS krb5int32 ::= 1
-
--- authorization data primitives
-
-AD-IF-RELEVANT ::= AuthorizationData
-
-AD-KDCIssued ::= SEQUENCE {
- ad-checksum[0] Checksum,
- i-realm[1] Realm OPTIONAL,
- i-sname[2] PrincipalName OPTIONAL,
- elements[3] AuthorizationData
-}
-
-AD-AND-OR ::= SEQUENCE {
- condition-count[0] INTEGER,
- elements[1] AuthorizationData
-}
-
-AD-MANDATORY-FOR-KDC ::= AuthorizationData
-
--- PA-SAM-RESPONSE-2/PA-SAM-RESPONSE-2
-
-PA-SAM-TYPE ::= INTEGER {
- PA_SAM_TYPE_ENIGMA(1), -- Enigma Logic
- PA_SAM_TYPE_DIGI_PATH(2), -- Digital Pathways
- PA_SAM_TYPE_SKEY_K0(3), -- S/key where KDC has key 0
- PA_SAM_TYPE_SKEY(4), -- Traditional S/Key
- PA_SAM_TYPE_SECURID(5), -- Security Dynamics
- PA_SAM_TYPE_CRYPTOCARD(6) -- CRYPTOCard
-}
-
-PA-SAM-REDIRECT ::= HostAddresses
-
-SAMFlags ::= BIT STRING {
- use-sad-as-key(0),
- send-encrypted-sad(1),
- must-pk-encrypt-sad(2)
-}
-
-PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE {
- sam-type[0] krb5int32,
- sam-flags[1] SAMFlags,
- sam-type-name[2] GeneralString OPTIONAL,
- sam-track-id[3] GeneralString OPTIONAL,
- sam-challenge-label[4] GeneralString OPTIONAL,
- sam-challenge[5] GeneralString OPTIONAL,
- sam-response-prompt[6] GeneralString OPTIONAL,
- sam-pk-for-sad[7] EncryptionKey OPTIONAL,
- sam-nonce[8] krb5int32,
- sam-etype[9] krb5int32,
- ...
-}
-
-PA-SAM-CHALLENGE-2 ::= SEQUENCE {
- sam-body[0] PA-SAM-CHALLENGE-2-BODY,
- sam-cksum[1] SEQUENCE OF Checksum, -- (1..MAX)
- ...
-}
-
-PA-SAM-RESPONSE-2 ::= SEQUENCE {
- sam-type[0] krb5int32,
- sam-flags[1] SAMFlags,
- sam-track-id[2] GeneralString OPTIONAL,
- sam-enc-nonce-or-sad[3] EncryptedData, -- PA-ENC-SAM-RESPONSE-ENC
- sam-nonce[4] krb5int32,
- ...
-}
-
-PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE {
- sam-nonce[0] krb5int32,
- sam-sad[1] GeneralString OPTIONAL,
- ...
-}
-
-PA-S4U2Self ::= SEQUENCE {
- name[0] PrincipalName,
- realm[1] Realm,
- cksum[2] Checksum,
- auth[3] GeneralString
-}
-
-KRB5SignedPathPrincipals ::= SEQUENCE OF Principal
-
--- never encoded on the wire, just used to checksum over
-KRB5SignedPathData ::= SEQUENCE {
- encticket[0] EncTicketPart,
- delegated[1] KRB5SignedPathPrincipals OPTIONAL
-}
-
-KRB5SignedPath ::= SEQUENCE {
- -- DERcoded KRB5SignedPathData
- -- krbtgt key (etype), KeyUsage = XXX
- etype[0] ENCTYPE,
- cksum[1] Checksum,
- -- srvs delegated though
- delegated[2] KRB5SignedPathPrincipals OPTIONAL
-}
-
-PA-ClientCanonicalizedNames ::= SEQUENCE{
- requested-name [0] PrincipalName,
- mapped-name [1] PrincipalName
-}
-
-PA-ClientCanonicalized ::= SEQUENCE {
- names [0] PA-ClientCanonicalizedNames,
- canon-checksum [1] Checksum
-}
-
-AD-LoginAlias ::= SEQUENCE { -- ad-type number TBD --
- login-alias [0] PrincipalName,
- checksum [1] Checksum
-}
-
--- old ms referral
-PA-SvrReferralData ::= SEQUENCE {
- referred-name [1] PrincipalName OPTIONAL,
- referred-realm [0] Realm
-}
-
-PA-SERVER-REFERRAL-DATA ::= EncryptedData
-
-PA-ServerReferralData ::= SEQUENCE {
- referred-realm [0] Realm OPTIONAL,
- true-principal-name [1] PrincipalName OPTIONAL,
- requested-principal-name [2] PrincipalName OPTIONAL,
- referral-valid-until [3] KerberosTime OPTIONAL,
- ...
-}
-
-END
-
--- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1
KX509 DEFINITIONS ::=
BEGIN
+KX509-ERROR-CODE ::= INTEGER {
+ KX509-STATUS-GOOD(0),
+ KX509-STATUS-CLIENT-BAD(1),
+ KX509-STATUS-CLIENT-FIX(2),
+ KX509-STATUS-CLIENT-TEMP(3),
+ KX509-STATUS-SERVER-BAD(4),
+ KX509-STATUS-SERVER-TEMP(5),
+ -- 6 is used internally in the umich client, avoid that
+ KX509-STATUS-SERVER-KEY(7)
+}
+
Kx509Request ::= SEQUENCE {
authenticator OCTET STRING,
pk-hash OCTET STRING,
return 0;
}
-int dce_fix;
+int support_ber;
int rfc1510_bitstring;
+int one_code_file;
+char *option_file;
int version_flag;
int help_flag;
struct getargs args[] = {
{ "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring },
- { "decode-dce-ber", 0, arg_flag, &dce_fix },
+ { "decode-dce-ber", 0, arg_flag, &support_ber },
+ { "support-ber", 0, arg_flag, &support_ber },
{ "preserve-binary", 0, arg_strings, &preserve },
{ "sequence", 0, arg_strings, &seq },
+ { "one-code-file", 0, arg_flag, &one_code_file },
+ { "option-file", 0, arg_string, &option_file },
{ "version", 0, arg_flag, &version_flag },
{ "help", 0, arg_flag, &help_flag }
};
const char *file;
const char *name = NULL;
int optidx = 0;
+ char **arg = NULL;
+ size_t len = 0, i;
setprogname(argv[0]);
if(getarg(args, num_args, argc, argv, &optidx))
name = argv[optidx + 1];
}
+ /*
+ * Parse extra options file
+ */
+ if (option_file) {
+ char buf[1024];
+ FILE *opt;
+
+ opt = fopen(option_file, "r");
+ if (opt == NULL) {
+ perror("open");
+ exit(1);
+ }
+
+ arg = calloc(2, sizeof(arg[0]));
+ arg[0] = option_file;
+ arg[1] = NULL;
+ len = 1;
+
+ while (fgets(buf, sizeof(buf), opt) != NULL) {
+ buf[strcspn(buf, "\n\r")] = '\0';
+
+ arg = realloc(arg, (len + 2) * sizeof(arg[0]));
+ if (argv == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ arg[len] = strdup(buf);
+ if (arg[len] == NULL) {
+ perror("strdup");
+ exit(1);
+ }
+ arg[len + 1] = NULL;
+ len++;
+ }
+ fclose(opt);
+
+ optidx = 0;
+ if(getarg(args, num_args, len, arg, &optidx))
+ usage(1);
+
+ if (len != optidx) {
+ fprintf(stderr, "extra args");
+ exit(1);
+ }
+ }
+
+
init_generate (file, name);
+
+ if (one_code_file)
+ generate_header_of_codefile(name);
+
initsym ();
ret = yyparse ();
if(ret != 0 || error_flag != 0)
close_generate ();
if (argc != optidx)
fclose(yyin);
+
+ if (one_code_file)
+ close_codefile();
+
+ if (arg) {
+ for (i = 1; i < len; i++)
+ free(arg[i]);
+ free(arg);
+ }
+
return 0;
}
/* $Id$ */
%{
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
encKeyPack [1] IMPLICIT OCTET STRING
}
-
KDCDHKeyInfo-Win2k ::= SEQUENCE {
nonce [0] INTEGER (-2147483648..2147483647),
subjectPublicKey [2] BIT STRING
...
}
+PA-PK-AS-REP-BTMM ::= SEQUENCE {
+ dhSignedData [0] heim_any OPTIONAL,
+ encKeyPack [1] heim_any OPTIONAL
+}
+
+
PkinitSP80056AOtherInfo ::= SEQUENCE {
algorithmID AlgorithmIdentifier,
partyUInfo [0] OCTET STRING,
iso(1) member-body(2) us(840) ansi-x942(10046)
number-type(2) 1 }
+-- ECC
+
+id-ecPublicKey OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
+
+id-ecDH OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) schemes(1)
+ ecdh(12) }
+
+id-ecMQV OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) schemes(1)
+ ecmqv(13) }
+
+id-ecdsa-with-SHA256 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
+ ecdsa-with-SHA2(3) 2 }
+
+id-ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 }
+
+-- some EC group ids
+
+id-ec-group-secp256r1 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
+ prime(1) 7 }
+
+id-ec-group-secp160r1 OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) 0 8 }
+
+id-ec-group-secp160r2 OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) 0 30 }
+
+-- DSA
+
id-x9-57 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) ansi-x942(10046)
- 4 }
+ iso(1) member-body(2) us(840) ansi-x942(10046) 4 }
id-dsa OBJECT IDENTIFIER ::= { id-x9-57 1 }
id-dsa-with-sha1 OBJECT IDENTIFIER ::= { id-x9-57 3 }
g INTEGER
}
+-- draft-ietf-pkix-ecc-subpubkeyinfo-11
+
+ECPoint ::= OCTET STRING
+
+ECParameters ::= CHOICE {
+ namedCurve OBJECT IDENTIFIER
+ -- implicitCurve NULL
+ -- specifiedCurve SpecifiedECDomain
+}
+
+ECDSA-Sig-Value ::= SEQUENCE {
+ r INTEGER,
+ s INTEGER
+}
+
-- really pkcs1
RSAPublicKey ::= SEQUENCE {
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-RCSID("$Id$");
-#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "compile_et.h"
#include <getarg.h>
-RCSID("$Id$");
-
#include <roken.h>
#include <err.h>
#include "parse.h"
#ifndef __COMPILE_ET_H__
#define __COMPILE_ET_H__
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <err.h>
#include <stdio.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-RCSID("$Id$");
-#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parse.h"
#include "lex.h"
-RCSID("$Id$");
-
static unsigned lineno = 1;
static int getstring(void);
#include "compile_et.h"
#include "lex.h"
-RCSID("$Id$");
-
void yyerror (char *s);
static long name2number(const char *str);
#endif
#endif
+#ifndef GSSAPI_DEPRECATED
+#define GSSAPI_DEPRECATED __attribute__((deprecated))
+#endif
+
/*
* Now define the three implementation-dependent types.
*/
gss_buffer_desc *elements;
} gss_buffer_set_desc, *gss_buffer_set_t;
+typedef struct gss_iov_buffer_desc_struct {
+ OM_uint32 type;
+ gss_buffer_desc buffer;
+} gss_iov_buffer_desc, *gss_iov_buffer_t;
+
/*
* For now, define a QOP-type as an OM_uint32
*/
#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
#define GSS_C_EMPTY_BUFFER {0, NULL}
+#define GSS_C_NO_IOV_BUFFER ((gss_iov_buffer_t)0)
/*
* Some alternate names for a couple of the above
*/
#define GSS_C_INDEFINITE 0xfffffffful
+/*
+ * Type of gss_wrap_iov()/gss_unwrap_iov().
+ */
+
+#define GSS_IOV_BUFFER_TYPE_EMPTY 0
+#define GSS_IOV_BUFFER_TYPE_DATA 1
+#define GSS_IOV_BUFFER_TYPE_HEADER 2
+#define GSS_IOV_BUFFER_TYPE_MECH_PARAMS 3
+
+#define GSS_IOV_BUFFER_TYPE_TRAILER 7
+#define GSS_IOV_BUFFER_TYPE_PADDING 9
+#define GSS_IOV_BUFFER_TYPE_STREAM 10
+#define GSS_IOV_BUFFER_TYPE_SIGN_ONLY 11
+
+#define GSS_IOV_BUFFER_TYPE_FLAG_MASK 0xffff0000
+#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE 0x00010000
+#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED 0x00020000
+
+#define GSS_IOV_BUFFER_TYPE(_t) ((_t) & ~GSS_IOV_BUFFER_TYPE_FLAG_MASK)
+#define GSS_IOV_BUFFER_FLAGS(_t) ((_t) & GSS_IOV_BUFFER_TYPE_FLAG_MASK)
+
#ifdef __cplusplus
extern "C" {
#endif
extern GSSAPI_LIB_VARIABLE gss_OID GSS_SASL_DIGEST_MD5_MECHANISM;
-/*
- * NTLM mechanism
- */
-
-extern GSSAPI_LIB_VARIABLE gss_OID GSS_NTLM_MECHANISM;
-
/* Major status codes */
#define GSS_S_COMPLETE 0
gss_buffer_t prf_out
);
+/*
+ * AEAD support
+ */
+
+OM_uint32 GSSAPI_LIB_FUNCTION
+gss_wrap_iov(OM_uint32 * /* minor_status */,
+ gss_ctx_id_t /* context_handle */,
+ int /* conf_req_flag */,
+ gss_qop_t /* qop_req */,
+ int * /* conf_state */,
+ gss_iov_buffer_desc * /*iov */,
+ int /* iov_count */);
+
+OM_uint32 GSSAPI_LIB_FUNCTION
+gss_unwrap_iov(OM_uint32 * /* minor_status */,
+ gss_ctx_id_t /* context_handle */,
+ int * /* conf_state */,
+ gss_qop_t * /* qop_state */,
+ gss_iov_buffer_desc * /* iov */,
+ int /* iov_count */);
+
+OM_uint32 GSSAPI_LIB_FUNCTION
+gss_wrap_iov_length(OM_uint32 * /* minor_status */,
+ gss_ctx_id_t /* context_handle */,
+ int /* conf_req_flag */,
+ gss_qop_t /* qop_req */,
+ int * /* conf_state */,
+ gss_iov_buffer_desc * /* iov */,
+ int /* iov_count */);
+
+OM_uint32 GSSAPI_LIB_FUNCTION
+gss_release_iov_buffer(OM_uint32 * /* minor_status */,
+ gss_iov_buffer_desc * /* iov */,
+ int /* iov_count */);
+
+
+OM_uint32
+gss_store_cred(OM_uint32 * /* minor_status */,
+ gss_cred_id_t /* input_cred_handle */,
+ gss_cred_usage_t /* cred_usage */,
+ const gss_OID /* desired_mech */,
+ OM_uint32 /* overwrite_cred */,
+ OM_uint32 /* default_cred */,
+ gss_OID_set * /* elements_stored */,
+ gss_cred_usage_t * /* cred_usage_stored */);
+
+
+/*
+ * Query functions
+ */
+
+typedef struct {
+ size_t header; /**< size of header */
+ size_t trailer; /**< size of trailer */
+ size_t max_msg_size; /**< maximum message size */
+ size_t buffers; /**< extra GSS_IOV_BUFFER_TYPE_EMPTY buffer to pass */
+ size_t blocksize; /**< Specificed optimal size of messages, also
+ is the maximum padding size
+ (GSS_IOV_BUFFER_TYPE_PADDING) */
+} gss_context_stream_sizes;
+
+extern gss_OID GSSAPI_LIB_VARIABLE GSS_C_ATTR_STREAM_SIZES;
+
+
+OM_uint32 GSSAPI_LIB_FUNCTION
+gss_context_query_attributes(OM_uint32 * /* minor_status */,
+ gss_OID /* attribute */,
+ void * /*data*/,
+ size_t /* len */);
/*
* The following routines are obsolete variants of gss_get_mic,
* gss_verify_mic, gss_wrap and gss_unwrap. They should be
* obsolete versions of these routines and their current forms.
*/
-OM_uint32 GSSAPI_LIB_FUNCTION gss_sign
+OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_sign
(OM_uint32 * /*minor_status*/,
gss_ctx_id_t /*context_handle*/,
int /*qop_req*/,
gss_buffer_t /*message_token*/
);
-OM_uint32 GSSAPI_LIB_FUNCTION gss_verify
+OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_verify
(OM_uint32 * /*minor_status*/,
gss_ctx_id_t /*context_handle*/,
gss_buffer_t /*message_buffer*/,
int * /*qop_state*/
);
-OM_uint32 GSSAPI_LIB_FUNCTION gss_seal
+OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_seal
(OM_uint32 * /*minor_status*/,
gss_ctx_id_t /*context_handle*/,
int /*conf_req_flag*/,
gss_buffer_t /*output_message_buffer*/
);
-OM_uint32 GSSAPI_LIB_FUNCTION gss_unseal
+OM_uint32 GSSAPI_LIB_FUNCTION GSSAPI_DEPRECATED gss_unseal
(OM_uint32 * /*minor_status*/,
gss_ctx_id_t /*context_handle*/,
gss_buffer_t /*input_message_buffer*/,
}
#endif
-#include <gssapi/gssapi_krb5.h>
-#include <gssapi/gssapi_spnego.h>
-
#endif /* GSSAPI_GSSAPI_H_ */
#ifndef GSSAPI_KRB5_H_
#define GSSAPI_KRB5_H_
-#include <gssapi/gssapi.h>
+#include <gssapi.h>
#ifdef __cplusplus
extern "C" {
gss_buffer_t prf_out
);
-#define GMI_VERSION 1
+typedef OM_uint32
+_gss_wrap_iov_t(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int * conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+typedef OM_uint32
+_gss_unwrap_iov_t(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+typedef OM_uint32
+_gss_wrap_iov_length_t(OM_uint32 * minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+typedef OM_uint32
+_gss_store_cred_t(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored);
+
+
+
+#define GMI_VERSION 2
typedef struct gssapi_mech_interface_desc {
unsigned gm_version;
_gss_set_sec_context_option *gm_set_sec_context_option;
_gss_set_cred_option *gm_set_cred_option;
_gss_pseudo_random *gm_pseudo_random;
+ _gss_wrap_iov_t *gm_wrap_iov;
+ _gss_unwrap_iov_t *gm_unwrap_iov;
+ _gss_wrap_iov_length_t *gm_wrap_iov_length;
+ _gss_store_cred_t *gm_store_cred;
} gssapi_mech_interface_desc, *gssapi_mech_interface;
gssapi_mech_interface
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
}
void
-_gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx)
+_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor)
{
+ krb5_error_code ret;
krb5_keyblock *key;
- int acceptor = (ctx->more_flags & LOCAL) == 0;
-
- *is_cfx = 0;
if (acceptor) {
if (ctx->auth_context->local_subkey)
case ETYPE_ARCFOUR_HMAC_MD5_56:
break;
default :
- *is_cfx = 1;
+ ctx->more_flags |= IS_CFX;
+
if ((acceptor && ctx->auth_context->local_subkey) ||
(!acceptor && ctx->auth_context->remote_subkey))
ctx->more_flags |= ACCEPTOR_SUBKEY;
break;
}
+ if (ctx->crypto)
+ krb5_crypto_destroy(context, ctx->crypto);
+ ret = krb5_crypto_init(context, key, 0, &ctx->crypto);
}
ctx->auth_context,
&seq_number);
- _gsskrb5i_is_cfx(ctx, &is_cfx);
+ _gsskrb5i_is_cfx(context, ctx, 1);
+ is_cfx = (ctx->more_flags & IS_CFX);
ret = _gssapi_msg_order_create(minor_status,
&ctx->order,
krb5_data outbuf;
int use_subkey = 0;
- _gsskrb5i_is_cfx(ctx, &is_cfx);
+ _gsskrb5i_is_cfx(context, ctx, 1);
+ is_cfx = (ctx->more_flags & IS_CFX);
if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
use_subkey = 1;
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
#include <roken.h>
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
return 0;
}
-krb5_error_code
-_gsskrb5cfx_max_wrap_length_cfx(krb5_context context,
- krb5_crypto crypto,
+OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
+ const gsskrb5_ctx ctx,
+ krb5_context context,
int conf_req_flag,
- size_t input_length,
- OM_uint32 *output_length)
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
{
krb5_error_code ret;
- *output_length = 0;
+ *max_input_size = 0;
/* 16-byte header is always first */
- if (input_length < 16)
+ if (req_output_size < 16)
return 0;
- input_length -= 16;
+ req_output_size -= 16;
if (conf_req_flag) {
size_t wrapped_size, sz;
- wrapped_size = input_length + 1;
+ wrapped_size = req_output_size + 1;
do {
wrapped_size--;
sz = krb5_get_wrapped_length(context,
- crypto, wrapped_size);
- } while (wrapped_size && sz > input_length);
- if (wrapped_size == 0) {
- *output_length = 0;
+ ctx->crypto, wrapped_size);
+ } while (wrapped_size && sz > req_output_size);
+ if (wrapped_size == 0)
return 0;
- }
/* inner header */
- if (wrapped_size < 16) {
- *output_length = 0;
+ if (wrapped_size < 16)
return 0;
- }
+
wrapped_size -= 16;
- *output_length = wrapped_size;
+ *max_input_size = wrapped_size;
} else {
krb5_cksumtype type;
size_t cksumsize;
- ret = krb5_crypto_get_checksum_type(context, crypto, &type);
+ ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);
if (ret)
return ret;
if (ret)
return ret;
- if (input_length < cksumsize)
+ if (req_output_size < cksumsize)
return 0;
/* Checksum is concatenated with data */
- *output_length = input_length - cksumsize;
+ *max_input_size = req_output_size - cksumsize;
}
return 0;
}
-
-OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
- const gsskrb5_ctx context_handle,
- krb5_context context,
- int conf_req_flag,
- gss_qop_t qop_req,
- OM_uint32 req_output_size,
- OM_uint32 *max_input_size,
- krb5_keyblock *key)
-{
- krb5_error_code ret;
- krb5_crypto crypto;
-
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret != 0) {
- *minor_status = ret;
- return GSS_S_FAILURE;
- }
-
- ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag,
- req_output_size, max_input_size);
- if (ret != 0) {
- *minor_status = ret;
- krb5_crypto_destroy(context, crypto);
- return GSS_S_FAILURE;
- }
-
- krb5_crypto_destroy(context, crypto);
-
- return GSS_S_COMPLETE;
-}
-
/*
* Rotate "rrc" bytes to the front or back
*/
}
OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
- const gsskrb5_ctx context_handle,
+ const gsskrb5_ctx ctx,
krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
const gss_buffer_t input_message_buffer,
int *conf_state,
- gss_buffer_t output_message_buffer,
- krb5_keyblock *key)
+ gss_buffer_t output_message_buffer)
{
- krb5_crypto crypto;
gss_cfx_wrap_token token;
krb5_error_code ret;
unsigned usage;
int32_t seq_number;
u_char *p;
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret != 0) {
- *minor_status = ret;
- return GSS_S_FAILURE;
- }
-
- ret = _gsskrb5cfx_wrap_length_cfx(context_handle, context,
- crypto, conf_req_flag,
+ ret = _gsskrb5cfx_wrap_length_cfx(ctx, context,
+ ctx->crypto, conf_req_flag,
input_message_buffer->length,
&wrapped_len, &cksumsize, &padlength);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
output_message_buffer->value = malloc(output_message_buffer->length);
if (output_message_buffer->value == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
token->TOK_ID[1] = 0x04;
token->Flags = 0;
token->Filler = 0xFF;
- if ((context_handle->more_flags & LOCAL) == 0)
+ if ((ctx->more_flags & LOCAL) == 0)
token->Flags |= CFXSentByAcceptor;
- if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+ if (ctx->more_flags & ACCEPTOR_SUBKEY)
token->Flags |= CFXAcceptorSubkey;
if (conf_req_flag) {
/*
token->RRC[0] = 0;
token->RRC[1] = 0;
- HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
krb5_auth_con_getlocalseqnumber(context,
- context_handle->auth_context,
+ ctx->auth_context,
&seq_number);
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
krb5_auth_con_setlocalseqnumber(context,
- context_handle->auth_context,
+ ctx->auth_context,
++seq_number);
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
/*
* If confidentiality is requested, the token header is
* calculated over the plaintext concatenated with the
* token header.
*/
- if (context_handle->more_flags & LOCAL) {
+ if (ctx->more_flags & LOCAL) {
usage = KRB5_KU_USAGE_INITIATOR_SEAL;
} else {
usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
memcpy(p + input_message_buffer->length + padlength,
token, sizeof(*token));
- ret = krb5_encrypt(context, crypto,
+ ret = krb5_encrypt(context, ctx->crypto,
usage, p,
input_message_buffer->length + padlength +
sizeof(*token),
&cipher);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_FAILURE;
}
* this is really ugly, but needed against windows
* for DCERPC, as windows rotates by EC+RRC.
*/
- if (IS_DCE_STYLE(context_handle)) {
+ if (IS_DCE_STYLE(ctx)) {
ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
} else {
ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
}
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_FAILURE;
}
buf = malloc(input_message_buffer->length + sizeof(*token));
if (buf == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_FAILURE;
}
memcpy(buf, input_message_buffer->value, input_message_buffer->length);
memcpy(buf + input_message_buffer->length, token, sizeof(*token));
- ret = krb5_create_checksum(context, crypto,
+ ret = krb5_create_checksum(context, ctx->crypto,
usage, 0, buf,
input_message_buffer->length +
sizeof(*token),
&cksum);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
free(buf);
return GSS_S_FAILURE;
input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
free_Checksum(&cksum);
return GSS_S_FAILURE;
free_Checksum(&cksum);
}
- krb5_crypto_destroy(context, crypto);
-
if (conf_state != NULL) {
*conf_state = conf_req_flag;
}
}
OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
- const gsskrb5_ctx context_handle,
+ const gsskrb5_ctx ctx,
krb5_context context,
const gss_buffer_t input_message_buffer,
gss_buffer_t output_message_buffer,
int *conf_state,
- gss_qop_t *qop_state,
- krb5_keyblock *key)
+ gss_qop_t *qop_state)
{
- krb5_crypto crypto;
gss_cfx_wrap_token token;
u_char token_flags;
krb5_error_code ret;
(CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
if (token_flags & CFXSentByAcceptor) {
- if ((context_handle->more_flags & LOCAL) == 0)
+ if ((ctx->more_flags & LOCAL) == 0)
return GSS_S_DEFECTIVE_TOKEN;
}
- if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+ if (ctx->more_flags & ACCEPTOR_SUBKEY) {
if ((token_flags & CFXAcceptorSubkey) == 0)
return GSS_S_DEFECTIVE_TOKEN;
} else {
return GSS_S_UNSEQ_TOKEN;
}
- HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
if (ret != 0) {
*minor_status = 0;
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return ret;
}
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
/*
* Decrypt and/or verify checksum
*/
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret != 0) {
- *minor_status = ret;
- return GSS_S_FAILURE;
- }
- if (context_handle->more_flags & LOCAL) {
+ if (ctx->more_flags & LOCAL) {
usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
} else {
usage = KRB5_KU_USAGE_INITIATOR_SEAL;
* this is really ugly, but needed against windows
* for DCERPC, as windows rotates by EC+RRC.
*/
- if (IS_DCE_STYLE(context_handle)) {
+ if (IS_DCE_STYLE(ctx)) {
*minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
} else {
*minor_status = rrc_rotate(p, len, rrc, TRUE);
}
if (*minor_status != 0) {
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
- ret = krb5_decrypt(context, crypto, usage,
+ ret = krb5_decrypt(context, ctx->crypto, usage,
p, len, &data);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
return GSS_S_BAD_MIC;
}
/* Check that there is room for the pad and token header */
if (data.length < ec + sizeof(*token)) {
- krb5_crypto_destroy(context, crypto);
krb5_data_free(&data);
return GSS_S_DEFECTIVE_TOKEN;
}
/* Check the integrity of the header */
if (memcmp(p, token, sizeof(*token)) != 0) {
- krb5_crypto_destroy(context, crypto);
krb5_data_free(&data);
return GSS_S_BAD_MIC;
}
/* Rotate by RRC; bogus to do this in-place XXX */
*minor_status = rrc_rotate(p, len, rrc, TRUE);
if (*minor_status != 0) {
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
/* Determine checksum type */
ret = krb5_crypto_get_checksum_type(context,
- crypto, &cksum.cksumtype);
+ ctx->crypto,
+ &cksum.cksumtype);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
/* Check we have at least as much data as the checksum */
if (len < cksum.checksum.length) {
*minor_status = ERANGE;
- krb5_crypto_destroy(context, crypto);
return GSS_S_BAD_MIC;
}
output_message_buffer->value = malloc(len + sizeof(*token));
if (output_message_buffer->value == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
token->RRC[0] = 0;
token->RRC[1] = 0;
- ret = krb5_verify_checksum(context, crypto,
+ ret = krb5_verify_checksum(context, ctx->crypto,
usage,
output_message_buffer->value,
len + sizeof(*token),
&cksum);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
_gsskrb5_release_buffer(minor_status, output_message_buffer);
return GSS_S_BAD_MIC;
}
}
- krb5_crypto_destroy(context, crypto);
-
if (qop_state != NULL) {
*qop_state = GSS_C_QOP_DEFAULT;
}
}
OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
- const gsskrb5_ctx context_handle,
+ const gsskrb5_ctx ctx,
krb5_context context,
gss_qop_t qop_req,
const gss_buffer_t message_buffer,
- gss_buffer_t message_token,
- krb5_keyblock *key)
+ gss_buffer_t message_token)
{
- krb5_crypto crypto;
gss_cfx_mic_token token;
krb5_error_code ret;
unsigned usage;
size_t len;
int32_t seq_number;
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret != 0) {
- *minor_status = ret;
- return GSS_S_FAILURE;
- }
-
len = message_buffer->length + sizeof(*token);
buf = malloc(len);
if (buf == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
token->TOK_ID[0] = 0x04;
token->TOK_ID[1] = 0x04;
token->Flags = 0;
- if ((context_handle->more_flags & LOCAL) == 0)
+ if ((ctx->more_flags & LOCAL) == 0)
token->Flags |= CFXSentByAcceptor;
- if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+ if (ctx->more_flags & ACCEPTOR_SUBKEY)
token->Flags |= CFXAcceptorSubkey;
memset(token->Filler, 0xFF, 5);
- HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
krb5_auth_con_getlocalseqnumber(context,
- context_handle->auth_context,
+ ctx->auth_context,
&seq_number);
_gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
_gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
krb5_auth_con_setlocalseqnumber(context,
- context_handle->auth_context,
+ ctx->auth_context,
++seq_number);
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
- if (context_handle->more_flags & LOCAL) {
+ if (ctx->more_flags & LOCAL) {
usage = KRB5_KU_USAGE_INITIATOR_SIGN;
} else {
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
}
- ret = krb5_create_checksum(context, crypto,
+ ret = krb5_create_checksum(context, ctx->crypto,
usage, 0, buf, len, &cksum);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
free(buf);
return GSS_S_FAILURE;
}
- krb5_crypto_destroy(context, crypto);
/* Determine MIC length */
message_token->length = sizeof(*token) + cksum.checksum.length;
}
OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
- const gsskrb5_ctx context_handle,
+ const gsskrb5_ctx ctx,
krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
- gss_qop_t *qop_state,
- krb5_keyblock *key)
+ gss_qop_t *qop_state)
{
- krb5_crypto crypto;
gss_cfx_mic_token token;
u_char token_flags;
krb5_error_code ret;
token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
if (token_flags & CFXSentByAcceptor) {
- if ((context_handle->more_flags & LOCAL) == 0)
+ if ((ctx->more_flags & LOCAL) == 0)
return GSS_S_DEFECTIVE_TOKEN;
}
- if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+ if (ctx->more_flags & ACCEPTOR_SUBKEY) {
if ((token_flags & CFXAcceptorSubkey) == 0)
return GSS_S_DEFECTIVE_TOKEN;
} else {
return GSS_S_UNSEQ_TOKEN;
}
- HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
if (ret != 0) {
*minor_status = 0;
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
/*
* Verify checksum
*/
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret != 0) {
- *minor_status = ret;
- return GSS_S_FAILURE;
- }
-
- ret = krb5_crypto_get_checksum_type(context, crypto,
+ ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
&cksum.cksumtype);
if (ret != 0) {
*minor_status = ret;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
cksum.checksum.data = p + sizeof(*token);
cksum.checksum.length = token_buffer->length - sizeof(*token);
- if (context_handle->more_flags & LOCAL) {
+ if (ctx->more_flags & LOCAL) {
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
} else {
usage = KRB5_KU_USAGE_INITIATOR_SIGN;
buf = malloc(message_buffer->length + sizeof(*token));
if (buf == NULL) {
*minor_status = ENOMEM;
- krb5_crypto_destroy(context, crypto);
return GSS_S_FAILURE;
}
memcpy(buf, message_buffer->value, message_buffer->length);
memcpy(buf + message_buffer->length, token, sizeof(*token));
- ret = krb5_verify_checksum(context, crypto,
+ ret = krb5_verify_checksum(context, ctx->crypto,
usage,
buf,
sizeof(*token) + message_buffer->length,
&cksum);
- krb5_crypto_destroy(context, crypto);
if (ret != 0) {
*minor_status = ret;
free(buf);
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
if (ctx->service_keyblock)
krb5_free_keyblock (context, ctx->service_keyblock);
krb5_data_free(&ctx->fwd_data);
+ if (ctx->crypto)
+ krb5_crypto_destroy(context, ctx->crypto);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
#include <gssapi_mech.h>
RCSID("$Id$");
_gsskrb5_inquire_cred_by_oid,
_gsskrb5_set_sec_context_option,
_gsskrb5_set_cred_option,
- _gsskrb5_pseudo_random
+ _gsskrb5_pseudo_random,
+ _gk_wrap_iov,
+ _gk_unwrap_iov,
+ _gk_wrap_iov_length
};
gssapi_mech_interface
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
GSSAPI_KRB5_INIT (&context);
+ if (ctx->more_flags & IS_CFX)
+ return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
+ message_buffer, message_token);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
message_buffer, message_token, key);
break;
default :
- ret = _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
- message_buffer, message_token, key);
+ abort();
break;
}
krb5_free_keyblock (context, key);
#ifndef GSSKRB5_LOCL_H
#define GSSKRB5_LOCL_H
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <krb5_locl.h>
#include <gkrb5_err.h>
#include <gssapi.h>
#include <gssapi_mech.h>
+#include <gssapi_krb5.h>
#include <assert.h>
#include "cfx.h"
struct gss_msg_order;
-typedef struct {
+typedef struct gsskrb5_ctx {
struct krb5_auth_context_data *auth_context;
krb5_principal source, target;
#define IS_DCE_STYLE(ctx) (((ctx)->flags & GSS_C_DCE_STYLE) != 0)
COMPAT_OLD_DES3_SELECTED = 8,
ACCEPTOR_SUBKEY = 16,
RETRIED = 32,
- CLOSE_CCACHE = 64
+ CLOSE_CCACHE = 64,
+ IS_CFX = 128
} more_flags;
enum gss_ctx_id_t_state {
/* initiator states */
struct gss_msg_order *order;
krb5_keyblock *service_keyblock;
krb5_data fwd_data;
+ krb5_crypto crypto;
} *gsskrb5_ctx;
typedef struct {
* Prototypes
*/
-#include <krb5/gsskrb5-private.h>
+#include <gsskrb5-private.h>
#define GSSAPI_KRB5_INIT(ctx) do { \
krb5_error_code kret_gss_init; \
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
krb5_data_zero(&ctx->fwd_data);
ctx->lifetime = GSS_C_INDEFINITE;
ctx->order = NULL;
+ ctx->crypto = NULL;
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
kret = krb5_auth_con_init (context, &ctx->auth_context);
krb5_auth_getremoteseqnumber (context, ctx->auth_context, &seq_number);
- _gsskrb5i_is_cfx(ctx, &is_cfx);
+ _gsskrb5i_is_cfx(context, ctx, 0);
+ is_cfx = (ctx->more_flags & IS_CFX);
ret = _gssapi_msg_order_create(minor_status,
&ctx->order,
krb5_error_code kret;
krb5_data indata;
krb5_ap_rep_enc_part *repl;
- int is_cfx = 0;
output_token->length = 0;
output_token->value = NULL;
krb5_free_ap_rep_enc_part (context,
repl);
- _gsskrb5i_is_cfx(ctx, &is_cfx);
- if (is_cfx) {
- krb5_keyblock *key = NULL;
-
- kret = krb5_auth_con_getremotesubkey(context,
- ctx->auth_context,
- &key);
- if (kret == 0 && key != NULL) {
- ctx->more_flags |= ACCEPTOR_SUBKEY;
- krb5_free_keyblock (context, key);
- }
- }
-
-
*minor_status = 0;
if (time_rec) {
ret = _gsskrb5_lifetime_left(minor_status,
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* mechanism.
*/
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- _gsskrb5i_is_cfx(context_handle, &is_updated);
+ is_updated = (context_handle->more_flags & IS_CFX);
if (is_updated == 0) {
krb5_keyblock *acceptor_subkey;
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- _gsskrb5i_is_cfx(context_handle, &is_cfx);
+ is_cfx = (context_handle->more_flags & IS_CFX);
sp = krb5_storage_emem();
if (sp == NULL) {
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
if (ctx->service_keyblock == NULL) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+ krb5_storage_free(sp);
_gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
*minor_status = EINVAL;
return GSS_S_FAILURE;
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
krb5_context context;
OM_uint32 ret = GSS_S_FAILURE;
gss_buffer_desc empty_buffer;
- gss_qop_t qop_state;
empty_buffer.length = 0;
empty_buffer.value = NULL;
GSSAPI_KRB5_INIT (&context);
- qop_state = GSS_C_QOP_DEFAULT;
-
ret = _gsskrb5_verify_mic_internal(minor_status,
(gsskrb5_ctx)context_handle,
context,
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
if (cred->keytab != NULL)
krb5_kt_close(context, cred->keytab);
if (cred->ccache != NULL) {
- const krb5_cc_ops *ops;
- ops = krb5_cc_get_ops(context, cred->ccache);
if (cred->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE)
krb5_cc_destroy(context, cred->ccache);
else
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* glue routine for _gsskrb5_inquire_sec_context_by_oid
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
output_message_buffer->value = NULL;
output_message_buffer->length = 0;
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
GSSAPI_KRB5_INIT (&context);
- if (qop_state != NULL)
- *qop_state = GSS_C_QOP_DEFAULT;
+ if (ctx->more_flags & IS_CFX)
+ return _gssapi_unwrap_cfx (minor_status, ctx, context,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
conf_state, qop_state, key);
break;
default :
- ret = _gssapi_unwrap_cfx (minor_status, ctx, context,
- input_message_buffer, output_message_buffer,
- conf_state, qop_state, key);
+ abort();
break;
}
krb5_free_keyblock (context, key);
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
OM_uint32
_gsskrb5_verify_mic_internal
(OM_uint32 * minor_status,
- const gsskrb5_ctx context_handle,
+ const gsskrb5_ctx ctx,
krb5_context context,
const gss_buffer_t message_buffer,
const gss_buffer_t token_buffer,
OM_uint32 ret;
krb5_keytype keytype;
- HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
- ret = _gsskrb5i_get_token_key(context_handle, context, &key);
- HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ if (ctx->more_flags & IS_CFX)
+ return _gssapi_verify_mic_cfx (minor_status, ctx,
+ context, message_buffer, token_buffer,
+ qop_state);
+
+ HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+ ret = _gsskrb5i_get_token_key(ctx, context, &key);
+ HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
krb5_enctype_to_keytype (context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_DES :
- ret = verify_mic_des (minor_status, context_handle, context,
+ ret = verify_mic_des (minor_status, ctx, context,
message_buffer, token_buffer, qop_state, key,
type);
break;
case KEYTYPE_DES3 :
- ret = verify_mic_des3 (minor_status, context_handle, context,
+ ret = verify_mic_des3 (minor_status, ctx, context,
message_buffer, token_buffer, qop_state, key,
type);
break;
case KEYTYPE_ARCFOUR :
case KEYTYPE_ARCFOUR_56 :
- ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
+ ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
context,
message_buffer, token_buffer,
qop_state, key, type);
break;
default :
- ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
- context,
- message_buffer, token_buffer, qop_state,
- key);
- break;
+ abort();
}
krb5_free_keyblock (context, key);
* SUCH DAMAGE.
*/
-#include "krb5/gsskrb5_locl.h"
+#include "gsskrb5_locl.h"
RCSID("$Id$");
GSSAPI_KRB5_INIT (&context);
+ if (ctx->more_flags & IS_CFX)
+ return _gssapi_wrap_size_cfx(minor_status, ctx, context,
+ conf_req_flag, qop_req,
+ req_output_size, max_input_size);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
break;
default :
- ret = _gssapi_wrap_size_cfx(minor_status, ctx, context,
- conf_req_flag, qop_req,
- req_output_size, max_input_size, key);
+ abort();
break;
}
krb5_free_keyblock (context, key);
krb5_keytype keytype;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
+ output_message_buffer->value = NULL;
+ output_message_buffer->length = 0;
+
GSSAPI_KRB5_INIT (&context);
+ if (ctx->more_flags & IS_CFX)
+ return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer);
+
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
output_message_buffer, key);
break;
default :
- ret = _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
- qop_req, input_message_buffer, conf_state,
- output_message_buffer, key);
+ abort();
break;
}
krb5_free_keyblock (context, key);
-#include "mech/mech_locl.h"
+#include "mech_locl.h"
#include "heim_threads.h"
RCSID("$Id$");
#include "mech_locl.h"
RCSID("$Id$");
+/**
+ * gss_canonicalize_name takes a Internal Name (IN) and converts in into a
+ * mechanism specific Mechanism Name (MN).
+ *
+ * The input name may multiple name, or generic name types.
+ *
+ * If the input_name if of the GSS_C_NT_USER_NAME, and the Kerberos
+ * mechanism is specified, the resulting MN type is a
+ * GSS_KRB5_NT_PRINCIPAL_NAME.
+ *
+ * For more information about @ref internalVSmechname.
+ *
+ * @param minor_status minor status code.
+ * @param input_name name to covert, unchanged by gss_canonicalize_name().
+ * @param mech_type the type to convert Name too.
+ * @param output_name the resulting type, release with
+ * gss_release_name(), independent of input_name.
+ *
+ * @returns a gss_error code, see gss_display_status() about printing
+ * the error code.
+ *
+ * @ingroup gssapi
+ */
+
OM_uint32 GSSAPI_LIB_FUNCTION
gss_canonicalize_name(OM_uint32 *minor_status,
const gss_name_t input_name,
gss_buffer_t message_token)
{
struct _gss_context *ctx = (struct _gss_context *) context_handle;
- gssapi_mech_interface m = ctx->gc_mech;
+ gssapi_mech_interface m;
_mg_buffer_zero(message_token);
if (ctx == NULL) {
return GSS_S_NO_CONTEXT;
}
+ m = ctx->gc_mech;
+
return (m->gm_get_mic(minor_status, ctx->gc_ctx, qop_req,
message_buffer, message_token));
}
const gss_OID input_name_type,
gss_name_t *output_name)
{
+ struct _gss_mechanism_name *mn;
gss_OID name_type = input_name_type;
- OM_uint32 major_status;
+ OM_uint32 major_status, ms;
struct _gss_name *name;
+ struct _gss_mech_switch *m;
+ gss_name_t rname;
*output_name = GSS_C_NO_NAME;
return (GSS_S_BAD_NAME);
}
+ _gss_load_mech();
+
/*
* Use GSS_NT_USER_NAME as default name type.
*/
input_name_buffer, output_name);
}
- /*
- * Only allow certain name types. This is pretty bogus - we
- * should figure out the list of supported name types using
- * gss_inquire_names_for_mech.
- */
- if (!gss_oid_equal(name_type, GSS_C_NT_USER_NAME)
- && !gss_oid_equal(name_type, GSS_C_NT_MACHINE_UID_NAME)
- && !gss_oid_equal(name_type, GSS_C_NT_STRING_UID_NAME)
- && !gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE_X)
- && !gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)
- && !gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)
- && !gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) {
- *minor_status = 0;
- return (GSS_S_BAD_NAMETYPE);
- }
*minor_status = 0;
- name = malloc(sizeof(struct _gss_name));
+ name = calloc(1, sizeof(struct _gss_name));
if (!name) {
*minor_status = ENOMEM;
return (GSS_S_FAILURE);
}
- memset(name, 0, sizeof(struct _gss_name));
+
+ SLIST_INIT(&name->gn_mn);
major_status = _gss_copy_oid(minor_status,
name_type, &name->gn_type);
major_status = _gss_copy_buffer(minor_status,
input_name_buffer, &name->gn_value);
- if (major_status) {
- gss_name_t rname = (gss_name_t)name;
- gss_release_name(minor_status, &rname);
- return (GSS_S_FAILURE);
+ if (major_status)
+ goto out;
+
+ /*
+ * Walk over the mechs and import the name into a mech name
+ * for those supported this nametype.
+ */
+
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ int present = 0;
+
+ major_status = gss_test_oid_set_member(minor_status,
+ name_type, m->gm_name_types, &present);
+
+ if (major_status || present == 0)
+ continue;
+
+ mn = malloc(sizeof(struct _gss_mechanism_name));
+ if (!mn) {
+ *minor_status = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto out;
+ }
+
+ major_status = (*m->gm_mech.gm_import_name)(minor_status,
+ &name->gn_value,
+ (name->gn_type.elements
+ ? &name->gn_type : GSS_C_NO_OID),
+ &mn->gmn_name);
+ if (major_status != GSS_S_COMPLETE) {
+ _gss_mg_error(&m->gm_mech, major_status, *minor_status);
+ free(mn);
+ goto out;
+ }
+
+ mn->gmn_mech = &m->gm_mech;
+ mn->gmn_mech_oid = &m->gm_mech_oid;
+ SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
}
- SLIST_INIT(&name->gn_mn);
+ /*
+ * If we can't find a mn for the name, bail out already here.
+ */
+
+ mn = SLIST_FIRST(&name->gn_mn);
+ if (!mn) {
+ *minor_status = 0;
+ major_status = GSS_S_NAME_NOT_MN;
+ goto out;
+ }
*output_name = (gss_name_t) name;
return (GSS_S_COMPLETE);
+
+ out:
+ rname = (gss_name_t)name;
+ gss_release_name(&ms, &rname);
+ return major_status;
}
gss_add_oid_set_member(&minor_status,
&m->gm_mech.gm_mech_oid, &_gss_mech_oids);
+ /* pick up the oid sets of names */
+
+ if (m->gm_mech.gm_inquire_names_for_mech) {
+ (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status,
+ &m->gm_mech.gm_mech_oid, &m->gm_name_types);
+ } else {
+ gss_create_empty_oid_set(&minor_status, &m->gm_name_types);
+ }
+
SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link);
return 0;
}
add_builtin(__gss_krb5_initialize());
add_builtin(__gss_spnego_initialize());
-#ifndef HEIMDAL_SMALLER
add_builtin(__gss_ntlm_initialize());
-#endif
#ifdef HAVE_DLOPEN
fp = fopen(_PATH_GSS_MECH, "r");
OPTSYM(set_sec_context_option);
OPTSYM(set_cred_option);
OPTSYM(pseudo_random);
+ OPTSYM(wrap_iov);
+ OPTSYM(unwrap_iov);
+ OPTSYM(wrap_iov_length);
SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link);
continue;
gss_buffer_t prf_out)
{
struct _gss_context *ctx = (struct _gss_context *) context;
- gssapi_mech_interface m = ctx->gc_mech;
+ gssapi_mech_interface m;
OM_uint32 major_status;
_mg_buffer_zero(prf_out);
return GSS_S_NO_CONTEXT;
}
+ m = ctx->gc_mech;
+
if (m->gm_pseudo_random == NULL)
return GSS_S_UNAVAILABLE;
gss_qop_t *qop_state)
{
struct _gss_context *ctx = (struct _gss_context *) context_handle;
- gssapi_mech_interface m = ctx->gc_mech;
+ gssapi_mech_interface m;
if (qop_state)
*qop_state = 0;
return GSS_S_NO_CONTEXT;
}
+ m = ctx->gc_mech;
+
return (m->gm_verify_mic(minor_status, ctx->gc_ctx,
message_buffer, token_buffer, qop_state));
}
gss_buffer_t output_message_buffer)
{
struct _gss_context *ctx = (struct _gss_context *) context_handle;
- gssapi_mech_interface m = ctx->gc_mech;
+ gssapi_mech_interface m;
if (conf_state)
*conf_state = 0;
return GSS_S_NO_CONTEXT;
}
+ m = ctx->gc_mech;
+
return (m->gm_wrap(minor_status, ctx->gc_ctx,
conf_req_flag, qop_req, input_message_buffer,
conf_state, output_message_buffer));
OM_uint32 *max_input_size)
{
struct _gss_context *ctx = (struct _gss_context *) context_handle;
- gssapi_mech_interface m = ctx->gc_mech;
+ gssapi_mech_interface m;
*max_input_size = 0;
if (ctx == NULL) {
return GSS_S_NO_CONTEXT;
}
+ m = ctx->gc_mech;
+
return (m->gm_wrap_size_limit(minor_status, ctx->gc_ctx,
conf_req_flag, qop_req, req_output_size, max_input_size));
}
#include <gssapi.h>
#include <gssapi_mech.h>
+#include <gssapi_krb5.h>
#include "mechqueue.h"
struct _gss_mech_switch {
SLIST_ENTRY(_gss_mech_switch) gm_link;
gss_OID_desc gm_mech_oid;
+ gss_OID_set gm_name_types;
void *gm_so;
gssapi_mech_interface_desc gm_mech;
};
* SUCH DAMAGE.
*/
-#include "spnego/spnego_locl.h"
+#include "spnego_locl.h"
RCSID("$Id$");
*get_mic = 1;
}
- if (verify_mic || get_mic) {
+ if (verify_mic || *get_mic) {
int eret;
size_t buf_len;
if (verify_mic) {
ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);
if (ret) {
- if (get_mic)
+ if (*get_mic)
send_reject (minor_status, output_token);
if (buf.value)
free(buf.value);
* SUCH DAMAGE.
*/
-#include "spnego/spnego_locl.h"
+#include "spnego_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "spnego/spnego_locl.h"
+#include "spnego_locl.h"
RCSID("$Id$");
return ret;
}
}
+ gss_release_oid_set(&junk, &m);
return ret;
}
gss_release_oid_set(&junk, &mechs);
- return GSS_S_COMPLETE;
+ return ret;
}
OM_uint32 _gss_spnego_inquire_mechs_for_name (
return gss_duplicate_name(minor_status, src_name, dest_name);
}
-OM_uint32 _gss_spnego_sign
- (OM_uint32 * minor_status,
- gss_ctx_id_t context_handle,
- int qop_req,
- gss_buffer_t message_buffer,
- gss_buffer_t message_token
- )
-{
- gssspnego_ctx ctx;
-
- *minor_status = 0;
-
- if (context_handle == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- ctx = (gssspnego_ctx)context_handle;
-
- if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- return gss_sign(minor_status,
- ctx->negotiated_ctx_id,
- qop_req,
- message_buffer,
- message_token);
-}
-
-OM_uint32 _gss_spnego_verify
- (OM_uint32 * minor_status,
- gss_ctx_id_t context_handle,
- gss_buffer_t message_buffer,
- gss_buffer_t token_buffer,
- int * qop_state
- )
-{
- gssspnego_ctx ctx;
-
- *minor_status = 0;
-
- if (context_handle == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- ctx = (gssspnego_ctx)context_handle;
-
- if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- return gss_verify(minor_status,
- ctx->negotiated_ctx_id,
- message_buffer,
- token_buffer,
- qop_state);
-}
-
-OM_uint32 _gss_spnego_seal
- (OM_uint32 * minor_status,
- gss_ctx_id_t context_handle,
- int conf_req_flag,
- int qop_req,
- gss_buffer_t input_message_buffer,
- int * conf_state,
- gss_buffer_t output_message_buffer
- )
-{
- gssspnego_ctx ctx;
-
- *minor_status = 0;
-
- if (context_handle == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- ctx = (gssspnego_ctx)context_handle;
-
- if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- return gss_seal(minor_status,
- ctx->negotiated_ctx_id,
- conf_req_flag,
- qop_req,
- input_message_buffer,
- conf_state,
- output_message_buffer);
-}
-
-OM_uint32 _gss_spnego_unseal
- (OM_uint32 * minor_status,
- gss_ctx_id_t context_handle,
- gss_buffer_t input_message_buffer,
- gss_buffer_t output_message_buffer,
- int * conf_state,
- int * qop_state
- )
-{
- gssspnego_ctx ctx;
-
- *minor_status = 0;
-
- if (context_handle == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- ctx = (gssspnego_ctx)context_handle;
-
- if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
- return GSS_S_NO_CONTEXT;
- }
-
- return gss_unseal(minor_status,
- ctx->negotiated_ctx_id,
- input_message_buffer,
- output_message_buffer,
- conf_state,
- qop_state);
-}
-
#if 0
OM_uint32 _gss_spnego_unwrap_ex
(OM_uint32 * minor_status,
* SUCH DAMAGE.
*/
-#include "spnego/spnego_locl.h"
+#include "spnego_locl.h"
RCSID("$Id$");
* SUCH DAMAGE.
*/
-#include "spnego/spnego_locl.h"
+#include "spnego_locl.h"
#include <gssapi_mech.h>
RCSID("$Id$");
_gss_spnego_inquire_cred_by_mech,
_gss_spnego_export_sec_context,
_gss_spnego_import_sec_context,
- _gss_spnego_inquire_names_for_mech,
+ NULL /* _gss_spnego_inquire_names_for_mech */,
_gss_spnego_inquire_mechs_for_name,
_gss_spnego_canonicalize_name,
_gss_spnego_duplicate_name,
* SUCH DAMAGE.
*/
-#include "spnego/spnego_locl.h"
+#include "spnego_locl.h"
RCSID("$Id$");
)
{
OM_uint32 ret, minor;
- NegTokenResp resp;
- size_t len, taglen;
+ NegotiationToken resp;
gss_OID_desc mech;
int require_mic;
size_t buf_len;
mech_buf.value = NULL;
mech_buf.length = 0;
- ret = der_match_tag_and_length(input_token->value, input_token->length,
- ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
+ ret = decode_NegotiationToken(input_token->value, input_token->length,
+ &resp, NULL);
if (ret)
- return ret;
+ return ret;
- if (len > input_token->length - taglen)
- return ASN1_OVERRUN;
-
- ret = decode_NegTokenResp((const unsigned char *)input_token->value+taglen,
- len, &resp, NULL);
- if (ret) {
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
+ if (resp.element != choice_NegotiationToken_negTokenResp) {
+ free_NegotiationToken(&resp);
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
}
- if (resp.negResult == NULL
- || *(resp.negResult) == reject
- /* || resp.supportedMech == NULL */
+ if (resp.u.negTokenResp.negResult == NULL
+ || *(resp.u.negTokenResp.negResult) == reject
+ /* || resp.u.negTokenResp.supportedMech == NULL */
)
{
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
return GSS_S_BAD_MECH;
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
- if (resp.supportedMech) {
+ if (resp.u.negTokenResp.supportedMech) {
if (ctx->oidlen) {
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_BAD_MECH;
}
ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1,
sizeof(ctx->oidbuf),
- resp.supportedMech,
+ resp.u.negTokenResp.supportedMech,
&ctx->oidlen);
/* Avoid recursively embedded SPNEGO */
if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length &&
GSS_SPNEGO_MECHANISM->elements,
ctx->oidlen) == 0))
{
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_BAD_MECH;
}
ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
}
} else if (ctx->oidlen == 0) {
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return GSS_S_BAD_MECH;
}
/* if a token (of non zero length), or no context, pass to underlaying mech */
- if ((resp.responseToken != NULL && resp.responseToken->length) ||
+ if ((resp.u.negTokenResp.responseToken != NULL && resp.u.negTokenResp.responseToken->length) ||
ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
gss_buffer_desc mech_input_token;
- if (resp.responseToken) {
- mech_input_token.length = resp.responseToken->length;
- mech_input_token.value = resp.responseToken->data;
+ if (resp.u.negTokenResp.responseToken) {
+ mech_input_token.length = resp.u.negTokenResp.responseToken->length;
+ mech_input_token.value = resp.u.negTokenResp.responseToken->data;
} else {
mech_input_token.length = 0;
mech_input_token.value = NULL;
&ctx->mech_time_rec);
if (GSS_ERROR(ret)) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
gss_mg_collect_error(&mech, ret, minor);
*minor_status = minor;
return ret;
if (ret == GSS_S_COMPLETE) {
ctx->open = 1;
}
- } else if (*(resp.negResult) == accept_completed) {
+ } else if (*(resp.u.negTokenResp.negResult) == accept_completed) {
if (ctx->maybe_open)
ctx->open = 1;
}
- if (*(resp.negResult) == request_mic) {
+ if (*(resp.u.negTokenResp.negResult) == request_mic) {
ctx->require_mic = 1;
}
* Verify the mechListMIC if one was provided or CFX was
* used and a non-preferred mechanism was selected
*/
- if (resp.mechListMIC != NULL) {
+ if (resp.u.negTokenResp.mechListMIC != NULL) {
require_mic = 1;
} else {
ret = _gss_spnego_require_mechlist_mic(minor_status, ctx,
&require_mic);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
gss_release_buffer(&minor, &mech_output_token);
return ret;
}
&ctx->initiator_mech_types, &buf_len, ret);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
gss_release_buffer(&minor, &mech_output_token);
*minor_status = ret;
return GSS_S_FAILURE;
if (mech_buf.length != buf_len)
abort();
- if (resp.mechListMIC == NULL) {
+ if (resp.u.negTokenResp.mechListMIC == NULL) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free(mech_buf.value);
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
*minor_status = 0;
return GSS_S_DEFECTIVE_TOKEN;
}
- mic_buf.length = resp.mechListMIC->length;
- mic_buf.value = resp.mechListMIC->data;
+ mic_buf.length = resp.u.negTokenResp.mechListMIC->length;
+ mic_buf.value = resp.u.negTokenResp.mechListMIC->data;
if (mech_output_token.length == 0) {
ret = gss_verify_mic(minor_status,
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
free(mech_buf.value);
gss_release_buffer(&minor, &mech_output_token);
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
return GSS_S_DEFECTIVE_TOKEN;
}
ctx->verified_mic = 1;
if (mech_buf.value != NULL)
free(mech_buf.value);
- free_NegTokenResp(&resp);
+ free_NegotiationToken(&resp);
gss_release_buffer(&minor, &mech_output_token);
if (actual_mech_type)
#ifndef SPNEGO_LOCL_H
#define SPNEGO_LOCL_H
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#include <pthread.h>
#endif
-#include <gssapi/gssapi_spnego.h>
#include <gssapi.h>
+#include <gssapi_krb5.h>
+#include <gssapi_spnego.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <gssapi_mech.h>
#include "spnego_asn1.h"
-#include "mech/utils.h"
+#include "utils.h"
#include <der.h>
#include <roken.h>
extern gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc;
extern gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc;
-#include <spnego/spnego-private.h>
+#include <spnego-private.h>
#endif /* SPNEGO_LOCL_H */
return 1;
return cb->cb.cb_2(a, b, cb);
}
+
+/*
+ *
+ */
+
+struct BN_CTX {
+ struct {
+ BIGNUM **val;
+ size_t used;
+ size_t len;
+ } bn;
+ struct {
+ size_t *val;
+ size_t used;
+ size_t len;
+ } stack;
+};
+
+BN_CTX *
+BN_CTX_new(void)
+{
+ struct BN_CTX *c;
+ c = calloc(1, sizeof(*c));
+ return c;
+}
+
+void
+BN_CTX_free(BN_CTX *c)
+{
+ size_t i;
+ for (i = 0; i < c->bn.len; i++)
+ BN_free(c->bn.val[i]);
+ free(c->bn.val);
+ free(c->stack.val);
+}
+
+BIGNUM *
+BN_CTX_get(BN_CTX *c)
+{
+ if (c->bn.used == c->bn.len) {
+ void *ptr;
+ size_t i;
+ c->bn.len += 16;
+ ptr = realloc(c->bn.val, c->bn.len * sizeof(c->bn.val[0]));
+ if (ptr == NULL)
+ return NULL;
+ c->bn.val = ptr;
+ for (i = c->bn.used; i < c->bn.len; i++) {
+ c->bn.val[i] = BN_new();
+ if (c->bn.val[i] == NULL) {
+ c->bn.len = i;
+ return NULL;
+ }
+ }
+ }
+ return c->bn.val[c->bn.used++];
+}
+
+void
+BN_CTX_start(BN_CTX *c)
+{
+ if (c->stack.used == c->stack.len) {
+ void *ptr;
+ c->stack.len += 16;
+ ptr = realloc(c->stack.val, c->stack.len * sizeof(c->stack.val[0]));
+ if (ptr == NULL)
+ abort();
+ c->stack.val = ptr;
+ }
+ c->stack.val[c->stack.used++] = c->bn.used;
+}
+
+void
+BN_CTX_end(BN_CTX *c)
+{
+ const size_t prev = c->stack.val[c->stack.used - 1];
+ size_t i;
+
+ if (c->stack.used == 0)
+ abort();
+
+ for (i = prev; i < c->bn.used; i++)
+ BN_clear(c->bn.val[i]);
+
+ c->stack.used--;
+ c->bn.used = prev;
+}
+
#define BN_set_negative hc_BN_set_negative
#define BN_set_word hc_BN_set_word
#define BN_uadd hc_BN_uadd
+#define BN_CTX_new hc_BN_CTX_new
+#define BN_CTX_free hc_BN_CTX_free
+#define BN_CTX_get hc_BN_CTX_get
+#define BN_CTX_start hc_BN_CTX_start
+#define BN_CTX_end hc_BN_CTX_end
/*
*
*/
-typedef void BIGNUM;
+typedef struct BIGNUM BIGNUM;
typedef struct BN_GENCB BN_GENCB;
-typedef void BN_CTX;
-typedef void BN_MONT_CTX;
-typedef void BN_BLINDING;
+typedef struct BN_CTX BN_CTX;
+typedef struct BN_MONT_CTX BN_MONT_CTX;
+typedef struct BN_BLINDING BN_BLINDING;
struct BN_GENCB {
unsigned int ver;
void BN_GENCB_set(BN_GENCB *, int (*)(int, int, BN_GENCB *), void *);
int BN_GENCB_call(BN_GENCB *, int, int);
+BN_CTX *BN_CTX_new(void);
+void BN_CTX_free(BN_CTX *);
+BIGNUM *BN_CTX_get(BN_CTX *);
+void BN_CTX_start(BN_CTX *);
+void BN_CTX_end(BN_CTX *);
+
#endif
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
-
-RCSID("$Id$");
#define HC_DEPRECATED
/*
- * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
+ * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
#include <config.h>
#endif
-RCSID("$Id$");
-
#define HC_DEPRECATED
#define HC_DEPRECATED_CRYPTO
return &null;
}
-#if 0
-int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);
-int EVP_DigestFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s);
-int EVP_SignFinal(EVP_MD_CTX *, void *, size_t *, EVP_PKEY *);
-int EVP_VerifyFinal(EVP_MD_CTX *, const void *, size_t, EVP_PKEY *);
-#endif
-
/**
* Return the block size of the cipher.
*
/**
* Perform a operation on a ctx
*
+ * @param ctx context to perform operation on.
+ * @param type type of operation.
+ * @param arg argument to operation.
+ * @param data addition data to operation.
+
* @return 1 for success, 0 for failure.
*
* @ingroup hcrypto_core
#include <stdio.h>
#include <stdlib.h>
#include <rand.h>
+#include <heim_threads.h>
#include <roken.h>
#include "randi.h"
+static int random_fd = -1;
+static HEIMDAL_MUTEX random_mutex = HEIMDAL_MUTEX_INITIALIZER;
+
/*
* Unix /dev/random
*/
}
+
static int
unix_bytes(unsigned char *outdata, int size)
{
ssize_t count;
- int fd;
+ int once = 0;
if (size <= 0)
return 0;
- fd = get_device_fd(O_RDONLY);
- if (fd < 0)
- return 0;
+ HEIMDAL_MUTEX_lock(&random_mutex);
+ if (random_fd == -1) {
+ retry:
+ random_fd = get_device_fd(O_RDONLY);
+ if (random_fd < 0) {
+ HEIMDAL_MUTEX_unlock(&random_mutex);
+ return 0;
+ }
+ }
while (size > 0) {
- count = read (fd, outdata, size);
- if (count < 0 && errno == EINTR)
- continue;
- else if (count <= 0) {
- close(fd);
+ HEIMDAL_MUTEX_unlock(&random_mutex);
+ count = read (random_fd, outdata, size);
+ HEIMDAL_MUTEX_lock(&random_mutex);
+ if (random_fd < 0) {
+ if (errno == EINTR)
+ continue;
+ else if (errno == EBADF && once++ == 0) {
+ close(random_fd);
+ random_fd = -1;
+ goto retry;
+ }
+ return 0;
+ } else if (count <= 0) {
+ HEIMDAL_MUTEX_unlock(&random_mutex);
return 0;
}
outdata += count;
size -= count;
}
- close(fd);
+ HEIMDAL_MUTEX_unlock(&random_mutex);
return 1;
}
{
if (selected_meth != NULL)
return;
+#ifdef __APPLE__
+ selected_meth = &hc_rand_unix_method;
+#else
selected_meth = &hc_rand_fortuna_method;
+#endif
}
/**
for(di = *dbp; di != NULL; di = ndi) {
ndi = di->next;
+ free (di->label);
free (di->realm);
free (di->dbname);
- if (di->mkey_file)
- free (di->mkey_file);
+ free (di->mkey_file);
+ free (di->acl_file);
+ free (di->log_file);
free(di);
}
*dbp = NULL;
Salt ::= SEQUENCE {
type[0] INTEGER (0..4294967295),
- salt[1] OCTET STRING
+ salt[1] OCTET STRING,
+ opaque[2] OCTET STRING OPTIONAL
}
Key ::= SEQUENCE {
HDB-extensions ::= SEQUENCE OF HDB-extension
+hdb_keyset ::= SEQUENCE {
+ kvno[1] INTEGER (0..4294967295),
+ keys[0] SEQUENCE OF Key
+}
hdb_entry ::= SEQUENCE {
principal[0] Principal OPTIONAL, -- this is optional only
/*
- * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "krb5.h"
#include "krb5_locl.h"
#include "hdb_locl.h"
RCSID("$Id$");
static struct hdb_method methods[] = {
#if HAVE_DB1 || HAVE_DB3
- {HDB_INTERFACE_VERSION, "db:", hdb_db_create},
+ { HDB_INTERFACE_VERSION, "db:", hdb_db_create},
#endif
#if HAVE_NDBM
- {HDB_INTERFACE_VERSION, "ndbm:", hdb_ndbm_create},
+ { HDB_INTERFACE_VERSION, "ndbm:", hdb_ndbm_create},
#endif
#if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
- {HDB_INTERFACE_VERSION, "ldap:", hdb_ldap_create},
- {HDB_INTERFACE_VERSION, "ldapi:", hdb_ldapi_create},
+ { HDB_INTERFACE_VERSION, "ldap:", hdb_ldap_create},
+ { HDB_INTERFACE_VERSION, "ldapi:", hdb_ldapi_create},
#endif
{0, NULL, NULL}
};
#if HAVE_DB1 || HAVE_DB3
-static struct hdb_method dbmetod = {"", hdb_db_create };
+static struct hdb_method dbmetod =
+ { HDB_INTERFACE_VERSION, "", hdb_db_create };
#elif defined(HAVE_NDBM)
-static struct hdb_method dbmetod = {"", hdb_ndbm_create };
+static struct hdb_method dbmetod =
+ { HDB_INTERFACE_VERSION, "", hdb_ndbm_create };
#endif
len = p - filename;
*rest = filename + len + 1;
- prefix = strndup(filename, len);
+ prefix = malloc(len + 1);
if (prefix == NULL)
krb5_errx(context, 1, "out of memory");
+ strlcpy(prefix, filename, len + 1);
if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1)
krb5_errx(context, 1, "out of memory");
+
/*
* Copyright (c) 1997 - 2001, 2003 - 2004 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
key.key.keyvalue.data = NULL;
if (salt) {
- key.salt = malloc(sizeof(*key.salt));
+ key.salt = calloc(1, sizeof(*key.salt));
if (key.salt == NULL) {
free_Key(&key);
return ENOMEM;
Key *k, *key_set;
int i, j;
char *default_keytypes[] = {
- "des:pw-salt",
"aes256-cts-hmac-sha1-96:pw-salt",
"des3-cbc-sha1:pw-salt",
"arcfour-hmac-md5:pw-salt",
if (ktypes == NULL)
ktypes = default_keytypes;
- if (ktypes == NULL)
- abort();
-
*ret_key_set = key_set = NULL;
*nkeyset = 0;
hdb_resolve,
hdb_get_name,
hdb_close,
+ NULL, /* destroy */
hdb_get_entry,
NULL, /* start_seq_get */
NULL, /* next_entry */
#include "hx_locl.h"
#include <pkinit_asn1.h>
-RCSID("$Id$");
/**
* @page page_ca Hx509 CA functions
*/
#include "hx_locl.h"
-RCSID("$Id$");
#include "crypto-headers.h"
#include <rtbl.h>
#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
+#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32
time_t time_now;
unsigned int max_depth;
#define HX509_VERIFY_MAX_DEPTH 30
ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
}
+void
+hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
+ int boolean)
+{
+ if (boolean)
+ ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
+ else
+ ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
+}
+
static const Extension *
find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
{
ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
i++;
if (ret == HX509_EXTENSION_NOT_FOUND) {
- ret = 0;
- break;
+ return 0;
} else if (ret != 0) {
hx509_set_error_string(context, 0, ret, "Error searching for SAN");
hx509_free_octet_string_list(list);
}
free_GeneralNames(&sa);
}
- return 0;
}
* @param context a hx509 context.
* @param p a hx509 certificate object.
* @param alg AlgorithmIdentifier, should be freed with
- * free_AlgorithmIdentifier().
+ * free_AlgorithmIdentifier(). The algorithmidentifier is
+ * typicly rsaEncryption, or id-ecPublicKey, or some other
+ * public key mechanism.
*
* @return An hx509 error code, see hx509_get_error_string().
*
"Failed to verify signature of certificate");
goto out;
}
+ /*
+ * Verify that the sigature algorithm "best-before" date is
+ * before the creation date of the certificate, do this for
+ * trust anchors too, since any trust anchor that is created
+ * after a algorithm is known to be bad deserved to be invalid.
+ *
+ * Skip the leaf certificate for now...
+ */
+
+ if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
+ time_t notBefore =
+ _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
+ ret = _hx509_signature_best_before(context,
+ &c->signatureAlgorithm,
+ notBefore);
+ if (ret)
+ goto out;
+ }
}
out:
int
hx509_query_match_cmp_func(hx509_query *q,
- int (*func)(void *, hx509_cert),
+ int (*func)(hx509_context, hx509_cert, void *),
void *ctx)
{
if (func)
return 0;
}
if (q->match & HX509_QUERY_MATCH_FUNCTION) {
- ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
+ ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
if (ret != 0)
return 0;
}
}
}
+ {
+ Certificate *c = _hx509_get_cert(cert);
+ heim_octet_string os, sig;
+ hx509_env envhash = NULL;
+ char *buf;
+
+ os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
+ os.length =
+ c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ hx509_signature_sha1(),
+ &os,
+ NULL,
+ &sig);
+ if (ret != 0)
+ goto out;
+
+ ret = hex_encode(sig.data, sig.length, &buf);
+ der_free_octet_string(&sig);
+ if (ret < 0) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret,
+ "Out of memory");
+ goto out;
+ }
+
+ ret = hx509_env_add(context, &envhash, "sha1", buf);
+ free(buf);
+ if (ret)
+ goto out;
+
+ ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
+ if (ret) {
+ hx509_env_free(&envhash);
+ goto out;
+ }
+ }
+
ret = hx509_env_add_binding(context, env, "certificate", envcert);
if (ret)
goto out;
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_cms CMS/PKCS7 message functions.
if (ret)
goto out;
+ if (flags & HX509_CMS_UE_ALLOW_WEAK)
+ hx509_crypto_allow_weak(crypto);
+
if (params) {
ret = hx509_crypto_set_params(context, crypto, params, &ivec);
if (ret) {
if (encryption_type == NULL)
encryption_type = oid_id_aes_256_cbc();
- ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
- if (ret)
- goto out;
+ if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
+ ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
+ if (ret)
+ goto out;
+ }
ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
if (ret)
goto out;
+ if (flags & HX509_CMS_EV_ALLOW_WEAK)
+ hx509_crypto_allow_weak(crypto);
+
ret = hx509_crypto_set_random_key(crypto, &key);
if (ret) {
hx509_set_error_string(context, 0, ret,
* Decode SignedData and verify that the signature is correct.
*
* @param context A hx509 context.
- * @param ctx a hx509 version context
- * @param data
+ * @param ctx a hx509 verify context.
+ * @param flags to control the behaivor of the function.
+ * @param data pointer to CMS SignedData encoded data.
* @param length length of the data that data point to.
- * @param signedContent
+ * @param signedContent external data used for signature.
* @param pool certificate pool to build certificates paths.
- * @param contentType free with der_free_oid()
+ * @param contentType free with der_free_oid().
* @param content the output of the function, free with
* der_free_octet_string().
* @param signer_certs list of the cerficates used to sign this
int
hx509_cms_verify_signed(hx509_context context,
hx509_verify_ctx ctx,
+ unsigned int flags,
const void *data,
size_t length,
const heim_octet_string *signedContent,
"Both external and internal SignedData");
goto out;
}
+
if (sd.encapContentInfo.eContent)
- signedContent = sd.encapContentInfo.eContent;
+ ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
+ else
+ ret = der_copy_octet_string(signedContent, content);
+ if (ret) {
+ hx509_set_error_string(context, 0, ret, "malloc: out of memory");
+ goto out;
+ }
ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
0, NULL, &certs);
}
for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
- heim_octet_string *signed_data;
+ heim_octet_string signed_data;
const heim_oid *match_oid;
heim_oid decode_oid;
ret = find_CMSIdentifier(context, &signer_info->sid, certs,
_hx509_verify_get_time(ctx), &cert,
HX509_QUERY_KU_DIGITALSIGNATURE);
- if (ret)
- continue;
+ if (ret) {
+ /**
+ * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
+ * search for matching certificates by not considering
+ * KeyUsage bits on the certificates.
+ */
+ if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
+ continue;
+
+ ret = find_CMSIdentifier(context, &signer_info->sid, certs,
+ _hx509_verify_get_time(ctx), &cert,
+ 0);
+ if (ret)
+ continue;
+
+ }
if (signer_info->signedAttrs) {
const Attribute *attr;
ret = _hx509_verify_signature(context,
NULL,
&signer_info->digestAlgorithm,
- signedContent,
+ content,
&os);
der_free_octet_string(&os);
if (ret) {
match_oid = &decode_oid;
}
- ALLOC(signed_data, 1);
- if (signed_data == NULL) {
- if (match_oid == &decode_oid)
- der_free_oid(&decode_oid);
- ret = ENOMEM;
- hx509_clear_error_string(context);
- goto next_sigature;
- }
-
ASN1_MALLOC_ENCODE(CMSAttributes,
- signed_data->data,
- signed_data->length,
+ signed_data.data,
+ signed_data.length,
&sa,
&size, ret);
if (ret) {
if (match_oid == &decode_oid)
der_free_oid(&decode_oid);
- free(signed_data);
hx509_clear_error_string(context);
goto next_sigature;
}
- if (size != signed_data->length)
+ if (size != signed_data.length)
_hx509_abort("internal ASN.1 encoder error");
} else {
- signed_data = rk_UNCONST(signedContent);
+ signed_data.data = content->data;
+ signed_data.length = content->length;
match_oid = oid_id_pkcs7_data();
}
- if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) {
+ /**
+ * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
+ * encapContentInfo mismatch with the oid in signedAttributes
+ * (or if no signedAttributes where use, pkcs7-data oid).
+ * This is only needed to work with broken CMS implementations
+ * that doesn't follow CMS signedAttributes rules.
+ */
+
+ if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
+ (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
ret = HX509_CMS_DATA_OID_MISMATCH;
hx509_set_error_string(context, 0, ret,
"Oid in message mismatch from the expected");
ret = hx509_verify_signature(context,
cert,
&signer_info->signatureAlgorithm,
- signed_data,
+ &signed_data,
&signer_info->signature);
if (ret)
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to verify sigature in "
+ "Failed to verify signature in "
"CMS SignedData");
}
- if (signed_data != signedContent) {
- der_free_octet_string(signed_data);
- free(signed_data);
- }
+ if (signer_info->signedAttrs)
+ free(signed_data.data);
if (ret)
goto next_sigature;
- ret = hx509_verify_path(context, ctx, cert, certs);
- if (ret)
- goto next_sigature;
+ /**
+ * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the
+ * signing certificates and leave that up to the caller.
+ */
+
+ if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) {
+ ret = hx509_verify_path(context, ctx, cert, certs);
+ if (ret)
+ goto next_sigature;
+ }
ret = hx509_certs_add(context, *signer_certs, cert);
if (ret)
hx509_cert_free(cert);
cert = NULL;
}
- if (found_valid_sig == 0) {
+ /**
+ * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
+ * SignerInfo (no signatures). If SignedData have no signatures,
+ * the function will return 0 with signer_certs set to NULL. Zero
+ * signers is allowed by the standard, but since its only useful
+ * in corner cases, it make into a flag that the caller have to
+ * turn on.
+ */
+ if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
+ if (*signer_certs)
+ hx509_certs_free(signer_certs);
+ } else if (found_valid_sig == 0) {
if (ret == 0) {
ret = HX509_CMS_SIGNER_NOT_FOUND;
hx509_set_error_string(context, 0, ret,
goto out;
}
- content->data = malloc(signedContent->length);
- if (content->data == NULL) {
- hx509_clear_error_string(context);
- ret = ENOMEM;
- goto out;
- }
- content->length = signedContent->length;
- memcpy(content->data, signedContent->data, content->length);
-
out:
free_SignedData(&sd);
if (certs)
hx509_certs_free(&certs);
if (ret) {
+ if (content->data)
+ der_free_octet_string(content);
if (*signer_certs)
hx509_certs_free(signer_certs);
der_free_oid(contentType);
hx509_certs pool,
heim_octet_string *signed_data)
{
- AlgorithmIdentifier digest;
- hx509_name name;
- SignerInfo *signer_info;
- heim_octet_string buf, content, sigdata = { 0, NULL };
+ hx509_certs certs;
+ int ret = 0;
+
+ signed_data->data = NULL;
+ signed_data->length = 0;
+
+ ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
+ if (ret)
+ return ret;
+ ret = hx509_certs_add(context, certs, cert);
+
+ ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
+ digest_alg, certs, peer, anchors, pool,
+ signed_data);
+
+ hx509_certs_free(&certs);
+ return ret;
+}
+
+struct sigctx {
SignedData sd;
- int ret;
+ const AlgorithmIdentifier *digest_alg;
+ const heim_oid *eContentType;
+ heim_octet_string content;
+ hx509_peer_info peer;
+ int cmsidflag;
+ hx509_certs certs;
+ hx509_certs anchors;
+ hx509_certs pool;
+};
+
+static int
+sig_process(hx509_context context, void *ctx, hx509_cert cert)
+{
+ struct sigctx *sigctx = ctx;
+ heim_octet_string buf, sigdata = { 0, NULL };
+ SignerInfo *signer_info = NULL;
+ AlgorithmIdentifier digest;
size_t size;
+ void *ptr;
+ int ret;
+ SignedData *sd = &sigctx->sd;
hx509_path path;
- int cmsidflag = CMS_ID_SKI;
- memset(&sd, 0, sizeof(sd));
- memset(&name, 0, sizeof(name));
- memset(&path, 0, sizeof(path));
memset(&digest, 0, sizeof(digest));
-
- content.data = rk_UNCONST(data);
- content.length = length;
-
- if (flags & HX509_CMS_SIGATURE_ID_NAME)
- cmsidflag = CMS_ID_NAME;
+ memset(&path, 0, sizeof(path));
if (_hx509_cert_private_key(cert) == NULL) {
hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
return HX509_PRIVATE_KEY_MISSING;
}
- if (digest_alg == NULL) {
- ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
- _hx509_cert_private_key(cert), peer, &digest);
- } else {
- ret = copy_AlgorithmIdentifier(digest_alg, &digest);
+ if (sigctx->digest_alg) {
+ ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
if (ret)
hx509_clear_error_string(context);
+ } else {
+ ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
+ _hx509_cert_private_key(cert),
+ sigctx->peer, &digest);
}
if (ret)
goto out;
- sd.version = CMSVersion_v3;
-
- if (eContentType == NULL)
- eContentType = oid_id_pkcs7_data();
-
- der_copy_oid(eContentType, &sd.encapContentInfo.eContentType);
-
- /* */
- if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) {
- ALLOC(sd.encapContentInfo.eContent, 1);
- if (sd.encapContentInfo.eContent == NULL) {
- hx509_clear_error_string(context);
- ret = ENOMEM;
- goto out;
- }
-
- sd.encapContentInfo.eContent->data = malloc(length);
- if (sd.encapContentInfo.eContent->data == NULL) {
- hx509_clear_error_string(context);
- ret = ENOMEM;
- goto out;
- }
- memcpy(sd.encapContentInfo.eContent->data, data, length);
- sd.encapContentInfo.eContent->length = length;
- }
+ /*
+ * Allocate on more signerInfo and do the signature processing
+ */
- ALLOC_SEQ(&sd.signerInfos, 1);
- if (sd.signerInfos.val == NULL) {
- hx509_clear_error_string(context);
+ ptr = realloc(sd->signerInfos.val,
+ (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
+ if (ptr == NULL) {
ret = ENOMEM;
goto out;
}
+ sd->signerInfos.val = ptr;
+
+ signer_info = &sd->signerInfos.val[sd->signerInfos.len];
- signer_info = &sd.signerInfos.val[0];
+ memset(signer_info, 0, sizeof(*signer_info));
signer_info->version = 1;
- ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid);
+ ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
if (ret) {
hx509_clear_error_string(context);
goto out;
signer_info->signedAttrs = NULL;
signer_info->unsignedAttrs = NULL;
-
ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
if (ret) {
hx509_clear_error_string(context);
* If it isn't pkcs7-data send signedAttributes
*/
- if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) {
+ if (der_heim_oid_cmp(sigctx->eContentType, oid_id_pkcs7_data()) != 0) {
CMSAttributes sa;
heim_octet_string sig;
ret = _hx509_create_signature(context,
NULL,
&digest,
- &content,
+ &sigctx->content,
NULL,
&sig);
if (ret)
oid_id_pkcs9_messageDigest(),
&buf);
if (ret) {
+ free(buf.data);
hx509_clear_error_string(context);
goto out;
}
ASN1_MALLOC_ENCODE(ContentType,
buf.data,
buf.length,
- eContentType,
+ sigctx->eContentType,
&size,
ret);
if (ret)
oid_id_pkcs9_contentType(),
&buf);
if (ret) {
+ free(buf.data);
hx509_clear_error_string(context);
goto out;
}
if (size != sigdata.length)
_hx509_abort("internal ASN.1 encoder error");
} else {
- sigdata.data = content.data;
- sigdata.length = content.length;
+ sigdata.data = sigctx->content.data;
+ sigdata.length = sigctx->content.length;
}
-
{
AlgorithmIdentifier sigalg;
ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
- _hx509_cert_private_key(cert), peer,
+ _hx509_cert_private_key(cert), sigctx->peer,
&sigalg);
if (ret)
goto out;
goto out;
}
- ALLOC_SEQ(&sd.digestAlgorithms, 1);
- if (sd.digestAlgorithms.val == NULL) {
- ret = ENOMEM;
- hx509_clear_error_string(context);
- goto out;
- }
-
- ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
+ sigctx->sd.signerInfos.len++;
+ signer_info = NULL;
/*
* Provide best effort path
*/
- if (pool) {
- _hx509_calculate_path(context,
- HX509_CALCULATE_PATH_NO_ANCHOR,
- time(NULL),
- anchors,
- 0,
- cert,
- pool,
- &path);
- } else
- _hx509_path_append(context, &path, cert);
+ if (sigctx->certs) {
+ unsigned int i;
+
+ if (sigctx->pool) {
+ _hx509_calculate_path(context,
+ HX509_CALCULATE_PATH_NO_ANCHOR,
+ time(NULL),
+ sigctx->anchors,
+ 0,
+ cert,
+ sigctx->pool,
+ &path);
+ } else
+ _hx509_path_append(context, &path, cert);
+
+ for (i = 0; i < path.len; i++) {
+ /* XXX remove dups */
+ ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
+ if (ret) {
+ hx509_clear_error_string(context);
+ goto out;
+ }
+ }
+ }
+
+ out:
+ if (signer_info)
+ free_SignerInfo(signer_info);
+ if (sigdata.data != sigctx->content.data)
+ der_free_octet_string(&sigdata);
+ _hx509_path_free(&path);
+ free_AlgorithmIdentifier(&digest);
+
+ return ret;
+}
+
+static int
+cert_process(hx509_context context, void *ctx, hx509_cert cert)
+{
+ struct sigctx *sigctx = ctx;
+ const unsigned int i = sigctx->sd.certificates->len;
+ void *ptr;
+ int ret;
+
+ ptr = realloc(sigctx->sd.certificates->val,
+ (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
+ if (ptr == NULL)
+ return ENOMEM;
+ sigctx->sd.certificates->val = ptr;
+
+ ret = hx509_cert_binary(context, cert,
+ &sigctx->sd.certificates->val[i]);
+ if (ret == 0)
+ sigctx->sd.certificates->len++;
+
+ return ret;
+}
+
+int
+hx509_cms_create_signed(hx509_context context,
+ int flags,
+ const heim_oid *eContentType,
+ const void *data, size_t length,
+ const AlgorithmIdentifier *digest_alg,
+ hx509_certs certs,
+ hx509_peer_info peer,
+ hx509_certs anchors,
+ hx509_certs pool,
+ heim_octet_string *signed_data)
+{
+ unsigned int i;
+ hx509_name name;
+ int ret;
+ size_t size;
+ struct sigctx sigctx;
+
+ memset(&sigctx, 0, sizeof(sigctx));
+ memset(&name, 0, sizeof(name));
+
+ if (eContentType == NULL)
+ eContentType = oid_id_pkcs7_data();
+
+ sigctx.digest_alg = digest_alg;
+ sigctx.content.data = rk_UNCONST(data);
+ sigctx.content.length = length;
+ sigctx.eContentType = eContentType;
+ sigctx.peer = peer;
+ /**
+ * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
+ * and serial number if possible. Otherwise subject key identifier
+ * will preferred.
+ */
+ if (flags & HX509_CMS_SIGNATURE_ID_NAME)
+ sigctx.cmsidflag = CMS_ID_NAME;
+ else
+ sigctx.cmsidflag = CMS_ID_SKI;
+
+ ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
+ if (ret)
+ return ret;
+
+ sigctx.anchors = anchors;
+ sigctx.pool = pool;
+ sigctx.sd.version = CMSVersion_v3;
- if (path.len) {
- int i;
+ der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
- ALLOC(sd.certificates, 1);
- if (sd.certificates == NULL) {
+ /**
+ * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
+ */
+ if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
+ ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
+ if (sigctx.sd.encapContentInfo.eContent == NULL) {
hx509_clear_error_string(context);
ret = ENOMEM;
goto out;
}
- ALLOC_SEQ(sd.certificates, path.len);
- if (sd.certificates->val == NULL) {
+
+ sigctx.sd.encapContentInfo.eContent->data = malloc(length);
+ if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
hx509_clear_error_string(context);
ret = ENOMEM;
goto out;
}
+ memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
+ sigctx.sd.encapContentInfo.eContent->length = length;
+ }
- for (i = 0; i < path.len; i++) {
- ret = hx509_cert_binary(context, path.val[i],
- &sd.certificates->val[i]);
+ /**
+ * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
+ * signatures).
+ */
+ if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
+ ret = hx509_certs_iter(context, certs, sig_process, &sigctx);
+ if (ret)
+ goto out;
+ }
+
+ if (sigctx.sd.signerInfos.len) {
+ ALLOC_SEQ(&sigctx.sd.digestAlgorithms, sigctx.sd.signerInfos.len);
+ if (sigctx.sd.digestAlgorithms.val == NULL) {
+ ret = ENOMEM;
+ hx509_clear_error_string(context);
+ goto out;
+ }
+
+ /* XXX remove dups */
+ for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
+ AlgorithmIdentifier *di =
+ &sigctx.sd.signerInfos.val[i].digestAlgorithm;
+ ret = copy_AlgorithmIdentifier(di,
+ &sigctx.sd.digestAlgorithms.val[i]);
if (ret) {
hx509_clear_error_string(context);
goto out;
}
}
+ if (sigctx.certs) {
+ ALLOC(sigctx.sd.certificates, 1);
+ if (sigctx.sd.certificates == NULL) {
+ hx509_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = hx509_certs_iter(context, sigctx.certs, cert_process, &sigctx);
+ if (ret)
+ goto out;
+ }
+
ASN1_MALLOC_ENCODE(SignedData,
signed_data->data, signed_data->length,
- &sd, &size, ret);
+ &sigctx.sd, &size, ret);
if (ret) {
hx509_clear_error_string(context);
goto out;
_hx509_abort("internal ASN.1 encoder error");
out:
- if (sigdata.data != content.data)
- der_free_octet_string(&sigdata);
- free_AlgorithmIdentifier(&digest);
- _hx509_path_free(&path);
- free_SignedData(&sd);
+ hx509_certs_free(&sigctx.certs);
+ free_SignedData(&sigctx.sd);
return ret;
}
*/
#include "hx_locl.h"
-RCSID("$Id$");
struct private_key {
AlgorithmIdentifier alg;
c->val.data[i]->private_key = NULL;
}
}
- (*keys)[nkeys++] = NULL;
+ (*keys)[nkeys] = NULL;
return 0;
}
*/
#include "hx_locl.h"
-RCSID("$Id$");
struct hx509_crypto;
struct hx509_private_key_ops {
const char *pemtype;
- const heim_oid *(*key_oid)(void);
+ const heim_oid *key_oid;
+ int (*available)(const hx509_private_key,
+ const AlgorithmIdentifier *);
int (*get_spki)(hx509_context,
const hx509_private_key,
SubjectPublicKeyInfo *);
struct hx509_generate_private_context *,
hx509_private_key);
BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *);
- int (*handle_alg)(const hx509_private_key,
- const AlgorithmIdentifier *,
- enum crypto_op_type);
- int (*sign)(hx509_context context,
- const hx509_private_key,
- const AlgorithmIdentifier *,
- const heim_octet_string *,
- AlgorithmIdentifier *,
- heim_octet_string *);
-#if 0
- const AlgorithmIdentifier *(*preferred_sig_alg)
- (const hx509_private_key,
- const hx509_peer_info);
- int (*unwrap)(hx509_context context,
- const hx509_private_key,
- const AlgorithmIdentifier *,
- const heim_octet_string *,
- heim_octet_string *);
-#endif
};
struct hx509_private_key {
union {
RSA *rsa;
void *keydata;
+#ifdef HAVE_OPENSSL
+ EC_KEY *ecdsa;
+#endif
} private_key;
- /* new crypto layer */
hx509_private_key_ops *ops;
};
struct signature_alg {
const char *name;
- const heim_oid *(*sig_oid)(void);
- const AlgorithmIdentifier *(*sig_alg)(void);
- const heim_oid *(*key_oid)(void);
- const heim_oid *(*digest_oid)(void);
+ const heim_oid *sig_oid;
+ const AlgorithmIdentifier *sig_alg;
+ const heim_oid *key_oid;
+ const AlgorithmIdentifier *digest_alg;
int flags;
#define PROVIDE_CONF 1
#define REQUIRE_SIGNER 2
#define RA_RSA_USES_DIGEST_INFO 0x1000000
-
+ time_t best_before; /* refuse signature made after best before date */
int (*verify_signature)(hx509_context context,
const struct signature_alg *,
const Certificate *,
const heim_octet_string *,
AlgorithmIdentifier *,
heim_octet_string *);
+ int digest_size;
+};
+
+static const struct signature_alg *
+find_sig_alg(const heim_oid *oid);
+
+/*
+ *
+ */
+
+static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") };
+
+static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
+const AlgorithmIdentifier _hx509_signature_sha512_data = {
+ { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid)
+};
+
+static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 };
+const AlgorithmIdentifier _hx509_signature_sha384_data = {
+ { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid)
+};
+
+static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
+const AlgorithmIdentifier _hx509_signature_sha256_data = {
+ { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid)
+};
+
+static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 };
+const AlgorithmIdentifier _hx509_signature_sha1_data = {
+ { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid)
+};
+
+static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 };
+const AlgorithmIdentifier _hx509_signature_md5_data = {
+ { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid)
+};
+
+static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 };
+const AlgorithmIdentifier _hx509_signature_md2_data = {
+ { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid)
+};
+
+static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 };
+const AlgorithmIdentifier _hx509_signature_ecPublicKey = {
+ { 6, rk_UNCONST(ecPublicKey) }, NULL
+};
+
+static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 };
+const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = {
+ { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL
+};
+
+static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 };
+const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = {
+ { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL
+};
+
+static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 };
+const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = {
+ { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL
+};
+
+static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 };
+const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = {
+ { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL
+};
+
+static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 };
+const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = {
+ { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL
+};
+
+static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 };
+const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = {
+ { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL
+};
+
+static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 };
+const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = {
+ { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL
+};
+
+static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 };
+const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = {
+ { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL
+};
+
+static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 };
+const AlgorithmIdentifier _hx509_signature_rsa_data = {
+ { 7, rk_UNCONST(rsa_oid) }, NULL
+};
+
+static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 };
+const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = {
+ { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL
+};
+
+static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 };
+const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = {
+ { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL
+};
+
+static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 };
+const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = {
+ { 9, rk_UNCONST(aes128_cbc_oid) }, NULL
+};
+
+static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 };
+const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = {
+ { 9, rk_UNCONST(aes256_cbc_oid) }, NULL
};
/*
return 0;
}
+#ifdef HAVE_OPENSSL
+
+/*
+ *
+ */
+
+static int
+ecdsa_verify_signature(hx509_context context,
+ const struct signature_alg *sig_alg,
+ const Certificate *signer,
+ const AlgorithmIdentifier *alg,
+ const heim_octet_string *data,
+ const heim_octet_string *sig)
+{
+ const AlgorithmIdentifier *digest_alg;
+ const SubjectPublicKeyInfo *spi;
+ heim_octet_string digest;
+ int ret;
+ EC_KEY *key = NULL;
+ size_t size;
+ ECParameters ecparam;
+ int groupnid;
+ EC_GROUP *group;
+ const unsigned char *p;
+ long len;
+
+ digest_alg = sig_alg->digest_alg;
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ digest_alg,
+ data,
+ NULL,
+ &digest);
+ if (ret)
+ return ret;
+
+ /* set up EC KEY */
+ spi = &signer->tbsCertificate.subjectPublicKeyInfo;
+
+ if (der_heim_oid_cmp(&spi->algorithm.algorithm, &asn1_oid_id_ecPublicKey) != 0 ||
+ spi->algorithm.parameters == NULL)
+ return HX509_CRYPTO_SIG_INVALID_FORMAT;
+
+#ifdef HAVE_OPENSSL
+ /*
+ * Find the group id
+ */
+
+ ret = decode_ECParameters(spi->algorithm.parameters->data,
+ spi->algorithm.parameters->length,
+ &ecparam, &size);
+ if (ret) {
+ der_free_octet_string(&digest);
+ return ret;
+ }
+
+ if (ecparam.element != choice_ECParameters_namedCurve) {
+ der_free_octet_string(&digest);
+ free_ECParameters(&ecparam);
+ return HX509_CRYPTO_SIG_INVALID_FORMAT;
+ }
+
+ /*
+ * Now map to openssl OID fun
+ */
+ groupnid = -1;
+
+ if (der_heim_oid_cmp(&ecparam.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0)
+ groupnid = NID_X9_62_prime256v1;
+ else if (der_heim_oid_cmp(&ecparam.u.namedCurve, &asn1_oid_id_ec_group_secp160r1) == 0)
+ groupnid = NID_secp160r1;
+ else if (der_heim_oid_cmp(&ecparam.u.namedCurve, &asn1_oid_id_ec_group_secp160r2) == 0)
+ groupnid = NID_secp160r2;
+
+ free_ECParameters(&ecparam);
+ if (groupnid == -1) {
+ der_free_octet_string(&digest);
+ return HX509_CRYPTO_SIG_INVALID_FORMAT;
+ }
+
+ /*
+ * Create group, key, parse key
+ */
+
+ key = EC_KEY_new();
+ group = EC_GROUP_new_by_curve_name(groupnid);
+ EC_KEY_set_group(key, group);
+ EC_GROUP_free(group);
+
+ p = spi->subjectPublicKey.data;
+ len = spi->subjectPublicKey.length / 8;
+
+ if (o2i_ECPublicKey(&key, &p, len) == NULL) {
+ EC_KEY_free(key);
+ return HX509_CRYPTO_SIG_INVALID_FORMAT;
+ }
+#else
+ key = SubjectPublicKeyInfo2EC_KEY(spi);
+#endif
+
+ ret = ECDSA_verify(-1, digest.data, digest.length,
+ sig->data, sig->length, key);
+ der_free_octet_string(&digest);
+ EC_KEY_free(key);
+ if (ret != 1) {
+ ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+ecdsa_create_signature(hx509_context context,
+ const struct signature_alg *sig_alg,
+ const hx509_private_key signer,
+ const AlgorithmIdentifier *alg,
+ const heim_octet_string *data,
+ AlgorithmIdentifier *signatureAlgorithm,
+ heim_octet_string *sig)
+{
+ const AlgorithmIdentifier *digest_alg;
+ heim_octet_string indata;
+ const heim_oid *sig_oid;
+ unsigned int siglen;
+ int ret;
+
+ if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0)
+ _hx509_abort("internal error passing private key to wrong ops");
+
+ sig_oid = sig_alg->sig_oid;
+ digest_alg = sig_alg->digest_alg;
+
+ if (signatureAlgorithm) {
+ ret = set_digest_alg(signatureAlgorithm, sig_oid, "\x05\x00", 2);
+ if (ret) {
+ hx509_clear_error_string(context);
+ return ret;
+ }
+ }
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ digest_alg,
+ data,
+ NULL,
+ &indata);
+
+ sig->length = ECDSA_size(signer->private_key.ecdsa);
+ sig->data = malloc(sig->length);
+ if (sig->data == NULL) {
+ der_free_octet_string(&indata);
+ hx509_set_error_string(context, 0, ENOMEM, "out of memory");
+ return ENOMEM;
+ }
+
+ siglen = sig->length;
+
+ ret = ECDSA_sign(-1, indata.data, indata.length,
+ sig->data, &siglen, signer->private_key.ecdsa);
+ der_free_octet_string(&indata);
+ if (ret != 1) {
+ hx509_set_error_string(context, 0, HX509_CMS_FAILED_CREATE_SIGATURE,
+ "ECDSA sign failed: %d", ret);
+ return HX509_CMS_FAILED_CREATE_SIGATURE;
+ }
+ if (siglen > sig->length)
+ _hx509_abort("ECDSA signature prelen longer the output len");
+
+ sig->length = siglen;
+
+ return 0;
+}
+
+static int
+ecdsa_available(const hx509_private_key signer,
+ const AlgorithmIdentifier *sig_alg)
+{
+ const struct signature_alg *sig;
+ const EC_GROUP *group;
+ BN_CTX *bnctx = NULL;
+ BIGNUM *order = NULL;
+ int ret = 0;
+
+ if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0)
+ _hx509_abort("internal error passing private key to wrong ops");
+
+ sig = find_sig_alg(&sig_alg->algorithm);
+
+ if (sig == NULL || sig->digest_size == 0)
+ return 0;
+
+ group = EC_KEY_get0_group(signer->private_key.ecdsa);
+ if (group == NULL)
+ return 0;
+
+ bnctx = BN_CTX_new();
+ order = BN_new();
+ if (order == NULL)
+ goto err;
+
+ if (EC_GROUP_get_order(group, order, bnctx) != 1)
+ goto err;
+
+ if (BN_num_bytes(order) > sig->digest_size)
+ ret = 1;
+ err:
+ if (bnctx)
+ BN_CTX_free(bnctx);
+ if (order)
+ BN_clear_free(order);
+
+ return ret;
+}
+
+
+#endif /* HAVE_OPENSSL */
+
/*
*
*/
goto out;
}
- if (sig_alg->digest_oid &&
+ if (sig_alg->digest_alg &&
der_heim_oid_cmp(&di.digestAlgorithm.algorithm,
- (*sig_alg->digest_oid)()) != 0)
+ &sig_alg->digest_alg->algorithm) != 0)
{
ret = HX509_CRYPTO_OID_MISMATCH;
hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch");
size_t size;
int ret;
+ if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) != 0)
+ return HX509_ALG_NOT_SUPP;
+
if (alg)
sig_oid = &alg->algorithm;
else
sig_oid = signer->signature_alg;
- if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha256WithRSAEncryption()) == 0) {
+ if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_sha256WithRSAEncryption) == 0) {
digest_alg = hx509_signature_sha256();
- } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha1WithRSAEncryption()) == 0) {
+ } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_sha1WithRSAEncryption) == 0) {
digest_alg = hx509_signature_sha1();
- } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) {
+ } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_md5WithRSAEncryption) == 0) {
digest_alg = hx509_signature_md5();
- } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) {
+ } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_md5WithRSAEncryption) == 0) {
digest_alg = hx509_signature_md5();
- } else if (der_heim_oid_cmp(sig_oid, oid_id_dsa_with_sha1()) == 0) {
+ } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_dsa_with_sha1) == 0) {
digest_alg = hx509_signature_sha1();
- } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_rsaEncryption()) == 0) {
+ } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) {
digest_alg = hx509_signature_sha1();
- } else if (der_heim_oid_cmp(sig_oid, oid_id_heim_rsa_pkcs1_x509()) == 0) {
+ } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_heim_rsa_pkcs1_x509) == 0) {
digest_alg = NULL;
} else
return HX509_ALG_NOT_SUPP;
"Failed to parse RSA key");
return HX509_PARSING_KEY_FAILED;
}
- private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption();
+ private_key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption;
return 0;
}
}
spki->subjectPublicKey.length = len * 8;
- ret = set_digest_alg(&spki->algorithm,oid_id_pkcs1_rsaEncryption(),
+ ret = set_digest_alg(&spki->algorithm, &asn1_oid_id_pkcs1_rsaEncryption,
"\x05\x00", 2);
if (ret) {
hx509_set_error_string(context, 0, ret, "malloc - out of memory");
"Failed to generate RSA key");
return HX509_PARSING_KEY_FAILED;
}
- private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption();
+ private_key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption;
return 0;
}
}
static BIGNUM *
-rsa_get_internal(hx509_context context, hx509_private_key key, const char *type)
+rsa_get_internal(hx509_context context,
+ hx509_private_key key,
+ const char *type)
{
if (strcasecmp(type, "rsa-modulus") == 0) {
return BN_dup(key->private_key.rsa->n);
static hx509_private_key_ops rsa_private_key_ops = {
"RSA PRIVATE KEY",
- oid_id_pkcs1_rsaEncryption,
+ &asn1_oid_id_pkcs1_rsaEncryption,
+ NULL,
rsa_private_key2SPKI,
rsa_private_key_export,
rsa_private_key_import,
rsa_get_internal
};
+#ifdef HAVE_OPENSSL
+
+static int
+ecdsa_private_key2SPKI(hx509_context context,
+ hx509_private_key private_key,
+ SubjectPublicKeyInfo *spki)
+{
+ memset(spki, 0, sizeof(*spki));
+ return ENOMEM;
+}
+
+static int
+ecdsa_private_key_export(hx509_context context,
+ const hx509_private_key key,
+ heim_octet_string *data)
+{
+ return ENOMEM;
+}
+
+static int
+ecdsa_private_key_import(hx509_context context,
+ const void *data,
+ size_t len,
+ hx509_private_key private_key)
+{
+ const unsigned char *p = data;
+
+ private_key->private_key.ecdsa =
+ d2i_ECPrivateKey(NULL, &p, len);
+ if (private_key->private_key.ecdsa == NULL) {
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "Failed to parse EC private key");
+ return HX509_PARSING_KEY_FAILED;
+ }
+ private_key->signature_alg = &asn1_oid_id_ecdsa_with_SHA256;
+
+ return 0;
+}
+
+static int
+ecdsa_generate_private_key(hx509_context context,
+ struct hx509_generate_private_context *ctx,
+ hx509_private_key private_key)
+{
+ return ENOMEM;
+}
+
+static BIGNUM *
+ecdsa_get_internal(hx509_context context,
+ hx509_private_key key,
+ const char *type)
+{
+ return NULL;
+}
+
+
+static hx509_private_key_ops ecdsa_private_key_ops = {
+ "EC PRIVATE KEY",
+ &asn1_oid_id_ecPublicKey,
+ ecdsa_available,
+ ecdsa_private_key2SPKI,
+ ecdsa_private_key_export,
+ ecdsa_private_key_import,
+ ecdsa_generate_private_key,
+ ecdsa_get_internal
+};
+
+#endif /* HAVE_OPENSSL */
/*
*
d2i_DSAPrivateKey(NULL, &p, len);
if (private_key->private_key.dsa == NULL)
return EINVAL;
- private_key->signature_alg = oid_id_dsa_with_sha1();
+ private_key->signature_alg = &asn1_oid_id_dsa_with_sha1;
return 0;
/* else */
if (signatureAlgorithm) {
int ret;
- ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(),
+ ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid,
"\x05\x00", 2);
if (ret)
return ret;
if (signatureAlgorithm) {
int ret;
- ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(),
+ ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid,
"\x05\x00", 2);
if (ret)
return ret;
return 0;
}
+#ifdef HAVE_OPENSSL
+
+static const struct signature_alg ecdsa_with_sha256_alg = {
+ "ecdsa-with-sha256",
+ &asn1_oid_id_ecdsa_with_SHA256,
+ &_hx509_signature_ecdsa_with_sha256_data,
+ &asn1_oid_id_ecPublicKey,
+ &_hx509_signature_sha256_data,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 0,
+ ecdsa_verify_signature,
+ ecdsa_create_signature,
+ 32
+};
+
+static const struct signature_alg ecdsa_with_sha1_alg = {
+ "ecdsa-with-sha1",
+ &asn1_oid_id_ecdsa_with_SHA1,
+ &_hx509_signature_ecdsa_with_sha1_data,
+ &asn1_oid_id_ecPublicKey,
+ &_hx509_signature_sha1_data,
+ PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 0,
+ ecdsa_verify_signature,
+ ecdsa_create_signature,
+ 20
+};
+
+#endif
+
static const struct signature_alg heim_rsa_pkcs1_x509 = {
"rsa-pkcs1-x509",
- oid_id_heim_rsa_pkcs1_x509,
- hx509_signature_rsa_pkcs1_x509,
- oid_id_pkcs1_rsaEncryption,
+ &asn1_oid_id_heim_rsa_pkcs1_x509,
+ &_hx509_signature_rsa_pkcs1_x509_data,
+ &asn1_oid_id_pkcs1_rsaEncryption,
NULL,
PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ 0,
rsa_verify_signature,
rsa_create_signature
};
static const struct signature_alg pkcs1_rsa_sha1_alg = {
"rsa",
- oid_id_pkcs1_rsaEncryption,
- hx509_signature_rsa_with_sha1,
- oid_id_pkcs1_rsaEncryption,
+ &asn1_oid_id_pkcs1_rsaEncryption,
+ &_hx509_signature_rsa_with_sha1_data,
+ &asn1_oid_id_pkcs1_rsaEncryption,
NULL,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 0,
rsa_verify_signature,
rsa_create_signature
};
static const struct signature_alg rsa_with_sha256_alg = {
"rsa-with-sha256",
- oid_id_pkcs1_sha256WithRSAEncryption,
- hx509_signature_rsa_with_sha256,
- oid_id_pkcs1_rsaEncryption,
- oid_id_sha256,
+ &asn1_oid_id_pkcs1_sha256WithRSAEncryption,
+ &_hx509_signature_rsa_with_sha256_data,
+ &asn1_oid_id_pkcs1_rsaEncryption,
+ &_hx509_signature_sha256_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 0,
rsa_verify_signature,
rsa_create_signature
};
static const struct signature_alg rsa_with_sha1_alg = {
"rsa-with-sha1",
- oid_id_pkcs1_sha1WithRSAEncryption,
- hx509_signature_rsa_with_sha1,
- oid_id_pkcs1_rsaEncryption,
- oid_id_secsig_sha_1,
+ &asn1_oid_id_pkcs1_sha1WithRSAEncryption,
+ &_hx509_signature_rsa_with_sha1_data,
+ &asn1_oid_id_pkcs1_rsaEncryption,
+ &_hx509_signature_sha1_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 0,
rsa_verify_signature,
rsa_create_signature
};
static const struct signature_alg rsa_with_md5_alg = {
"rsa-with-md5",
- oid_id_pkcs1_md5WithRSAEncryption,
- hx509_signature_rsa_with_md5,
- oid_id_pkcs1_rsaEncryption,
- oid_id_rsa_digest_md5,
+ &asn1_oid_id_pkcs1_md5WithRSAEncryption,
+ &_hx509_signature_rsa_with_md5_data,
+ &asn1_oid_id_pkcs1_rsaEncryption,
+ &_hx509_signature_md5_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 1230739889,
rsa_verify_signature,
rsa_create_signature
};
static const struct signature_alg rsa_with_md2_alg = {
"rsa-with-md2",
- oid_id_pkcs1_md2WithRSAEncryption,
- hx509_signature_rsa_with_md2,
- oid_id_pkcs1_rsaEncryption,
- oid_id_rsa_digest_md2,
+ &asn1_oid_id_pkcs1_md2WithRSAEncryption,
+ &_hx509_signature_rsa_with_md2_data,
+ &asn1_oid_id_pkcs1_rsaEncryption,
+ &_hx509_signature_md2_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG,
+ 1230739889,
rsa_verify_signature,
rsa_create_signature
};
static const struct signature_alg dsa_sha1_alg = {
"dsa-with-sha1",
- oid_id_dsa_with_sha1,
+ &asn1_oid_id_dsa_with_sha1,
NULL,
- oid_id_dsa,
- oid_id_secsig_sha_1,
+ &asn1_oid_id_dsa,
+ &_hx509_signature_sha1_data,
PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
+ 0,
dsa_verify_signature,
/* create_signature */ NULL,
};
static const struct signature_alg sha256_alg = {
"sha-256",
- oid_id_sha256,
- hx509_signature_sha256,
+ &asn1_oid_id_sha256,
+ &_hx509_signature_sha256_data,
NULL,
NULL,
SIG_DIGEST,
+ 0,
sha256_verify_signature,
sha256_create_signature
};
static const struct signature_alg sha1_alg = {
"sha1",
- oid_id_secsig_sha_1,
- hx509_signature_sha1,
+ &asn1_oid_id_secsig_sha_1,
+ &_hx509_signature_sha1_data,
NULL,
NULL,
SIG_DIGEST,
+ 0,
sha1_verify_signature,
sha1_create_signature
};
static const struct signature_alg md5_alg = {
"rsa-md5",
- oid_id_rsa_digest_md5,
- hx509_signature_md5,
+ &asn1_oid_id_rsa_digest_md5,
+ &_hx509_signature_md5_data,
NULL,
NULL,
SIG_DIGEST,
+ 0,
md5_verify_signature
};
static const struct signature_alg md2_alg = {
"rsa-md2",
- oid_id_rsa_digest_md2,
- hx509_signature_md2,
+ &asn1_oid_id_rsa_digest_md2,
+ &_hx509_signature_md2_data,
NULL,
NULL,
SIG_DIGEST,
+ 0,
md2_verify_signature
};
/*
* Order matter in this structure, "best" first for each "key
- * compatible" type (type is RSA, DSA, none, etc)
+ * compatible" type (type is ECDSA, RSA, DSA, none, etc)
*/
static const struct signature_alg *sig_algs[] = {
+#ifdef HAVE_OPENSSL
+ &ecdsa_with_sha256_alg,
+ &ecdsa_with_sha1_alg,
+#endif
&rsa_with_sha256_alg,
&rsa_with_sha1_alg,
&pkcs1_rsa_sha1_alg,
static const struct signature_alg *
find_sig_alg(const heim_oid *oid)
{
- int i;
+ unsigned int i;
for (i = 0; sig_algs[i]; i++)
- if (der_heim_oid_cmp((*sig_algs[i]->sig_oid)(), oid) == 0)
+ if (der_heim_oid_cmp(sig_algs[i]->sig_oid, oid) == 0)
return sig_algs[i];
return NULL;
}
+static const AlgorithmIdentifier *
+alg_for_privatekey(const hx509_private_key pk, int type)
+{
+ const heim_oid *keytype;
+ unsigned int i;
+
+ if (pk->ops == NULL)
+ return NULL;
+
+ keytype = pk->ops->key_oid;
+
+ for (i = 0; sig_algs[i]; i++) {
+ if (sig_algs[i]->key_oid == NULL)
+ continue;
+ if (der_heim_oid_cmp(sig_algs[i]->key_oid, keytype) != 0)
+ continue;
+ if (pk->ops->available &&
+ pk->ops->available(pk, sig_algs[i]->sig_alg) == 0)
+ continue;
+ if (type == HX509_SELECT_PUBLIC_SIG)
+ return sig_algs[i]->sig_alg;
+ if (type == HX509_SELECT_DIGEST)
+ return sig_algs[i]->digest_alg;
+
+ return NULL;
+ }
+ return NULL;
+}
+
/*
*
*/
static struct hx509_private_key_ops *private_algs[] = {
&rsa_private_key_ops,
+#ifdef HAVE_OPENSSL
+ &ecdsa_private_key_ops,
+#endif
NULL
};
for (i = 0; private_algs[i]; i++) {
if (private_algs[i]->key_oid == NULL)
continue;
- if (der_heim_oid_cmp((*private_algs[i]->key_oid)(), oid) == 0)
+ if (der_heim_oid_cmp(private_algs[i]->key_oid, oid) == 0)
return private_algs[i];
}
return NULL;
}
+/*
+ * Check if the algorithm `alg' have a best before date, and if it
+ * des, make sure the its before the time `t'.
+ */
+
+int
+_hx509_signature_best_before(hx509_context context,
+ const AlgorithmIdentifier *alg,
+ time_t t)
+{
+ const struct signature_alg *md;
+
+ md = find_sig_alg(&alg->algorithm);
+ if (md == NULL) {
+ hx509_clear_error_string(context);
+ return HX509_SIG_ALG_NO_SUPPORTED;
+ }
+ if (md->best_before && md->best_before < t) {
+ hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE,
+ "Algorithm %s has passed it best before date",
+ md->name);
+ return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
+ }
+ return 0;
+}
int
_hx509_verify_signature(hx509_context context,
const SubjectPublicKeyInfo *spi;
spi = &signer->tbsCertificate.subjectPublicKeyInfo;
- if (der_heim_oid_cmp(&spi->algorithm.algorithm, (*md->key_oid)()) != 0) {
+ if (der_heim_oid_cmp(&spi->algorithm.algorithm, md->key_oid) != 0) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_DONT_MATCH_KEY_ALG;
}
{
const struct signature_alg *md;
- if (signer && signer->ops && signer->ops->handle_alg &&
- (*signer->ops->handle_alg)(signer, alg, COT_SIGN))
- {
- return (*signer->ops->sign)(context, signer, alg, data,
- signatureAlgorithm, sig);
- }
-
md = find_sig_alg(&alg->algorithm);
if (md == NULL) {
hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED,
ciphertext->length = ret;
ciphertext->data = to;
- ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(), encryption_oid);
+ ret = der_copy_oid(&asn1_oid_id_pkcs1_rsaEncryption, encryption_oid);
if (ret) {
der_free_octet_string(ciphertext);
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
{
*ctx = NULL;
- if (der_heim_oid_cmp(oid, oid_id_pkcs1_rsaEncryption()) != 0) {
+ if (der_heim_oid_cmp(oid, &asn1_oid_id_pkcs1_rsaEncryption) != 0) {
hx509_set_error_string(context, 0, EINVAL,
"private key not an RSA key");
return EINVAL;
return ret;
}
-
/*
*
*/
-static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") };
-
-static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
-const AlgorithmIdentifier _hx509_signature_sha512_data = {
- { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid)
-};
-
-static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 };
-const AlgorithmIdentifier _hx509_signature_sha384_data = {
- { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid)
-};
-
-static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
-const AlgorithmIdentifier _hx509_signature_sha256_data = {
- { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid)
-};
-
-static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 };
-const AlgorithmIdentifier _hx509_signature_sha1_data = {
- { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid)
-};
-
-static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 };
-const AlgorithmIdentifier _hx509_signature_md5_data = {
- { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid)
-};
-
-static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 };
-const AlgorithmIdentifier _hx509_signature_md2_data = {
- { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid)
-};
-
-static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 };
-const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = {
- { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL
-};
-
-static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 };
-const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = {
- { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL
-};
-
-static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 };
-const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = {
- { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL
-};
-
-static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 };
-const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = {
- { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL
-};
-
-static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 };
-const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = {
- { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL
-};
-
-static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 };
-const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = {
- { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL
-};
-
-static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 };
-const AlgorithmIdentifier _hx509_signature_rsa_data = {
- { 7, rk_UNCONST(rsa_oid) }, NULL
-};
-
-static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 };
-const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = {
- { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL
-};
-
-static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 };
-const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = {
- { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL
-};
-
-static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 };
-const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = {
- { 9, rk_UNCONST(aes128_cbc_oid) }, NULL
-};
-
-static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 };
-const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = {
- { 9, rk_UNCONST(aes256_cbc_oid) }, NULL
-};
-
const AlgorithmIdentifier *
hx509_signature_sha512(void)
{ return &_hx509_signature_sha512_data; }
hx509_signature_md2(void)
{ return &_hx509_signature_md2_data; }
+const AlgorithmIdentifier *
+hx509_signature_ecPublicKey(void)
+{ return &_hx509_signature_ecPublicKey; }
+
+const AlgorithmIdentifier *
+hx509_signature_ecdsa_with_sha256(void)
+{ return &_hx509_signature_ecdsa_with_sha256_data; }
+
+const AlgorithmIdentifier *
+hx509_signature_ecdsa_with_sha1(void)
+{ return &_hx509_signature_ecdsa_with_sha1_data; }
+
const AlgorithmIdentifier *
hx509_signature_rsa_with_sha512(void)
{ return &_hx509_signature_rsa_with_sha512_data; }
if (--(*key)->ref > 0)
return 0;
- if ((*key)->private_key.rsa)
- RSA_free((*key)->private_key.rsa);
+ if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) {
+ if ((*key)->private_key.rsa)
+ RSA_free((*key)->private_key.rsa);
+#ifdef HAVE_OPENSSL
+ } else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, &asn1_oid_id_ecPublicKey) == 0) {
+ if ((*key)->private_key.ecdsa)
+ EC_KEY_free((*key)->private_key.ecdsa);
+#endif
+ }
(*key)->private_key.rsa = NULL;
free(*key);
*key = NULL;
if (key->private_key.rsa)
RSA_free(key->private_key.rsa);
key->private_key.rsa = ptr;
- key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption();
+ key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption;
key->md = &pkcs1_rsa_sha1_alg;
}
heim_oid *data)
{
int ret;
- ret = der_copy_oid((*key->ops->key_oid)(), data);
+ ret = der_copy_oid(key->ops->key_oid, data);
if (ret)
hx509_set_error_string(context, 0, ret, "malloc out of memory");
return ret;
struct hx509cipher {
const char *name;
+ int flags;
+#define CIPHER_WEAK 1
const heim_oid *(*oid_func)(void);
const AlgorithmIdentifier *(*ai_func)(void);
const EVP_CIPHER *(*evp_func)(void);
struct hx509_crypto_data {
char *name;
+ int flags;
+#define ALLOW_WEAK 1
const struct hx509cipher *cipher;
const EVP_CIPHER *c;
heim_octet_string key;
static const struct hx509cipher ciphers[] = {
{
"rc2-cbc",
+ CIPHER_WEAK,
oid_id_pkcs3_rc2_cbc,
NULL,
EVP_rc2_cbc,
},
{
"rc2-cbc",
+ CIPHER_WEAK,
oid_id_rsadsi_rc2_cbc,
NULL,
EVP_rc2_cbc,
},
{
"rc2-40-cbc",
+ CIPHER_WEAK,
oid_private_rc2_40,
NULL,
EVP_rc2_40_cbc,
},
{
"des-ede3-cbc",
+ 0,
oid_id_pkcs3_des_ede3_cbc,
NULL,
EVP_des_ede3_cbc,
},
{
"des-ede3-cbc",
+ 0,
oid_id_rsadsi_des_ede3_cbc,
hx509_crypto_des_rsdi_ede3_cbc,
EVP_des_ede3_cbc,
},
{
"aes-128-cbc",
+ 0,
oid_id_aes_128_cbc,
hx509_crypto_aes128_cbc,
EVP_aes_128_cbc,
},
{
"aes-192-cbc",
+ 0,
oid_id_aes_192_cbc,
NULL,
EVP_aes_192_cbc,
},
{
"aes-256-cbc",
+ 0,
oid_id_aes_256_cbc,
hx509_crypto_aes256_cbc,
EVP_aes_256_cbc,
return 0;
}
+void
+hx509_crypto_allow_weak(hx509_crypto crypto)
+{
+ crypto->flags |= ALLOW_WEAK;
+}
+
int
hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length)
{
*ciphertext = NULL;
+ if ((crypto->cipher->flags & CIPHER_WEAK) &&
+ (crypto->flags & ALLOW_WEAK) == 0)
+ return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
+
assert(EVP_CIPHER_iv_length(crypto->c) == ivec->length);
EVP_CIPHER_CTX_init(&evp);
clear->data = NULL;
clear->length = 0;
+ if ((crypto->cipher->flags & CIPHER_WEAK) &&
+ (crypto->flags & ALLOW_WEAK) == 0)
+ return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
+
if (ivec && EVP_CIPHER_iv_length(crypto->c) < ivec->length)
return HX509_CRYPTO_INTERNAL_ERROR;
if (ret)
goto out;
+ hx509_crypto_allow_weak(c);
+
ret = hx509_crypto_set_key_data(c, key->data, key->length);
if (ret) {
hx509_crypto_destroy(c);
const EVP_MD **md,
PBE_string2key_func *s2k)
{
- if (der_heim_oid_cmp(oid, oid_id_pbewithSHAAnd40BitRC2_CBC()) == 0) {
+ if (der_heim_oid_cmp(oid, &asn1_oid_id_pbewithSHAAnd40BitRC2_CBC) == 0) {
*c = EVP_rc2_40_cbc();
*md = EVP_sha1();
*s2k = PBE_string2key;
*/
-int
-_hx509_match_keys(hx509_cert c, hx509_private_key private_key)
+static int
+match_keys_rsa(hx509_cert c, hx509_private_key private_key)
{
const Certificate *cert;
const SubjectPublicKeyInfo *spi;
return ret == 1;
}
+static int
+match_keys_ec(hx509_cert c, hx509_private_key private_key)
+{
+ return 1; /* XXX use EC_KEY_check_key */
+}
+
+
+int
+_hx509_match_keys(hx509_cert c, hx509_private_key key)
+{
+ if (der_heim_oid_cmp(key->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0)
+ return match_keys_rsa(c, key);
+ if (der_heim_oid_cmp(key->ops->key_oid, &asn1_oid_id_ecPublicKey) == 0)
+ return match_keys_ec(c, key);
+ return 0;
+
+}
+
+
static const heim_oid *
find_keytype(const hx509_private_key key)
{
md = find_sig_alg(key->signature_alg);
if (md == NULL)
return NULL;
- return (*md->key_oid)();
+ return md->key_oid;
}
-
int
hx509_crypto_select(const hx509_context context,
int type,
hx509_peer_info peer,
AlgorithmIdentifier *selected)
{
- const AlgorithmIdentifier *def;
+ const AlgorithmIdentifier *def = NULL;
size_t i, j;
int ret, bits;
if (type == HX509_SELECT_DIGEST) {
bits = SIG_DIGEST;
- def = _hx509_crypto_default_digest_alg;
+ if (source)
+ def = alg_for_privatekey(source, type);
+ if (def == NULL)
+ def = _hx509_crypto_default_digest_alg;
} else if (type == HX509_SELECT_PUBLIC_SIG) {
bits = SIG_PUBLIC_SIG;
/* XXX depend on `source´ and `peer´ */
- def = _hx509_crypto_default_sig_alg;
+ if (source)
+ def = alg_for_privatekey(source, type);
+ if (def == NULL)
+ def = _hx509_crypto_default_sig_alg;
} else if (type == HX509_SELECT_SECRET_ENC) {
bits = SIG_SECRET;
def = _hx509_crypto_default_secret_alg;
for (j = 0; sig_algs[j]; j++) {
if ((sig_algs[j]->flags & bits) != bits)
continue;
- if (der_heim_oid_cmp((*sig_algs[j]->sig_oid)(),
+ if (der_heim_oid_cmp(sig_algs[j]->sig_oid,
&peer->val[i].algorithm) != 0)
continue;
if (keytype && sig_algs[j]->key_oid &&
- der_heim_oid_cmp(keytype, (*sig_algs[j]->key_oid)()))
+ der_heim_oid_cmp(keytype, sig_algs[j]->key_oid))
continue;
/* found one, use that */
if (sig_algs[i]->sig_alg == NULL)
continue;
if (keytype && sig_algs[i]->key_oid &&
- der_heim_oid_cmp((*sig_algs[i]->key_oid)(), keytype))
+ der_heim_oid_cmp(sig_algs[i]->key_oid, keytype))
continue;
/* found one, add that to the list */
goto out;
*val = ptr;
- ret = copy_AlgorithmIdentifier((*sig_algs[i]->sig_alg)(), &(*val)[len]);
+ ret = copy_AlgorithmIdentifier(sig_algs[i]->sig_alg, &(*val)[len]);
if (ret)
goto out;
len++;
if (bits & SIG_SECRET) {
for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) {
-
+
+ if (ciphers[i].flags & CIPHER_WEAK)
+ continue;
if (ciphers[i].ai_func == NULL)
continue;
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_env Hx509 enviroment functions
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_error Hx509 error reporting functions
*/
#include "hx_locl.h"
-RCSID("$ID$");
int
_hx509_map_file_os(const char *fn, heim_octet_string *os)
#ifndef HEIMDAL_HX509_H
#define HEIMDAL_HX509_H 1
-#include <heim_asn1.h>
#include <rfc2459_asn1.h>
+#include <stdarg.h>
+#include <stdio.h>
typedef struct hx509_cert_attribute_data *hx509_cert_attribute;
typedef struct hx509_cert_data *hx509_cert;
/* flags to hx509_cms_unenvelope */
#define HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT 0x01
+#define HX509_CMS_UE_ALLOW_WEAK 0x02
+
+/* flags to hx509_cms_envelope_1 */
+#define HX509_CMS_EV_NO_KU_CHECK 0x01
+#define HX509_CMS_EV_ALLOW_WEAK 0x02
+
+/* flags to hx509_cms_verify_signed */
+#define HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH 0x01
+#define HX509_CMS_VS_NO_KU_CHECK 0x02
+#define HX509_CMS_VS_ALLOW_ZERO_SIGNER 0x04
+#define HX509_CMS_VS_NO_VALIDATE 0x08
/* selectors passed to hx509_crypto_select and hx509_crypto_available */
#define HX509_SELECT_ALL 0
#define HX509_CA_TEMPLATE_EKU 64
/* flags hx509_cms_create_signed* */
-#define HX509_CMS_SIGATURE_DETACHED 1
-#define HX509_CMS_SIGATURE_ID_NAME 2
+#define HX509_CMS_SIGNATURE_DETACHED 0x01
+#define HX509_CMS_SIGNATURE_ID_NAME 0x02
+#define HX509_CMS_SIGNATURE_NO_SIGNER 0x04
/* hx509_verify_hostname nametype */
typedef enum {
error_code NO_PROMPTER, "No prompter function defined"
error_code SIGNATURE_WITHOUT_SIGNER, "Signature require signer, but non available"
error_code RSA_PUBLIC_ENCRYPT, "RSA public encyption failed"
-error_code RSA_PRIVATE_ENCRYPT, "RSA public encyption failed"
-error_code RSA_PUBLIC_DECRYPT, "RSA private decryption failed"
+error_code RSA_PRIVATE_ENCRYPT, "RSA private encyption failed"
+error_code RSA_PUBLIC_DECRYPT, "RSA public decryption failed"
error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed"
+error_code ALGORITHM_BEST_BEFORE, "Algorithm has passed its best before date"
# revoke related errors
index 96
/* $Id$ */
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <stdio.h>
#include <stdlib.h>
Name *subject_name;
hx509_path *path;
char *friendlyname;
- int (*cmp_func)(void *, hx509_cert);
+ int (*cmp_func)(hx509_context, hx509_cert, void *);
void *cmp_func_ctx;
heim_octet_string *keyhash_sha1;
time_t timenow;
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_keyset Certificate store operations
hx509_certs_end_seq(context, certs, cursor);
if (ret)
return ret;
+ /**
+ * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
+ * the query.
+ */
if (c == NULL) {
hx509_clear_error_string(context);
return HX509_CERT_NOT_FOUND;
return 0;
}
+/**
+ * Filter certificate matching the query.
+ *
+ * @param context a hx509 context.
+ * @param certs certificate store to search.
+ * @param q query allocated with @ref hx509_query functions.
+ * @param result the filtered certificate store, caller must free with
+ * hx509_certs_free().
+ *
+ * @return Returns an hx509 error code.
+ *
+ * @ingroup hx509_keyset
+ */
+
+int
+hx509_certs_filter(hx509_context context,
+ hx509_certs certs,
+ const hx509_query *q,
+ hx509_certs *result)
+{
+ hx509_cursor cursor;
+ hx509_cert c;
+ int ret, found = 0;
+
+ _hx509_query_statistic(context, 0, q);
+
+ ret = hx509_certs_init(context, "MEMORY:filter-certs", 0,
+ NULL, result);
+ if (ret)
+ return ret;
+
+ ret = hx509_certs_start_seq(context, certs, &cursor);
+ if (ret) {
+ hx509_certs_free(result);
+ return ret;
+ }
+
+ c = NULL;
+ while (1) {
+ ret = hx509_certs_next_cert(context, certs, cursor, &c);
+ if (ret)
+ break;
+ if (c == NULL)
+ break;
+ if (_hx509_query_match_cert(context, q, c)) {
+ hx509_certs_add(context, *result, c);
+ found = 1;
+ }
+ hx509_cert_free(c);
+ }
+
+ hx509_certs_end_seq(context, certs, cursor);
+ if (ret) {
+ hx509_certs_free(result);
+ return ret;
+ }
+
+ /**
+ * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
+ * the query.
+ */
+ if (!found) {
+ hx509_certs_free(result);
+ hx509_clear_error_string(context);
+ return HX509_CERT_NOT_FOUND;
+ }
+
+ return 0;
+}
+
+
static int
certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
{
*/
#include "hx_locl.h"
-RCSID("$Id$");
#include <dirent.h>
/*
*/
#include "hx_locl.h"
-RCSID("$Id$");
typedef enum { USE_PEM, USE_DER } outformat;
parse_certificate(hx509_context context, const char *fn,
struct hx509_collector *c,
const hx509_pem_header *headers,
- const void *data, size_t len)
+ const void *data, size_t len,
+ const AlgorithmIdentifier *ai)
{
hx509_cert cert;
int ret;
}
static int
-parse_rsa_private_key(hx509_context context, const char *fn,
- struct hx509_collector *c,
- const hx509_pem_header *headers,
- const void *data, size_t len)
+parse_private_key(hx509_context context, const char *fn,
+ struct hx509_collector *c,
+ const hx509_pem_header *headers,
+ const void *data, size_t len,
+ const AlgorithmIdentifier *ai)
{
int ret = 0;
const char *enc;
if (strcmp(enc, "4,ENCRYPTED") != 0) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
- "RSA key encrypted in unknown method %s "
+ "Private key encrypted in unknown method %s "
"in file",
enc, fn);
hx509_clear_error_string(context);
dek = hx509_pem_find_header(headers, "DEK-Info");
if (dek == NULL) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
- "Encrypted RSA missing DEK-Info");
+ "Encrypted private key missing DEK-Info");
return HX509_PARSING_KEY_FAILED;
}
if (cipher == NULL) {
free(ivdata);
hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
- "RSA key encrypted with "
+ "Private key encrypted with "
"unsupported cipher: %s",
type);
free(type);
if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) {
free(ivdata);
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
- "Salt have wrong length in RSA key file");
+ "Salt have wrong length in "
+ "private key file");
return HX509_PARSING_KEY_FAILED;
}
password = pw->val[i];
passwordlen = strlen(password);
- ret = try_decrypt(context, c, hx509_signature_rsa(),
- cipher, ivdata, password, passwordlen,
- data, len);
+ ret = try_decrypt(context, c, ai, cipher, ivdata,
+ password, passwordlen, data, len);
if (ret == 0) {
decrypted = 1;
break;
ret = hx509_lock_prompt(lock, &prompt);
if (ret == 0)
- ret = try_decrypt(context, c, hx509_signature_rsa(),
- cipher, ivdata, password, strlen(password),
- data, len);
+ ret = try_decrypt(context, c, ai, cipher, ivdata, password,
+ strlen(password), data, len);
/* XXX add password to lock password collection ? */
memset(password, 0, sizeof(password));
}
keydata.data = rk_UNCONST(data);
keydata.length = len;
- ret = _hx509_collector_private_key_add(context,
- c,
- hx509_signature_rsa(),
- NULL,
- &keydata,
- NULL);
+ ret = _hx509_collector_private_key_add(context, c, ai, NULL,
+ &keydata, NULL);
}
return ret;
struct pem_formats {
const char *name;
int (*func)(hx509_context, const char *, struct hx509_collector *,
- const hx509_pem_header *, const void *, size_t);
+ const hx509_pem_header *, const void *, size_t,
+ const AlgorithmIdentifier *);
+ const AlgorithmIdentifier *(*ai)(void);
} formats[] = {
- { "CERTIFICATE", parse_certificate },
- { "RSA PRIVATE KEY", parse_rsa_private_key }
+ { "CERTIFICATE", parse_certificate, NULL },
+ { "RSA PRIVATE KEY", parse_private_key, hx509_signature_rsa },
+ { "EC PRIVATE KEY", parse_private_key, hx509_signature_ecPublicKey }
};
for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
const char *q = formats[j].name;
if (strcasecmp(type, q) == 0) {
- ret = (*formats[j].func)(context, NULL, pem_ctx->c, header, data, len);
+ const AlgorithmIdentifier *ai = NULL;
+ if (formats[j].ai != NULL)
+ ai = (*formats[j].ai)();
+
+ ret = (*formats[j].func)(context, NULL, pem_ctx->c,
+ header, data, len, ai);
if (ret == 0)
break;
}
}
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
- ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length);
+ const AlgorithmIdentifier *ai = NULL;
+ if (formats[i].ai != NULL)
+ ai = (*formats[i].ai)();
+
+ ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length, ai);
if (ret == 0)
break;
}
*/
#include "hx_locl.h"
-RCSID("$Id$");
#ifdef HAVE_FRAMEWORK_SECURITY
CSSM_DATA sig, in;
int fret = 0;
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
if(cret) abort();
kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
RSA * rsa, int padding)
{
- return -1;
+ struct kc_rsa *kc = RSA_get_app_data(rsa);
+
+ CSSM_RETURN cret;
+ OSStatus ret;
+ const CSSM_ACCESS_CREDENTIALS *creds;
+ SecKeyRef privKeyRef = (SecKeyRef)kc->item;
+ CSSM_CSP_HANDLE cspHandle;
+ const CSSM_KEY *cssmKey;
+ CSSM_CC_HANDLE handle = 0;
+ CSSM_DATA out, in, rem;
+ int fret = 0;
+ CSSM_SIZE outlen = 0;
+ char remdata[1024];
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+
+ cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
+ if(cret) abort();
+
+ cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
+ if(cret) abort();
+
+ ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
+ kSecCredentialTypeDefault, &creds);
+ if(ret) abort();
+
+
+ ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
+ CSSM_ALGID_RSA,
+ creds,
+ cssmKey,
+ CSSM_PADDING_PKCS1,
+ &handle);
+ if(ret) abort();
+
+ in.Data = (uint8 *)from;
+ in.Length = flen;
+
+ out.Data = (uint8 *)to;
+ out.Length = kc->keysize;
+
+ rem.Data = (uint8 *)remdata;
+ rem.Length = sizeof(remdata);
+
+ cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
+ if(cret) {
+ /* cssmErrorString(cret); */
+ fret = -1;
+ } else
+ fret = out.Length;
+
+ if(handle)
+ CSSM_DeleteContext(handle);
+
+ return fret;
}
static int
struct iter *iter = cursor;
if (iter->certs) {
- int ret;
- ret = hx509_certs_end_seq(context, iter->certs, iter->cursor);
+ hx509_certs_end_seq(context, iter->certs, iter->cursor);
hx509_certs_free(&iter->certs);
} else {
CFRelease(iter->searchRef);
*/
#include "hx_locl.h"
-RCSID("Id$");
/*
* Should use two hash/tree certificates intead of a array. Criteria
*/
#include "hx_locl.h"
-RCSID("$Id$");
static int
*/
#include "hx_locl.h"
-RCSID("$Id$");
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
*/
#include "hx_locl.h"
-RCSID("$Id$");
struct ks_pkcs12 {
hx509_certs certs;
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_lock Locking and unlocking certificates and encrypted data.
/*
- * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
+ * Copyright (c) 2004 - 2009 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
#include "hx_locl.h"
#include <wind.h>
-RCSID("$Id$");
/**
* @page page_name PKIX/X.509 Names
_hx509_Name_to_string(const Name *n, char **str)
{
size_t total_len = 0;
- int i, j;
+ int i, j, ret;
*str = strdup("");
if (*str == NULL)
ss = ds->u.utf8String;
break;
case choice_DirectoryString_bmpString: {
- uint16_t *bmp = ds->u.bmpString.data;
+ const uint16_t *bmp = ds->u.bmpString.data;
size_t bmplen = ds->u.bmpString.length;
size_t k;
- ss = malloc(bmplen + 1);
+ ret = wind_ucs2utf8_length(bmp, bmplen, &k);
+ if (ret)
+ return ret;
+
+ ss = malloc(k + 1);
if (ss == NULL)
_hx509_abort("allocation failure"); /* XXX */
- for (k = 0; k < bmplen; k++)
- ss[k] = bmp[k] & 0xff; /* XXX */
+ ret = wind_ucs2utf8(bmp, bmplen, ss, NULL);
+ if (ret)
+ return ret;
ss[k] = '\0';
break;
}
ss[ds->u.teletexString.length] = '\0';
break;
case choice_DirectoryString_universalString: {
- uint32_t *uni = ds->u.universalString.data;
+ const uint32_t *uni = ds->u.universalString.data;
size_t unilen = ds->u.universalString.length;
size_t k;
- ss = malloc(unilen + 1);
+ ret = wind_ucs4utf8_length(uni, unilen, &k);
+ if (ret)
+ return ret;
+
+ ss = malloc(k + 1);
if (ss == NULL)
_hx509_abort("allocation failure"); /* XXX */
- for (k = 0; k < unilen; k++)
- ss[k] = uni[k] & 0xff; /* XXX */
+ ret = wind_ucs4utf8(uni, unilen, ss, NULL);
+ if (ret)
+ return ret;
ss[k] = '\0';
break;
}
if (name == NULL)
return ENOMEM;
ret = wind_utf8ucs4(ds->u.utf8String, name, &len);
- if (ret)
+ if (ret) {
+ free(name);
return ret;
+ }
break;
default:
_hx509_abort("unknown directory type: %d", ds->element);
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_peer Hx509 crypto selecting functions
*/
#include "hx_locl.h"
-RCSID("$Id$");
/**
* @page page_print Hx509 printing functions
#include "hx_locl.h"
#include <pkcs10_asn1.h>
-RCSID("$Id$");
struct hx509_request_data {
hx509_name name;
*/
#include "hx_locl.h"
-RCSID("$Id$");
struct revoke_crl {
char *path;
#include <stdlib.h>
#include <hx_locl.h>
-RCSID("$Id$");
%}
*/
#include "hx_locl.h"
-RCSID("$Id$");
static int
test_name(hx509_context context, const char *name)
#else
HEIMDAL_MUTEX_unlock(&acc_mutex);
krb5_set_error_message(context, KRB5_CC_NOSUPP,
- N_("no support for shared object", "file, error"));
+ N_("no support for shared object", ""));
return KRB5_CC_NOSUPP;
#endif
}
addr->length = incred->addresses.val[i].address.length;
addr->data = malloc(addr->length);
if (addr->data == NULL) {
+ free(addr);
ret = ENOMEM;
goto fail;
}
error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
if (error == ccNoError) {
+ cc_time_t offset;
error = get_cc_name(a);
if (error != ccNoError) {
acc_close(context, *id);
*id = NULL;
return translate_cc_error(context, error);
}
+
+ error = (*a->ccache->func->get_kdc_time_offset)(a->ccache,
+ cc_credentials_v5,
+ &offset);
+ if (error == 0)
+ context->kdc_sec_offset = offset;
+
+ error = 0;
} else if (error == ccErrCCacheNotFound) {
a->ccache = NULL;
a->cache_name = NULL;
- error = 0;
} else {
*id = NULL;
return translate_cc_error(context, error);
name);
}
+ if (error == 0 && context->kdc_sec_offset)
+ error = (*a->ccache->func->set_kdc_time_offset)(a->ccache,
+ cc_credentials_v5,
+ context->kdc_sec_offset);
+
return translate_cc_error(context, error);
}
krb5_storage *sp;
sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address));
+ if (sp == NULL)
+ return ENOMEM;
+
/* for totally obscure reasons, these are not in network byteorder */
krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
for (a = ai, i = 0; a != NULL; a = a->ai_next) {
if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i]))
continue;
- if(krb5_address_search(context, &addresses->val[i], addresses))
+ if(krb5_address_search(context, &addresses->val[i], addresses)) {
+ krb5_free_address(context, &addresses->val[i]);
continue;
- addresses->len = i;
+ }
i++;
+ addresses->len = i;
}
freeaddrinfo (ai);
return 0;
*p++ = (2 >> 24) & 0xFF;
memcpy (p, &port, 2);
- p += 2;
return 0;
}
const PrincipalName from,
const Realm realm)
{
- krb5_principal p = malloc(sizeof(*p));
+ krb5_error_code ret;
+ krb5_principal p;
+
+ p = malloc(sizeof(*p));
if (p == NULL)
return ENOMEM;
- copy_PrincipalName(&from, &p->name);
+ ret = copy_PrincipalName(&from, &p->name);
+ if (ret) {
+ free(p);
+ return ret;
+ }
p->realm = strdup(realm);
- if (p->realm == NULL)
+ if (p->realm == NULL) {
+ free_PrincipalName(&p->name);
+ free(p);
return ENOMEM;
+ }
*principal = p;
return 0;
}
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;
RCSID("$Id$");
+/**
+ * @page krb5_ccache_intro The credential cache functions
+ * @section section_krb5_ccache Kerberos credential caches
+ *
+ * krb5_ccache structure holds a Kerberos credential cache.
+ *
+ * Heimdal support the follow types of credential caches:
+ *
+ * - SDB
+ * Store the credential in a database
+ * - FILE
+ * Store the credential in memory
+ * - MEMORY
+ * Store the credential in memory
+ * - API
+ * A credential cache server based solution for Mac OS X
+ * - KCM
+ * A credential cache server based solution for all platforms
+ *
+ * @subsection Example
+ *
+ * This is a minimalistic version of klist:
+@code
+#include <krb5.h>
+
+int
+main (int argc, char **argv)
+{
+ krb5_context context;
+ krb5_cc_cursor cursor;
+ krb5_error_code ret;
+ krb5_ccache id;
+ krb5_creds creds;
+
+ if (krb5_init_context (&context) != 0)
+ errx(1, "krb5_context");
+
+ ret = krb5_cc_default (context, &id);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_cc_default");
+
+ ret = krb5_cc_start_seq_get(context, id, &cursor);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
+
+ while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){
+ char *principal;
+
+ krb5_unparse_name_short(context, creds.server, &principal);
+ printf("principal: %s\\n", principal);
+ free(principal);
+ krb5_free_cred_contents (context, &creds);
+ }
+ ret = krb5_cc_end_seq_get(context, id, &cursor);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
+
+ krb5_cc_close(context, id);
+
+ krb5_free_context(context);
+ return 0;
+}
+* @endcode
+*/
+
/**
* Add a new ccache type with operations `ops', overwriting any
* existing one if `override'.
/**
* Start iterating over `id', `cursor' is initialized to the
- * beginning.
+ * beginning. Caller must free the cursor with krb5_cc_end_seq_get().
*
* @return Return an error code or 0, see krb5_get_error_message().
*
}
/**
- * Search for a matching credential cache of type `type' that have the
+ * Search for a matching credential cache that have the
* `principal' as the default principal. On success, `id' needs to be
* freed with krb5_cc_close() or krb5_cc_destroy().
*
+ * @param context A Kerberos 5 context
+ * @param client The principal to search for
+ * @param id the returned credential cache
+ *
* @return On failure, error code is returned and `id' is set to NULL.
*
* @ingroup krb5_ccache
if (ret)
return ret;
- while ((ret = krb5_cccol_cursor_next (context, cursor, &cache)) == 0) {
+ while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) {
krb5_principal principal;
ret = krb5_cc_get_principal(context, cache, &principal);
krb5_unparse_name(context, client, &str);
krb5_set_error_message(context, KRB5_CC_NOTFOUND,
- N_("Principal %s not found in a "
+ N_("Principal %s not found in any "
"credential cache", ""),
str ? str : "<out of memory>");
if (str)
}
ret = krb5_make_principal(context, &cred->server,
- krb5_principal_get_realm(context, client),
+ KRB5_REALM_NAME,
KRB5_CONF_NAME, name, pname, NULL);
free(pname);
if (ret) {
* @param principal configuration for a specific principal, if
* NULL, global for the whole cache.
* @param name name under which the configuraion is stored.
- * @param data data to store
+ * @param data data to store, if NULL, configure is removed.
*
* @ingroup krb5_ccache
*/
if (ret && ret != KRB5_CC_NOTFOUND)
goto out;
- /* not that anyone care when this expire */
- cred.times.authtime = time(NULL);
- cred.times.endtime = cred.times.authtime + 3600 * 24 * 30;
-
- ret = krb5_data_copy(&cred.ticket, data->data, data->length);
- if (ret)
- goto out;
-
- ret = krb5_cc_store_cred(context, id, &cred);
+ if (data) {
+ /* not that anyone care when this expire */
+ cred.times.authtime = time(NULL);
+ cred.times.endtime = cred.times.authtime + 3600 * 24 * 30;
+
+ ret = krb5_data_copy(&cred.ticket, data->data, data->length);
+ if (ret)
+ goto out;
+
+ ret = krb5_cc_store_cred(context, id, &cred);
+ }
out:
krb5_free_cred_contents (context, &cred);
* @param cache the returned cursor, pointer is set to NULL on failure
* and a cache on success. The returned cache needs to be freed
* with krb5_cc_close() or destroyed with krb5_cc_destroy().
+ * MIT Kerberos behavies slightly diffrent and sets cache to NULL
+ * when all caches are iterated over and return 0.
*
* @return Return 0 or and error, KRB5_CC_END is returned at the end
* of iteration. See krb5_get_error_message().
* and mtime is 0, there was no credentials in the caches.
*
* @param context A Kerberos 5 context
- * @param id The credential cache to probe
+ * @param type The credential cache to probe, if NULL, all type are traversed.
* @param mtime the last modification time, set to 0 on error.
* @return Return 0 or and error. See krb5_get_error_message().
if (ret)
return ret;
- while ((ret = krb5_cccol_cursor_next (context, cursor, &id)) == 0) {
+ while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) {
if (type && strcmp(krb5_cc_get_type(context, id), type) != 0)
continue;
return 0;
}
+/**
+ * Return a friendly name on credential cache. Free the result with krb5_xfree().
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_ccache
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_get_friendly_name(krb5_context context,
+ krb5_ccache id,
+ char **name)
+{
+ krb5_error_code ret;
+ krb5_data data;
+
+ ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data);
+ if (ret) {
+ krb5_principal principal;
+ ret = krb5_cc_get_principal(context, id, &principal);
+ if (ret)
+ return ret;
+ ret = krb5_unparse_name(context, principal, name);
+ krb5_free_principal(context, principal);
+ } else {
+ ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data);
+ krb5_data_free(&data);
+ if (ret <= 0) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ } else
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/**
+ * Set the friendly name on credential cache.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_ccache
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_set_friendly_name(krb5_context context,
+ krb5_ccache id,
+ const char *name)
+{
+ krb5_data data;
+
+ data.data = rk_UNCONST(name);
+ data.length = strlen(name);
+
+ return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data);
+}
RCSID("$Id$");
+#undef KRB5_DEPRECATED
+#define KRB5_DEPRECATED
#undef __attribute__
#define __attribute__(X)
krb5_data passwd_data;
size_t len;
u_char header[6];
- u_char *p;
struct iovec iov[3];
struct msghdr msghdr;
goto out2;
len = 6 + ap_req_data.length + krb_priv_data.length;
- p = header;
- *p++ = (len >> 8) & 0xFF;
- *p++ = (len >> 0) & 0xFF;
- *p++ = 0;
- *p++ = 1;
- *p++ = (ap_req_data.length >> 8) & 0xFF;
- *p++ = (ap_req_data.length >> 0) & 0xFF;
+ header[0] = (len >> 8) & 0xFF;
+ header[1] = (len >> 0) & 0xFF;
+ header[2] = 0;
+ header[3] = 1;
+ header[4] = (ap_req_data.length >> 8) & 0xFF;
+ header[5] = (ap_req_data.length >> 0) & 0xFF;
memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_name = NULL;
*p++ = 0xff;
*p++ = 0x80;
*p++ = (ap_req_data.length >> 8) & 0xFF;
- *p++ = (ap_req_data.length >> 0) & 0xFF;
+ *p = (ap_req_data.length >> 0) & 0xFF;
memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_name = NULL;
int *result_code,
krb5_data *result_code_string,
krb5_data *result_string)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
struct kpwd_proc *p = find_chpw_proto("change password");
#endif /* HEIMDAL_SMALLER */
/**
- * Change passwrod using creds.
+ * Change password using creds.
*
* @param context a Keberos context
* @param creds The initial kadmin/passwd for the principal or an admin principal
return ret;
}
-#ifndef HEIMDAL_SMALLER
-
/*
*
*/
return ret;
}
-#endif /* !HEIMDAL_SMALLER */
-
/*
*
*/
#include "krb5_locl.h"
-#undef __attribute__
-#define __attribute__(x)
+#undef KRB5_DEPRECATED
+#define KRB5_DEPRECATED
RCSID("$Id$");
size_t length,
EncTicketPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_EncTicketPart(data, length, t, len);
}
size_t length,
EncTicketPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_EncTicketPart(data, length, t, len);
}
size_t length,
EncASRepPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_EncASRepPart(data, length, t, len);
}
size_t length,
EncASRepPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_EncASRepPart(data, length, t, len);
}
size_t length,
EncTGSRepPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_EncTGSRepPart(data, length, t, len);
}
size_t length,
EncTGSRepPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_EncTGSRepPart(data, length, t, len);
}
size_t length,
EncAPRepPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_EncAPRepPart(data, length, t, len);
}
size_t length,
EncAPRepPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_EncAPRepPart(data, length, t, len);
}
size_t length,
Authenticator *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_Authenticator(data, length, t, len);
}
size_t length,
Authenticator *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_Authenticator(data, length, t, len);
}
size_t length,
EncKrbCredPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_EncKrbCredPart(data, length, t, len);
}
size_t length,
EncKrbCredPart *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_EncKrbCredPart (data, length, t, len);
}
size_t length,
ETYPE_INFO *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_ETYPE_INFO(data, length, t, len);
}
size_t length,
ETYPE_INFO *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_ETYPE_INFO (data, length, t, len);
}
size_t length,
ETYPE_INFO2 *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return decode_ETYPE_INFO2(data, length, t, len);
}
size_t length,
ETYPE_INFO2 *t,
size_t *len)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return encode_ETYPE_INFO2 (data, length, t, len);
}
return 0;
}
+/**
+ * Parse a configuration file and add the result into res. This
+ * interface can be used to parse several configuration files into one
+ * resulting krb5_config_section by calling it repeatably.
+ *
+ * @param context a Kerberos 5 context.
+ * @param fname a file name to a Kerberos configuration file
+ * @param res the returned result, must be free with krb5_free_config_files().
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_support
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_config_parse_file_multi (krb5_context context,
const char *fname,
krb5_config_section **res)
{
const char *str;
+ char *newfname = NULL;
unsigned lineno = 0;
krb5_error_code ret;
struct fileptr f;
+
+ /**
+ * If the fname starts with "~/" parse configuration file in the
+ * current users home directory. The behavior can be disabled and
+ * enabled by calling krb5_set_home_dir_access().
+ */
+ if (_krb5_homedir_access(context) && fname[0] == '~' && fname[1] == '/') {
+ const char *home = NULL;
+
+ if(!issuid())
+ home = getenv("HOME");
+
+ if (home == NULL) {
+ struct passwd *pw = getpwuid(getuid());
+ if(pw != NULL)
+ home = pw->pw_dir;
+ }
+ if (home) {
+ asprintf(&newfname, "%s%s", home, &fname[1]);
+ if (newfname == NULL) {
+ krb5_set_error_message(context, ret,
+ N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+ fname = newfname;
+ }
+ }
+
f.f = fopen(fname, "r");
f.s = NULL;
if(f.f == NULL) {
ret = errno;
krb5_set_error_message (context, ret, "open %s: %s",
fname, strerror(ret));
+ if (newfname)
+ free(newfname);
return ret;
}
fclose(f.f);
if (ret) {
krb5_set_error_message (context, ret, "%s:%u: %s", fname, lineno, str);
+ if (newfname)
+ free(newfname);
return ret;
}
+ if (newfname)
+ free(newfname);
return 0;
}
KRB5_LIB_VARIABLE const char *krb5_config_file =
#ifdef __APPLE__
+"~/Library/Preferences/edu.mit.Kerberos:"
"/Library/Preferences/edu.mit.Kerberos:"
#endif
SYSCONFDIR "/krb5.conf:/etc/krb5.conf";
krb5_cc_register(context, &krb5_acc_ops, TRUE);
krb5_cc_register(context, &krb5_fcc_ops, TRUE);
krb5_cc_register(context, &krb5_mcc_ops, TRUE);
-#ifdef HAVE_SQLITE
krb5_cc_register(context, &krb5_scc_ops, TRUE);
-#endif
#ifdef HAVE_KCM
krb5_cc_register(context, &krb5_kcm_ops, TRUE);
#endif
}
HEIMDAL_MUTEX_init(p->mutex);
+ p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
+
ret = krb5_get_default_config_files(&files);
if(ret)
goto out;
* Make a copy for the Kerberos 5 context, allocated krb5_contex shoud
* be freed with krb5_free_context().
*
- * @param in the Kerberos context to copy
+ * @param context the Kerberos context to copy
* @param out the copy of the Kerberos, set to NULL error.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
krb5_set_extra_addresses(context, NULL);
krb5_set_ignore_addresses(context, NULL);
krb5_set_send_to_kdc_func(context, NULL, NULL);
- if (context->mutex != NULL) {
- HEIMDAL_MUTEX_destroy(context->mutex);
- free(context->mutex);
- }
+
+ HEIMDAL_MUTEX_destroy(context->mutex);
+ free(context->mutex);
+
memset(context, 0, sizeof(*context));
free(context);
}
krb5_free_config_files(pp);
return ENOMEM;
}
- l = strsep_copy(&p, ":", fn, l + 1);
+ (void)strsep_copy(&p, ":", fn, l + 1);
ret = add_file(&pp, &len, fn);
if (ret) {
krb5_free_config_files(pp);
/**
* Free a list of configuration files.
*
- * @param filenames list to be freed.
+ * @param filenames list, terminated with a NULL pointer, to be
+ * freed. NULL is an valid argument.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
krb5_free_config_files(char **filenames)
{
char **p;
- for(p = filenames; *p != NULL; p++)
+ for(p = filenames; p && *p != NULL; p++)
free(*p);
free(filenames);
}
{
context->max_skew = t;
}
+
+/**
+ * Init encryption types in len, val with etypes.
+ *
+ * @param context Kerberos 5 context.
+ * @param len output length of val.
+ * @param val output array of enctypes.
+ * @param etypes etypes to set val and len to, if NULL, use default enctypes.
+
+ * @return Returns 0 to indicate success. Otherwise an kerberos et
+ * error code is returned, see krb5_get_error_message().
+ *
+ * @ingroup krb5
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_etype (krb5_context context,
+ unsigned *len,
+ krb5_enctype **val,
+ const krb5_enctype *etypes)
+{
+ unsigned int i;
+ krb5_error_code ret;
+ krb5_enctype *tmp = NULL;
+
+ ret = 0;
+ if (etypes == NULL) {
+ ret = krb5_get_default_in_tkt_etypes(context, &tmp);
+ if (ret)
+ return ret;
+ etypes = tmp;
+ }
+
+ for (i = 0; etypes[i]; ++i)
+ ;
+ *len = i;
+ *val = malloc(i * sizeof(**val));
+ if (i != 0 && *val == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto cleanup;
+ }
+ memmove (*val,
+ etypes,
+ i * sizeof(*tmp));
+cleanup:
+ if (tmp != NULL)
+ free (tmp);
+ return ret;
+}
+
+/*
+ * Allow homedir accces
+ */
+
+static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static krb5_boolean allow_homedir = TRUE;
+
+krb5_boolean
+_krb5_homedir_access(krb5_context context)
+{
+ krb5_boolean allow;
+
+ /* is never allowed for root */
+ if (geteuid() == 0)
+ return FALSE;
+
+ if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0)
+ return FALSE;
+
+ HEIMDAL_MUTEX_lock(&homedir_mutex);
+ allow = allow_homedir;
+ HEIMDAL_MUTEX_unlock(&homedir_mutex);
+ return allow;
+}
+
+/**
+ * Enable and disable home directory access on either the global state
+ * or the krb5_context state. By calling krb5_set_home_dir_access()
+ * with context set to NULL, the global state is configured otherwise
+ * the state for the krb5_context is modified.
+ *
+ * For home directory access to be allowed, both the global state and
+ * the krb5_context state have to be allowed.
+ *
+ * Administrator (root user), never uses the home directory.
+ *
+ * @param context a Kerberos 5 context or NULL
+ * @param allow allow if TRUE home directory
+ * @return the old value
+ *
+ */
+
+krb5_boolean
+krb5_set_home_dir_access(krb5_context context, krb5_boolean allow)
+{
+ krb5_boolean old;
+ if (context) {
+ old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE;
+ if (allow)
+ context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
+ else
+ context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS;
+ } else {
+ HEIMDAL_MUTEX_lock(&homedir_mutex);
+ old = allow_homedir;
+ allow_homedir = allow;
+ HEIMDAL_MUTEX_unlock(&homedir_mutex);
+ }
+
+ return old;
+}
#include "krb5-v4compat.h"
+#ifndef HEIMDAL_SMALLER
+
static krb5_error_code
check_ticket_flags(TicketFlags f)
{
krb5_free_creds (context, v5_creds);
return ret;
}
+
+#endif
#include "krb5_locl.h"
-RCSID("$Id$");
-
static u_long table[256];
#define CRC_GEN 0xEDB88320L
RCSID("$Id$");
-#undef __attribute__
-#define __attribute__(X)
+#undef KRB5_DEPRECATED
+#define KRB5_DEPRECATED
#ifndef HEIMDAL_SMALLER
/* keep this for compatibility with older code */
krb5_error_code KRB5_LIB_FUNCTION
krb5_free_creds_contents (krb5_context context, krb5_creds *c)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
return krb5_free_cred_contents (context, c);
}
}
if (match && (whichfields & KRB5_TC_MATCH_KEYTYPE))
- match = krb5_enctypes_compatible_keys(context,
- mcreds->session.keytype,
- creds->session.keytype);
+ match = mcreds->session.keytype == creds->session.keytype;
if (match && (whichfields & KRB5_TC_MATCH_FLAGS_EXACT))
match = mcreds->flags.i == creds->flags.i;
RCSID("$Id$");
#include <pkinit_asn1.h>
-#undef __attribute__
-#define __attribute__(X)
+#undef KRB5_DEPRECATED
+#define KRB5_DEPRECATED
#define WEAK_ENCTYPES 1
static void free_key_data(krb5_context,
struct key_data *,
struct encryption_type *);
+static void free_key_schedule(krb5_context,
+ struct key_data *,
+ struct encryption_type *);
static krb5_error_code usage2arcfour (krb5_context, unsigned *);
static void xor (DES_cblock *, const unsigned char *);
{
krb5_error_code ret;
struct encryption_type *et = _find_enctype(key->key->keytype);
- struct key_type *kt = et->keytype;
+ struct key_type *kt;
+
+ if (et == NULL) {
+ krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
+ N_("encryption type %d not supported", ""),
+ key->key->keytype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+
+ kt = et->keytype;
if(kt->schedule == NULL)
return 0;
return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
}
keyed_checksum = (ct->flags & F_KEYED) != 0;
- if(keyed_checksum && crypto == NULL) {
- krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
- N_("Checksum type %s is keyed but no "
- "crypto context (key) was passed in", ""),
- ct->name);
- return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
- }
if(keyed_checksum) {
+ struct checksum_type *kct;
+ if (crypto == NULL) {
+ krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
+ N_("Checksum type %s is keyed but no "
+ "crypto context (key) was passed in", ""),
+ ct->name);
+ return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
+ }
+ kct = crypto->et->keyed_checksum;
+ if (kct != NULL && kct->type != ct->type) {
+ krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
+ N_("Checksum type %s is keyed, but "
+ "the key type %s passed didnt have that checksum "
+ "type as the keyed type", ""),
+ ct->name, crypto->et->name);
+ return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
+ }
+
ret = get_checksum_key(context, crypto, usage, ct, &dkey);
if (ret)
return ret;
{
const EVP_CIPHER *c = (*crypto->et->keytype->evp)();
EVP_CIPHER_CTX ctx;
- /* XXX blksz 1 for cts, so we can't use that */
+
EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */
EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1);
- EVP_Cipher(&ctx, out->data, result.checksum.data, 16);
+ EVP_Cipher(&ctx, out->data, result.checksum.data,
+ crypto->et->blocksize);
EVP_CIPHER_CTX_cleanup(&ctx);
}
}
-/* if two enctypes have compatible keys */
-krb5_boolean KRB5_LIB_FUNCTION
-krb5_enctypes_compatible_keys(krb5_context context,
- krb5_enctype etype1,
- krb5_enctype etype2)
-{
- struct encryption_type *e1 = _find_enctype(etype1);
- struct encryption_type *e2 = _find_enctype(etype2);
- return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
-}
-
static krb5_boolean
derived_crypto(krb5_context context,
krb5_crypto crypto)
* Kerberos encrypted data look like this:
*
* 1. KRB5_CRYPTO_TYPE_HEADER
- * 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in
- * any order, however the receiver have to aware of the
- * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used headers and
- * trailers.
+ * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...]
+ * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
+ * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
+ * commonly used headers and trailers.
* 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
* 4. KRB5_CRYPTO_TYPE_TRAILER
*/
krb5_crypto crypto,
unsigned usage,
krb5_crypto_iov *data,
- size_t num_data,
+ int num_data,
void *ivec)
{
size_t headersz, trailersz, len;
- size_t i, sz, block_sz, pad_sz;
+ int i;
+ size_t sz, block_sz, pad_sz;
Checksum cksum;
unsigned char *p, *q;
krb5_error_code ret;
struct key_data *dkey;
const struct encryption_type *et = crypto->et;
- krb5_crypto_iov *tiv, *piv, *hiv;
+ krb5_crypto_iov *tiv, *piv, *hiv, *div;
+
+ if (num_data < 0) {
+ krb5_clear_error_message(context);
+ return KRB5_CRYPTO_INTERNAL;
+ }
if(!derived_crypto(context, crypto)) {
krb5_clear_error_message(context);
headersz = et->confoundersize;
trailersz = CHECKSUMSIZE(et->keyed_checksum);
- for (len = 0, i = 0; i < num_data; i++) {
- if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER &&
- data[i].flags == KRB5_CRYPTO_TYPE_DATA) {
- len += data[i].data.length;
- }
- }
+ div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA);
+ if (div == NULL)
+ return KRB5_CRYPTO_INTERNAL;
+
+ len = div->data.length;
sz = headersz + len;
block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
pad_sz = block_sz - sz;
- trailersz += pad_sz;
/* header */
/* XXX replace with EVP_Cipher */
- len = hiv->data.length;
- for (i = 0; i < num_data; i++) {
- if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
- data[i].flags != KRB5_CRYPTO_TYPE_PADDING)
- continue;
- len += data[i].data.length;
- }
+ len = hiv->data.length + div->data.length;
+ if (piv)
+ len += piv->data.length;
p = q = malloc(len);
if(p == NULL)
memcpy(q, hiv->data.data, hiv->data.length);
q += hiv->data.length;
- for (i = 0; i < num_data; i++) {
- if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
- data[i].flags != KRB5_CRYPTO_TYPE_PADDING)
- continue;
- memcpy(q, data[i].data.data, data[i].data.length);
- q += data[i].data.length;
- }
+ memcpy(q, div->data.data, div->data.length);
+ q += div->data.length;
+ memset(q, 0, pad_sz);
ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
if(ret) {
/* now copy data back to buffers */
q = p;
+
memcpy(hiv->data.data, q, hiv->data.length);
q += hiv->data.length;
- for (i = 0; i < num_data; i++) {
- if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
- data[i].flags != KRB5_CRYPTO_TYPE_PADDING)
- continue;
- memcpy(data[i].data.data, q, data[i].data.length);
- q += data[i].data.length;
- }
+ memcpy(div->data.data, q, div->data.length);
+ q += div->data.length;
+
+ if (piv)
+ memcpy(piv->data.data, q, pad_sz);
free(p);
return ret;
* @ingroup krb5_crypto
*
* 1. KRB5_CRYPTO_TYPE_HEADER
- * 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in
+ * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
* any order, however the receiver have to aware of the
* order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
* protocol headers and trailers. The output data will be of same
krb5_crypto crypto,
unsigned usage,
krb5_crypto_iov *data,
- size_t num_data,
+ unsigned int num_data,
void *ivec)
{
+ unsigned int i;
size_t headersz, trailersz, len;
- size_t i, sz, block_sz, pad_sz;
+ size_t sz, block_sz, pad_sz;
Checksum cksum;
unsigned char *p, *q;
krb5_error_code ret;
struct key_data *dkey;
struct encryption_type *et = crypto->et;
- krb5_crypto_iov *tiv, *hiv;
+ krb5_crypto_iov *tiv, *hiv, *div;
+
+ if (num_data < 0) {
+ krb5_clear_error_message(context);
+ return KRB5_CRYPTO_INTERNAL;
+ }
if(!derived_crypto(context, crypto)) {
krb5_clear_error_message(context);
headersz = et->confoundersize;
trailersz = CHECKSUMSIZE(et->keyed_checksum);
- for (len = 0, i = 0; i < num_data; i++)
- if (data[i].flags == KRB5_CRYPTO_TYPE_DATA)
+ for (len = 0, i = 0; i < num_data; i++) {
+ if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) {
+ if (len != 0)
+ return KRB5_CRYPTO_INTERNAL;
len += data[i].data.length;
+ }
+ }
sz = headersz + len;
block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
return KRB5_BAD_MSIZE;
tiv->data.length = trailersz;
- /* body */
+ div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA);
+ if (div == NULL)
+ return KRB5_CRYPTO_INTERNAL;
/* XXX replace with EVP_Cipher */
memcpy(q, hiv->data.data, hiv->data.length);
q += hiv->data.length;
- for (i = 0; i < num_data; i++) {
- if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
- continue;
- memcpy(q, data[i].data.data, data[i].data.length);
- q += data[i].data.length;
- }
+ memcpy(q, div->data.data, div->data.length);
ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
if(ret) {
return ret;
}
- /* XXX now copy data back to buffers */
- q = p;
- memcpy(hiv->data.data, q, hiv->data.length);
- q += hiv->data.length;
- len -= hiv->data.length;
-
- for (i = 0; i < num_data; i++) {
- if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
- continue;
- if (len < data[i].data.length)
- data[i].data.length = len;
- memcpy(data[i].data.data, q, data[i].data.length);
- q += data[i].data.length;
- len -= data[i].data.length;
- }
+ /* copy data back to buffers */
+ memcpy(hiv->data.data, p, hiv->data.length);
+ memcpy(div->data.data, p + hiv->data.length, len - hiv->data.length);
free(p);
- if (len)
- krb5_abortx(context, "data still in the buffer");
+
+ /* check signature */
len = hiv->data.length;
for (i = 0; i < num_data; i++) {
* @param usage Key usage for this buffer
* @param data array of buffers to process
* @param num_data length of array
- * @param result output data
+ * @param type output data
*
* @return Return an error code or 0.
* @ingroup krb5_crypto
krb5_crypto crypto,
unsigned usage,
krb5_crypto_iov *data,
- size_t num_data,
+ unsigned int num_data,
krb5_cksumtype *type)
{
Checksum cksum;
krb5_crypto_iov *civ;
krb5_error_code ret;
- unsigned int i;
+ int i;
size_t len;
char *p, *q;
+ if (num_data < 0) {
+ krb5_clear_error_message(context);
+ return KRB5_CRYPTO_INTERNAL;
+ }
+
if(!derived_crypto(context, crypto)) {
krb5_clear_error_message(context);
return KRB5_CRYPTO_INTERNAL;
krb5_abortx(NULL, "Failed to generate random block");
}
-static void
-DES3_postproc(krb5_context context,
- unsigned char *k, size_t len, struct key_data *key)
-{
- DES3_random_to_key(context, key->key, k, len);
-
- if (key->schedule) {
- krb5_free_data(context, key->schedule);
- key->schedule = NULL;
- }
-}
-
static krb5_error_code
derive_key(krb5_context context,
struct encryption_type *et,
const void *constant,
size_t len)
{
- unsigned char *k;
+ unsigned char *k = NULL;
unsigned int nblocks = 0, i;
krb5_error_code ret = 0;
struct key_type *kt = et->keytype;
nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
k = malloc(nblocks * et->blocksize);
if(k == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
}
ret = _krb5_n_fold(constant, len, k, et->blocksize);
if (ret) {
- free(k);
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- return ret;
+ goto out;
}
+
for(i = 0; i < nblocks; i++) {
if(i > 0)
memcpy(k + i * et->blocksize,
size_t res_len = (kt->bits + 7) / 8;
if(len != 0 && c == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
}
memcpy(c, constant, len);
(*et->encrypt)(context, key, c, len, 1, 0, NULL);
k = malloc(res_len);
if(res_len != 0 && k == NULL) {
free(c);
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
}
ret = _krb5_n_fold(c, len, k, res_len);
+ free(c);
if (ret) {
- free(k);
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- return ret;
+ goto out;
}
- free(c);
}
/* XXX keytype dependent post-processing */
switch(kt->type) {
case KEYTYPE_DES3:
- DES3_postproc(context, k, nblocks * et->blocksize, key);
+ DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
break;
case KEYTYPE_AES128:
case KEYTYPE_AES256:
kt->type);
break;
}
+ out:
if (key->schedule) {
- krb5_free_data(context, key->schedule);
+ free_key_schedule(context, key, et);
key->schedule = NULL;
}
- memset(k, 0, nblocks * et->blocksize);
- free(k);
+ if (k) {
+ memset(k, 0, nblocks * et->blocksize);
+ free(k);
+ }
return ret;
}
return 0;
}
+static void
+free_key_schedule(krb5_context context,
+ struct key_data *key,
+ struct encryption_type *et)
+{
+ if (et->keytype->cleanup)
+ (*et->keytype->cleanup)(context, key);
+ memset(key->schedule->data, 0, key->schedule->length);
+ krb5_free_data(context, key->schedule);
+}
+
static void
free_key_data(krb5_context context, struct key_data *key,
struct encryption_type *et)
{
krb5_free_keyblock(context, key->key);
if(key->schedule) {
- if (et->keytype->cleanup)
- (*et->keytype->cleanup)(context, key);
- memset(key->schedule->data, 0, key->schedule->length);
- krb5_free_data(context, key->schedule);
+ free_key_schedule(context, key, et);
+ key->schedule = NULL;
}
}
return ret;
}
kd.schedule = NULL;
- DES3_postproc (context, tmp, keylen, &kd); /* XXX */
+ DES3_random_to_key(context, kd.key, tmp, keylen);
memset(tmp, 0, keylen);
free(tmp);
ret = derive_key(context,
#ifndef HEIMDAL_SMALLER
-static struct key_type *keytypes[] = {
- &keytype_null,
- &keytype_des,
- &keytype_des3_derived,
-#ifdef DES3_OLD_ENCTYPE
- &keytype_des3,
-#endif
- &keytype_aes128,
- &keytype_aes256,
- &keytype_arcfour
-};
-
-static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]);
-
-
-static struct key_type *
-_find_keytype(krb5_keytype type)
-{
- int i;
- for(i = 0; i < num_keytypes; i++)
- if(keytypes[i]->type == type)
- return keytypes[i];
- return NULL;
-}
-
-/*
- * First take the configured list of etypes for `keytype' if available,
- * else, do `krb5_keytype_to_enctypes'.
- */
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_keytype_to_enctypes_default (krb5_context context,
- krb5_keytype keytype,
- unsigned *len,
- krb5_enctype **val)
- __attribute__((deprecated))
-{
- unsigned int i, n;
- krb5_enctype *ret;
-
- if (keytype != KEYTYPE_DES || context->etypes_des == NULL)
- return krb5_keytype_to_enctypes (context, keytype, len, val);
-
- for (n = 0; context->etypes_des[n]; ++n)
- ;
- ret = malloc (n * sizeof(*ret));
- if (ret == NULL && n != 0) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
- }
- for (i = 0; i < n; ++i)
- ret[i] = context->etypes_des[i];
- *len = n;
- *val = ret;
- return 0;
-}
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_keytype_to_string(krb5_context context,
- krb5_keytype keytype,
- char **string)
- __attribute__((deprecated))
-{
- struct key_type *kt = _find_keytype(keytype);
- if(kt == NULL) {
- krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
- "key type %d not supported", keytype);
- return KRB5_PROG_KEYTYPE_NOSUPP;
- }
- *string = strdup(kt->name);
- if(*string == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
- }
- return 0;
-}
-
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_string_to_keytype(krb5_context context,
- const char *string,
- krb5_keytype *keytype)
- __attribute__((deprecated))
-{
- char *end;
- int i;
-
- for(i = 0; i < num_keytypes; i++)
- if(strcasecmp(keytypes[i]->name, string) == 0){
- *keytype = keytypes[i]->type;
- return 0;
- }
-
- /* check if the enctype is a number */
- *keytype = strtol(string, &end, 0);
- if(*end == '\0' && *keytype != 0) {
- if (krb5_enctype_valid(context, *keytype) == 0)
- return 0;
- }
-
- krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
- "key type %s not supported", string);
- return KRB5_PROG_KEYTYPE_NOSUPP;
-}
-
krb5_error_code KRB5_LIB_FUNCTION
krb5_keytype_to_enctypes (krb5_context context,
krb5_keytype keytype,
unsigned *len,
krb5_enctype **val)
+ KRB5_DEPRECATED
{
int i;
unsigned n = 0;
for (i = num_etypes - 1; i >= 0; --i) {
if (etypes[i]->keytype->type == keytype
- && !(etypes[i]->flags & F_PSEUDO))
+ && !(etypes[i]->flags & F_PSEUDO)
+ && krb5_enctype_valid(context, etypes[i]->type) == 0)
++n;
}
+ if (n == 0) {
+ krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
+ "Keytype have no mapping");
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+ }
+
ret = malloc(n * sizeof(*ret));
if (ret == NULL && n != 0) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
n = 0;
for (i = num_etypes - 1; i >= 0; --i) {
if (etypes[i]->keytype->type == keytype
- && !(etypes[i]->flags & F_PSEUDO))
+ && !(etypes[i]->flags & F_PSEUDO)
+ && krb5_enctype_valid(context, etypes[i]->type) == 0)
ret[n++] = etypes[i]->type;
}
*len = n;
return 0;
}
+/* if two enctypes have compatible keys */
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_enctypes_compatible_keys(krb5_context context,
+ krb5_enctype etype1,
+ krb5_enctype etype2)
+ KRB5_DEPRECATED
+{
+ struct encryption_type *e1 = _find_enctype(etype1);
+ struct encryption_type *e2 = _find_enctype(etype2);
+ return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
+}
+
#endif /* HEIMDAL_SMALLER */
/**
* Free the content of krb5_data structure, its ok to free a zeroed
- * structure. When done, the structure will be zeroed.
+ * structure (with memset() or krb5_data_zero()). When done, the
+ * structure will be zeroed. The same function is called
+ * krb5_free_data_contents() in MIT Kerberos.
*
* @param p krb5_data to free.
*
krb5_data_zero(p);
}
-/**
- * Same as krb5_data_free().
- *
- * @param context Kerberos 5 context.
- * @param data krb5_data to free.
- *
- * @ingroup krb5
- */
-
-void KRB5_LIB_FUNCTION
-krb5_free_data_contents(krb5_context context, krb5_data *data)
-{
- krb5_data_free(data);
-}
-
/**
* Free krb5_data (and its content).
*
RCSID("$Id$");
-#undef __attribute__
-#define __attribute__(X)
+#undef KRB5_DEPRECATED
+#define KRB5_DEPRECATED
+#undef __attribute__(x)
+#define __attribute__(x)
/**
* Clears the error message from the Kerberos 5 context.
}
HEIMDAL_MUTEX_unlock(context->mutex);
+ if (code == 0)
+ return strdup("Success");
+
cstr = krb5_get_err_text(context, code);
if (cstr)
return strdup(cstr);
void KRB5_LIB_FUNCTION
krb5_free_error_string(krb5_context context, char *str)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
krb5_free_error_message(context, str);
}
krb5_error_code KRB5_LIB_FUNCTION
krb5_set_error_string(krb5_context context, const char *fmt, ...)
- __attribute__((format (printf, 2, 3))) __attribute__((deprecated))
+ __attribute__((format (printf, 2, 3))) KRB5_DEPRECATED
{
va_list ap;
krb5_error_code KRB5_LIB_FUNCTION
krb5_vset_error_string(krb5_context context, const char *fmt, va_list args)
- __attribute__ ((format (printf, 2, 0))) __attribute__((deprecated))
+ __attribute__ ((format (printf, 2, 0))) KRB5_DEPRECATED
{
krb5_vset_error_message(context, 0, fmt, args);
return 0;
void KRB5_LIB_FUNCTION
krb5_clear_error_string(krb5_context context)
- __attribute__((deprecated))
+ KRB5_DEPRECATED
{
krb5_clear_error_message(context);
}
* hardlink)
*/
-static krb5_error_code
-erase_file(krb5_context context, const char *filename)
+krb5_error_code
+_krb5_erase_file(krb5_context context, const char *filename)
{
int fd;
struct stat sb1, sb2;
fcc_destroy(krb5_context context,
krb5_ccache id)
{
- erase_file(context, FILENAME(id));
+ _krb5_erase_file(context, FILENAME(id));
return 0;
}
return ret;
}
- return krb5_cc_move(context, newfile, id);
+ ret = krb5_cc_move(context, newfile, id);
+ if (ret) {
+ krb5_cc_destroy(context, newfile);
+ return ret;
+ }
+
+ return ret;
}
static krb5_error_code
iter->first = 0;
fn = krb5_cc_default_name(context);
- if (strncasecmp(fn, "FILE:", 5) != 0) {
+ if (fn == NULL || strncasecmp(fn, "FILE:", 5) != 0) {
ret = _krb5_expand_default_cc_name(context,
KRB5_DEFAULT_CCNAME_FILE,
&expandedfn);
if (ret)
return ret;
+ fn = expandedfn;
}
ret = krb5_cc_resolve(context, fn, id);
if (expandedfn)
fcc_unlock(context, fd1);
close(fd1);
- erase_file(context, FILENAME(from));
+ _krb5_erase_file(context, FILENAME(from));
if (ret) {
- erase_file(context, FILENAME(to));
+ _krb5_erase_file(context, FILENAME(to));
return ret;
}
}
krb5_storage *sp;
int fd;
ret = init_fcc (context, to, &sp, &fd);
- krb5_storage_free(sp);
+ if (sp)
+ krb5_storage_free(sp);
fcc_unlock(context, fd);
close(fd);
}
#include "krb5_locl.h"
-RCSID("$Id: get_addrs.c 23815 2008-09-13 09:21:03Z lha $");
+RCSID("$Id$");
#ifdef __osf__
/* hate */
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
-#ifdef HAVE_IFADDR_H
#include <ifaddrs.h>
-#endif
static krb5_error_code
gethostname_fallback (krb5_context context, krb5_addresses *res)
unsigned int num, idx;
krb5_addresses ignore_addresses;
- res->val = NULL;
-
if (getifaddrs(&ifa0) == -1) {
ret = errno;
krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret));
{
krb5_error_code ret = -1;
+ res->len = 0;
+ res->val = NULL;
+
if (flags & SCAN_INTERFACES) {
ret = find_all_addresses (context, res, flags);
if(ret || res->len == 0)
ret = gethostname_fallback (context, res);
} else {
- res->len = 0;
- res->val = NULL;
ret = 0;
}
if (ret)
return ret;
- ret = krb5_decode_EncASRepPart(context,
- data.data,
+ ret = decode_EncASRepPart(data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ if (ret)
+ ret = decode_EncTGSRepPart(data.data,
data.length,
&dec_rep->enc_part,
&size);
if (ret)
- ret = krb5_decode_EncTGSRepPart(context,
- data.data,
- data.length,
- &dec_rep->enc_part,
- &size);
+ krb5_set_error_message(context, ret,
+ N_("Failed to decode encpart in ticket", ""));
krb5_data_free (&data);
return ret;
}
} else if(krb5_rd_error(context, &resp, &error) == 0) {
ret = krb5_error_from_rd_error(context, &error, in_creds);
krb5_free_error_contents(context, &error);
- } else if(resp.data && ((char*)resp.data)[0] == 4) {
+ } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) {
ret = KRB5KRB_AP_ERR_V4_REPLY;
krb5_clear_error_message(context);
} else {
{
if (opt->self)
krb5_free_principal(context, opt->self);
+ if (opt->ticket) {
+ free_Ticket(opt->ticket);
+ free(opt->ticket);
+ }
memset(opt, 0, sizeof(*opt));
free(opt);
}
*/
static int
-copy_txt_to_realms (struct resource_record *head,
+copy_txt_to_realms (struct rk_resource_record *head,
krb5_realm **realms)
{
- struct resource_record *rr;
+ struct rk_resource_record *rr;
unsigned int n, i;
for(n = 0, rr = head; rr; rr = rr->next)
- if (rr->type == T_TXT)
+ if (rr->type == rk_ns_t_txt)
++n;
if (n == 0)
(*realms)[i] = NULL;
for (i = 0, rr = head; rr; rr = rr->next) {
- if (rr->type == T_TXT) {
+ if (rr->type == rk_ns_t_txt) {
char *tmp;
tmp = strdup(rr->u.txt);
{
static const char *default_labels[] = { "_kerberos", NULL };
char dom[MAXHOSTNAMELEN];
- struct dns_reply *r;
+ struct rk_dns_reply *r;
const char **labels;
char **config_labels;
int i, ret;
krb5_config_free_strings(config_labels);
return -1;
}
- r = dns_lookup(dom, "TXT");
+ r = rk_dns_lookup(dom, "TXT");
if(r != NULL) {
ret = copy_txt_to_realms (r->head, realms);
- dns_free_data(r);
+ rk_dns_free_data(r);
if(ret == 0) {
if (config_labels)
krb5_config_free_strings(config_labels);
* SUCH DAMAGE.
*/
+#define KRB5_DEPRECATED
+
#include "krb5_locl.h"
RCSID("$Id$");
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_init_etype (krb5_context context,
- unsigned *len,
- krb5_enctype **val,
- const krb5_enctype *etypes)
-{
- unsigned int i;
- krb5_error_code ret;
- krb5_enctype *tmp = NULL;
-
- ret = 0;
- if (etypes == NULL) {
- ret = krb5_get_default_in_tkt_etypes(context,
- &tmp);
- if (ret)
- return ret;
- etypes = tmp;
- }
-
- for (i = 0; etypes[i]; ++i)
- ;
- *len = i;
- *val = malloc(i * sizeof(**val));
- if (i != 0 && *val == NULL) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- goto cleanup;
- }
- memmove (*val,
- etypes,
- i * sizeof(*tmp));
-cleanup:
- if (tmp != NULL)
- free (tmp);
- return ret;
-}
-
-static krb5_error_code
-check_server_referral(krb5_context context,
- krb5_kdc_rep *rep,
- unsigned flags,
- krb5_const_principal requested,
- krb5_const_principal returned,
- const krb5_keyblock const * key)
-{
- krb5_error_code ret;
- PA_ServerReferralData ref;
- krb5_crypto session;
- EncryptedData ed;
- size_t len;
- krb5_data data;
- PA_DATA *pa;
- int i = 0, cmp;
-
- if (rep->kdc_rep.padata == NULL)
- goto noreferral;
-
- pa = krb5_find_padata(rep->kdc_rep.padata->val,
- rep->kdc_rep.padata->len,
- KRB5_PADATA_SERVER_REFERRAL, &i);
- if (pa == NULL)
- goto noreferral;
-
- memset(&ed, 0, sizeof(ed));
- memset(&ref, 0, sizeof(ref));
-
- ret = decode_EncryptedData(pa->padata_value.data,
- pa->padata_value.length,
- &ed, &len);
- if (ret)
- return ret;
- if (len != pa->padata_value.length) {
- free_EncryptedData(&ed);
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("Referral EncryptedData wrong for realm %s",
- "realm"), requested->realm);
- return KRB5KRB_AP_ERR_MODIFIED;
- }
-
- ret = krb5_crypto_init(context, key, 0, &session);
- if (ret) {
- free_EncryptedData(&ed);
- return ret;
- }
-
- ret = krb5_decrypt_EncryptedData(context, session,
- KRB5_KU_PA_SERVER_REFERRAL,
- &ed, &data);
- free_EncryptedData(&ed);
- krb5_crypto_destroy(context, session);
- if (ret)
- return ret;
-
- ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
- if (ret) {
- krb5_data_free(&data);
- return ret;
- }
- krb5_data_free(&data);
-
- if (strcmp(requested->realm, returned->realm) != 0) {
- free_PA_ServerReferralData(&ref);
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("server ref realm mismatch, "
- "requested realm %s got back %s", ""),
- requested->realm, returned->realm);
- return KRB5KRB_AP_ERR_MODIFIED;
- }
-
- if (returned->name.name_string.len == 2 &&
- strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0)
- {
- const char *realm = returned->name.name_string.val[1];
-
- if (ref.referred_realm == NULL
- || strcmp(*ref.referred_realm, realm) != 0)
- {
- free_PA_ServerReferralData(&ref);
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("tgt returned with wrong ref", ""));
- return KRB5KRB_AP_ERR_MODIFIED;
- }
- } else if (krb5_principal_compare(context, returned, requested) == 0) {
- free_PA_ServerReferralData(&ref);
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("req princ no same as returned", ""));
- return KRB5KRB_AP_ERR_MODIFIED;
- }
-
- if (ref.requested_principal_name) {
- cmp = _krb5_principal_compare_PrincipalName(context,
- requested,
- ref.requested_principal_name);
- if (!cmp) {
- free_PA_ServerReferralData(&ref);
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("referred principal not same "
- "as requested", ""));
- return KRB5KRB_AP_ERR_MODIFIED;
- }
- } else if (flags & EXTRACT_TICKET_AS_REQ) {
- free_PA_ServerReferralData(&ref);
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("Requested principal missing on AS-REQ", ""));
- return KRB5KRB_AP_ERR_MODIFIED;
- }
-
- free_PA_ServerReferralData(&ref);
-
- return ret;
-noreferral:
- if (krb5_principal_compare(context, requested, returned) == FALSE) {
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("Not same server principal returned "
- "as requested", ""));
- return KRB5KRB_AP_ERR_MODIFIED;
- }
- return 0;
-}
-
-
-/*
- * Verify referral data
- */
-
-
-static krb5_error_code
-check_client_referral(krb5_context context,
- krb5_kdc_rep *rep,
- krb5_const_principal requested,
- krb5_const_principal mapped,
- krb5_keyblock const * key)
-{
- krb5_error_code ret;
- PA_ClientCanonicalized canon;
- krb5_crypto crypto;
- krb5_data data;
- PA_DATA *pa;
- size_t len;
- int i = 0;
-
- if (rep->kdc_rep.padata == NULL)
- goto noreferral;
-
- pa = krb5_find_padata(rep->kdc_rep.padata->val,
- rep->kdc_rep.padata->len,
- KRB5_PADATA_CLIENT_CANONICALIZED, &i);
- if (pa == NULL)
- goto noreferral;
-
- ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
- pa->padata_value.length,
- &canon, &len);
- if (ret) {
- krb5_set_error_message(context, ret,
- N_("Failed to decode ClientCanonicalized "
- "from realm %s", ""), requested->realm);
- return ret;
- }
-
- ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
- &canon.names, &len, ret);
- if (ret) {
- free_PA_ClientCanonicalized(&canon);
- return ret;
- }
- if (data.length != len)
- krb5_abortx(context, "internal asn.1 error");
-
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret) {
- free(data.data);
- free_PA_ClientCanonicalized(&canon);
- return ret;
- }
-
- ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
- data.data, data.length,
- &canon.canon_checksum);
- krb5_crypto_destroy(context, crypto);
- free(data.data);
- if (ret) {
- krb5_set_error_message(context, ret,
- N_("Failed to verify client canonicalized "
- "data from realm %s", ""),
- requested->realm);
- free_PA_ClientCanonicalized(&canon);
- return ret;
- }
-
- if (!_krb5_principal_compare_PrincipalName(context,
- requested,
- &canon.names.requested_name))
- {
- free_PA_ClientCanonicalized(&canon);
- krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
- N_("Requested name doesn't match"
- " in client referral", ""));
- return KRB5_PRINC_NOMATCH;
- }
- if (!_krb5_principal_compare_PrincipalName(context,
- mapped,
- &canon.names.mapped_name))
- {
- free_PA_ClientCanonicalized(&canon);
- krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
- N_("Mapped name doesn't match"
- " in client referral", ""));
- return KRB5_PRINC_NOMATCH;
- }
-
- return 0;
-
-noreferral:
- if (krb5_principal_compare(context, requested, mapped) == FALSE) {
- krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
- N_("Not same client principal returned "
- "as requested", ""));
- return KRB5KRB_AP_ERR_MODIFIED;
- }
- return 0;
-}
-
-
-
-static krb5_error_code
-decrypt_tkt (krb5_context context,
- krb5_keyblock *key,
- krb5_key_usage usage,
- krb5_const_pointer decrypt_arg,
- krb5_kdc_rep *dec_rep)
-{
- krb5_error_code ret;
- krb5_data data;
- size_t size;
- krb5_crypto crypto;
-
- ret = krb5_crypto_init(context, key, 0, &crypto);
- if (ret)
- return ret;
-
- ret = krb5_decrypt_EncryptedData (context,
- crypto,
- usage,
- &dec_rep->kdc_rep.enc_part,
- &data);
- krb5_crypto_destroy(context, crypto);
-
- if (ret)
- return ret;
-
- ret = krb5_decode_EncASRepPart(context,
- data.data,
- data.length,
- &dec_rep->enc_part,
- &size);
- if (ret)
- ret = krb5_decode_EncTGSRepPart(context,
- data.data,
- data.length,
- &dec_rep->enc_part,
- &size);
- krb5_data_free (&data);
- if (ret)
- return ret;
- return 0;
-}
-
-int
-_krb5_extract_ticket(krb5_context context,
- krb5_kdc_rep *rep,
- krb5_creds *creds,
- krb5_keyblock *key,
- krb5_const_pointer keyseed,
- krb5_key_usage key_usage,
- krb5_addresses *addrs,
- unsigned nonce,
- unsigned flags,
- krb5_decrypt_proc decrypt_proc,
- krb5_const_pointer decryptarg)
-{
- krb5_error_code ret;
- krb5_principal tmp_principal;
- size_t len;
- time_t tmp_time;
- krb5_timestamp sec_now;
-
- /* decrypt */
-
- if (decrypt_proc == NULL)
- decrypt_proc = decrypt_tkt;
-
- ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
- if (ret)
- goto out;
-
- /* save session key */
-
- creds->session.keyvalue.length = 0;
- creds->session.keyvalue.data = NULL;
- creds->session.keytype = rep->enc_part.key.keytype;
- ret = krb5_data_copy (&creds->session.keyvalue,
- rep->enc_part.key.keyvalue.data,
- rep->enc_part.key.keyvalue.length);
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
-
- /*
- * HACK:
- * this is really a ugly hack, to support using the Netbios Domain Name
- * as realm against windows KDC's, they always return the full realm
- * based on the DNS Name.
- */
- flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
- flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
-
- /* compare client and save */
- ret = _krb5_principalname2krb5_principal (context,
- &tmp_principal,
- rep->kdc_rep.cname,
- rep->kdc_rep.crealm);
- if (ret)
- goto out;
-
- /* check client referral and save principal */
- /* anonymous here ? */
- if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
- ret = check_client_referral(context, rep,
- creds->client,
- tmp_principal,
- &creds->session);
- if (ret) {
- krb5_free_principal (context, tmp_principal);
- goto out;
- }
- }
- krb5_free_principal (context, creds->client);
- creds->client = tmp_principal;
-
- /* check server referral and save principal */
- ret = _krb5_principalname2krb5_principal (context,
- &tmp_principal,
- rep->kdc_rep.ticket.sname,
- rep->kdc_rep.ticket.realm);
- if (ret)
- goto out;
- if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
- ret = check_server_referral(context,
- rep,
- flags,
- creds->server,
- tmp_principal,
- &creds->session);
- if (ret) {
- krb5_free_principal (context, tmp_principal);
- goto out;
- }
- }
- krb5_free_principal(context, creds->server);
- creds->server = tmp_principal;
-
- /* verify names */
- if(flags & EXTRACT_TICKET_MATCH_REALM){
- const char *srealm = krb5_principal_get_realm(context, creds->server);
- const char *crealm = krb5_principal_get_realm(context, creds->client);
-
- if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
- strcmp(rep->enc_part.srealm, crealm) != 0)
- {
- ret = KRB5KRB_AP_ERR_MODIFIED;
- krb5_clear_error_message(context);
- goto out;
- }
- }
-
- /* compare nonces */
-
- if (nonce != rep->enc_part.nonce) {
- ret = KRB5KRB_AP_ERR_MODIFIED;
- krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- goto out;
- }
-
- /* set kdc-offset */
-
- krb5_timeofday (context, &sec_now);
- if (rep->enc_part.flags.initial
- && context->kdc_sec_offset == 0
- && krb5_config_get_bool (context, NULL,
- "libdefaults",
- "kdc_timesync",
- NULL)) {
- context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
- krb5_timeofday (context, &sec_now);
- }
-
- /* check all times */
-
- if (rep->enc_part.starttime) {
- tmp_time = *rep->enc_part.starttime;
- } else
- tmp_time = rep->enc_part.authtime;
-
- if (creds->times.starttime == 0
- && abs(tmp_time - sec_now) > context->max_skew) {
- ret = KRB5KRB_AP_ERR_SKEW;
- krb5_set_error_message (context, ret,
- N_("time skew (%d) larger than max (%d)", ""),
- abs(tmp_time - sec_now),
- (int)context->max_skew);
- goto out;
- }
-
- if (creds->times.starttime != 0
- && tmp_time != creds->times.starttime) {
- krb5_clear_error_message (context);
- ret = KRB5KRB_AP_ERR_MODIFIED;
- goto out;
- }
-
- creds->times.starttime = tmp_time;
-
- if (rep->enc_part.renew_till) {
- tmp_time = *rep->enc_part.renew_till;
- } else
- tmp_time = 0;
-
- if (creds->times.renew_till != 0
- && tmp_time > creds->times.renew_till) {
- krb5_clear_error_message (context);
- ret = KRB5KRB_AP_ERR_MODIFIED;
- goto out;
- }
-
- creds->times.renew_till = tmp_time;
-
- creds->times.authtime = rep->enc_part.authtime;
-
- if (creds->times.endtime != 0
- && rep->enc_part.endtime > creds->times.endtime) {
- krb5_clear_error_message (context);
- ret = KRB5KRB_AP_ERR_MODIFIED;
- goto out;
- }
-
- creds->times.endtime = rep->enc_part.endtime;
-
- if(rep->enc_part.caddr)
- krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
- else if(addrs)
- krb5_copy_addresses (context, addrs, &creds->addresses);
- else {
- creds->addresses.len = 0;
- creds->addresses.val = NULL;
- }
- creds->flags.b = rep->enc_part.flags;
-
- creds->authdata.len = 0;
- creds->authdata.val = NULL;
-
- /* extract ticket */
- ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
- &rep->kdc_rep.ticket, &len, ret);
- if(ret)
- goto out;
- if (creds->ticket.length != len)
- krb5_abortx(context, "internal error in ASN.1 encoder");
- creds->second_ticket.length = 0;
- creds->second_ticket.data = NULL;
-
-
-out:
- memset (rep->enc_part.key.keyvalue.data, 0,
- rep->enc_part.key.keyvalue.length);
- return ret;
-}
-
+#ifndef HEIMDAL_SMALLER
static krb5_error_code
make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
if(salt == NULL) {
/* default to standard salt */
ret = krb5_get_pw_salt (context, client, &salt2);
+ if (ret)
+ return ret;
salt = &salt2;
}
if (!enctypes) {
*preauth = &preauth2;
ALLOC_SEQ(*preauth, 1);
(*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
- krb5_decode_ETYPE_INFO(context,
- md.val[i].padata_value.data,
- md.val[i].padata_value.length,
- &(*preauth)->val[0].info,
- NULL);
+ decode_ETYPE_INFO(md.val[i].padata_value.data,
+ md.val[i].padata_value.length,
+ &(*preauth)->val[0].info,
+ NULL);
break;
default:
break;
krb5_const_pointer decryptarg,
krb5_creds *creds,
krb5_kdc_rep *ret_as_reply)
+ KRB5_DEPRECATED
{
krb5_error_code ret;
AS_REQ a;
krb5_creds *creds,
krb5_ccache ccache,
krb5_kdc_rep *ret_as_reply)
+ KRB5_DEPRECATED
{
krb5_error_code ret;
ret = krb5_cc_store_cred (context, ccache, creds);
return ret;
}
+
+#endif /* HEIMDAL_SMALLER */
+++ /dev/null
-/*
- * Copyright (c) 1997 - 2001 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$");
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_keytab_key_proc (krb5_context context,
- krb5_enctype enctype,
- krb5_salt salt,
- krb5_const_pointer keyseed,
- krb5_keyblock **key)
-{
- krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed);
- krb5_keytab keytab = args->keytab;
- krb5_principal principal = args->principal;
- krb5_error_code ret;
- krb5_keytab real_keytab;
- krb5_keytab_entry entry;
-
- if(keytab == NULL)
- krb5_kt_default(context, &real_keytab);
- else
- real_keytab = keytab;
-
- ret = krb5_kt_get_entry (context, real_keytab, principal,
- 0, enctype, &entry);
-
- if (keytab == NULL)
- krb5_kt_close (context, real_keytab);
-
- if (ret)
- return ret;
-
- ret = krb5_copy_keyblock (context, &entry.keyblock, key);
- krb5_kt_free_entry(context, &entry);
- return ret;
-}
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_get_in_tkt_with_keytab (krb5_context context,
- krb5_flags options,
- krb5_addresses *addrs,
- const krb5_enctype *etypes,
- const krb5_preauthtype *pre_auth_types,
- krb5_keytab keytab,
- krb5_ccache ccache,
- krb5_creds *creds,
- krb5_kdc_rep *ret_as_reply)
-{
- krb5_keytab_key_proc_args a;
-
- a.principal = creds->client;
- a.keytab = keytab;
-
- return krb5_get_in_tkt (context,
- options,
- addrs,
- etypes,
- pre_auth_types,
- krb5_keytab_key_proc,
- &a,
- NULL,
- NULL,
- creds,
- ccache,
- ret_as_reply);
-}
error_code EOF, "End of file"
error_code BAD_MKEY, "Failed to get the master key"
error_code SERVICE_NOMATCH, "Unacceptable service used"
+error_code NOT_SEEKABLE, "File descriptor not seekable"
+error_code TOO_BIG, "Offset too large"
index 64
prefix HEIM_PKINIT
#undef __attribute__
#define __attribute__(x)
-RCSID("$Id$");
+/**
+ * @page krb5_init_creds_intro The initial credential handing functions
+ * @section section_krb5_init_creds Initial credential
+ *
+ * Functions to get initial credentials: @ref krb5_credential .
+ */
-void KRB5_LIB_FUNCTION
-krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
- __attribute__((deprecated))
-{
- memset (opt, 0, sizeof(*opt));
-}
+/**
+ * Allocate a new krb5_get_init_creds_opt structure, free with
+ * krb5_get_init_creds_opt_free().
+ *
+ * @ingroup krb5_credential
+ */
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_alloc(krb5_context context,
return 0;
}
-krb5_error_code
-_krb5_get_init_creds_opt_copy(krb5_context context,
- const krb5_get_init_creds_opt *in,
- krb5_get_init_creds_opt **out)
-{
- krb5_get_init_creds_opt *opt;
-
- *out = NULL;
- opt = calloc(1, sizeof(*opt));
- if (opt == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
- }
- if (in)
- *opt = *in;
- if(opt->opt_private == NULL) {
- opt->opt_private = calloc(1, sizeof(*opt->opt_private));
- if (opt->opt_private == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- free(opt);
- return ENOMEM;
- }
- opt->opt_private->refcount = 1;
- } else
- opt->opt_private->refcount++;
- *out = opt;
- return 0;
-}
-
-void KRB5_LIB_FUNCTION
-_krb5_get_init_creds_opt_free_krb5_error(krb5_get_init_creds_opt *opt)
-{
- if (opt->opt_private == NULL || opt->opt_private->error == NULL)
- return;
- free_KRB_ERROR(opt->opt_private->error);
- free(opt->opt_private->error);
- opt->opt_private->error = NULL;
-}
-
-void KRB5_LIB_FUNCTION
-_krb5_get_init_creds_opt_set_krb5_error(krb5_context context,
- krb5_get_init_creds_opt *opt,
- const KRB_ERROR *error)
-{
- krb5_error_code ret;
-
- if (opt->opt_private == NULL)
- return;
-
- _krb5_get_init_creds_opt_free_krb5_error(opt);
-
- opt->opt_private->error = malloc(sizeof(*opt->opt_private->error));
- if (opt->opt_private->error == NULL)
- return;
- ret = copy_KRB_ERROR(error, opt->opt_private->error);
- if (ret) {
- free(opt->opt_private->error);
- opt->opt_private->error = NULL;
- }
-}
-
+/**
+ * Free krb5_get_init_creds_opt structure.
+ *
+ * @ingroup krb5_credential
+ */
void KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_free(krb5_context context,
if (opt->opt_private->refcount < 1) /* abort ? */
return;
if (--opt->opt_private->refcount == 0) {
- _krb5_get_init_creds_opt_free_krb5_error(opt);
_krb5_get_init_creds_opt_free_pkinit(opt);
free(opt->opt_private);
}
return 0;
}
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_get_init_creds_opt_get_error(krb5_context context,
- krb5_get_init_creds_opt *opt,
- KRB_ERROR **error)
-{
- krb5_error_code ret;
-
- *error = NULL;
-
- ret = require_ext_opt(context, opt, "init_creds_opt_get_error");
- if (ret)
- return ret;
-
- if (opt->opt_private->error == NULL)
- return 0;
-
- *error = malloc(sizeof(**error));
- if (*error == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
- }
-
- ret = copy_KRB_ERROR(opt->opt_private->error, *error);
- if (ret)
- krb5_clear_error_message(context);
-
- return 0;
-}
-
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_set_addressless(krb5_context context,
krb5_get_init_creds_opt *opt,
return 0;
}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_process_last_req(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_process_last_req func,
+ void *ctx)
+{
+ krb5_error_code ret;
+ ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k");
+ if (ret)
+ return ret;
+
+ opt->opt_private->lr.func = func;
+ opt->opt_private->lr.ctx = ctx;
+
+ return 0;
+}
+
+
+#ifndef HEIMDAL_SMALLER
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
+ KRB5_DEPRECATED
+{
+ memset (opt, 0, sizeof(*opt));
+}
+
+/**
+ * Deprecated: use the new krb5_init_creds_init() and
+ * krb5_init_creds_get_error().
+ *
+ * @ingroup krb5_deprecated
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_get_error(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ KRB_ERROR **error)
+ KRB5_DEPRECATED
+{
+ *error = calloc(1, sizeof(**error));
+ if (*error == NULL) {
+ krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+#endif /* HEIMDAL_SMALLER */
/*
- * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
krb5_addresses *addrs;
krb5_enctype *etypes;
krb5_preauthtype *pre_auth_types;
- const char *in_tkt_service;
+ char *in_tkt_service;
unsigned nonce;
unsigned pk_nonce;
AS_REQ as_req;
int pa_counter;
- const char *password;
- krb5_s2k_proc key_proc;
+ /* password and keytab_data is freed on completion */
+ char *password;
+ krb5_keytab_key_proc_args *keytab_data;
+
+ krb5_pointer *keyseed;
+ krb5_s2k_proc keyproc;
krb5_get_init_creds_tristate req_pac;
krb5_pk_init_ctx pk_init_ctx;
int ic_flags;
+
+ METHOD_DATA md;
+ KRB_ERROR error;
+ AS_REP as_rep;
+ EncKDCRepPart enc_part;
+
+ krb5_prompter_fct prompter;
+ void *prompter_data;
+
} krb5_get_init_creds_ctx;
static krb5_error_code
opaque = *s2kparms;
else
krb5_data_zero(&opaque);
-
+
*key = malloc(sizeof(**key));
if (*key == NULL)
return ENOMEM;
}
static void
-free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx)
+free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
{
if (ctx->etypes)
free(ctx->etypes);
if (ctx->pre_auth_types)
free (ctx->pre_auth_types);
+ if (ctx->in_tkt_service)
+ free(ctx->in_tkt_service);
+ if (ctx->keytab_data)
+ free(ctx->keytab_data);
+ krb5_free_cred_contents(context, &ctx->cred);
+ free_METHOD_DATA(&ctx->md);
+ free_AS_REP(&ctx->as_rep);
+ free_EncKDCRepPart(&ctx->enc_part);
+ free_KRB_ERROR(&ctx->error);
free_AS_REQ(&ctx->as_req);
- memset(&ctx->as_req, 0, sizeof(ctx->as_req));
+ memset(ctx, 0, sizeof(*ctx));
}
static int
krb5_creds *cred,
krb5_principal client,
krb5_deltat start_time,
- const char *in_tkt_service,
krb5_get_init_creds_opt *options)
{
krb5_error_code ret;
- krb5_const_realm client_realm;
int tmp;
krb5_timestamp now;
goto out;
}
- client_realm = krb5_principal_get_realm (context, cred->client);
-
if (start_time)
cred->times.starttime = now + start_time;
cred->times.renew_till = now + options->renew_life;
}
- if (in_tkt_service) {
- ret = krb5_parse_name (context, in_tkt_service, &cred->server);
- if (ret)
- goto out;
- krb5_principal_set_realm (context, cred->server, client_realm);
- } else {
- ret = krb5_make_principal(context, &cred->server,
- client_realm, KRB5_TGS_NAME, client_realm,
- NULL);
- if (ret)
- goto out;
- }
return 0;
out:
time_t now)
{
char *p;
-
+
asprintf (&p, "%s%s", str, ctime(&now));
(*prompter) (context, data, NULL, p, 0, NULL);
free (p);
}
/*
- * Parse the last_req data and show it to the user if it's interesting
+ * Check the context, and in the case there is a expiration warning,
+ * use the prompter to print the warning.
+ *
+ * @param context A Kerberos 5 context.
+ * @param options An GIC options structure
+ * @param ctx The krb5_init_creds_context check for expiration.
*/
-static void
-print_expire (krb5_context context,
- krb5_const_realm realm,
- krb5_kdc_rep *rep,
- krb5_prompter_fct prompter,
- krb5_data *data)
+static krb5_error_code
+process_last_request(krb5_context context,
+ krb5_get_init_creds_opt *options,
+ krb5_init_creds_context ctx)
{
- int i;
- LastReq *lr = &rep->enc_part.last_req;
+ krb5_const_realm realm;
+ LastReq *lr;
+ krb5_boolean reported = FALSE;
krb5_timestamp sec;
time_t t;
- krb5_boolean reported = FALSE;
+ size_t i;
+
+ /*
+ * First check if there is a API consumer.
+ */
+
+ realm = krb5_principal_get_realm (context, ctx->cred.client);
+ lr = &ctx->enc_part.last_req;
+
+ if (options && options->opt_private && options->opt_private->lr.func) {
+ krb5_last_req_entry **lre;
+
+ lre = calloc(lr->len + 1, sizeof(**lre));
+ if (lre == NULL) {
+ krb5_set_error_message(context, ENOMEM,
+ N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+ for (i = 0; i < lr->len; i++) {
+ lre[i] = calloc(1, sizeof(*lre[i]));
+ if (lre[i] == NULL)
+ break;
+ lre[i]->lr_type = lr->val[i].lr_type;
+ lre[i]->value = lr->val[i].lr_value;
+ }
+
+ (*options->opt_private->lr.func)(context, lre,
+ options->opt_private->lr.ctx);
+
+ for (i = 0; i < lr->len; i++)
+ free(lre[i]);
+ free(lre);
+ }
+
+ /*
+ * Now check if we should prompt the user
+ */
+
+ if (ctx->prompter == NULL)
+ return 0;
krb5_timeofday (context, &sec);
if (lr->val[i].lr_value <= t) {
switch (abs(lr->val[i].lr_type)) {
case LR_PW_EXPTIME :
- report_expiration(context, prompter, data,
+ report_expiration(context, ctx->prompter,
+ ctx->prompter_data,
"Your password will expire at ",
lr->val[i].lr_value);
reported = TRUE;
break;
case LR_ACCT_EXPTIME :
- report_expiration(context, prompter, data,
+ report_expiration(context, ctx->prompter,
+ ctx->prompter_data,
"Your account will expire at ",
lr->val[i].lr_value);
reported = TRUE;
}
if (!reported
- && rep->enc_part.key_expiration
- && *rep->enc_part.key_expiration <= t) {
- report_expiration(context, prompter, data,
+ && ctx->enc_part.key_expiration
+ && *ctx->enc_part.key_expiration <= t) {
+ report_expiration(context, ctx->prompter,
+ ctx->prompter_data,
"Your password/account will expire at ",
- *rep->enc_part.key_expiration);
+ *ctx->enc_part.key_expiration);
}
+ return 0;
}
static krb5_addresses no_addrs = { 0, NULL };
get_init_creds_common(krb5_context context,
krb5_principal client,
krb5_deltat start_time,
- const char *in_tkt_service,
krb5_get_init_creds_opt *options,
- krb5_get_init_creds_ctx *ctx)
+ krb5_init_creds_context ctx)
{
- krb5_get_init_creds_opt default_opt;
+ krb5_get_init_creds_opt *default_opt = NULL;
krb5_error_code ret;
krb5_enctype *etypes;
krb5_preauthtype *pre_auth_types;
memset(ctx, 0, sizeof(*ctx));
if (options == NULL) {
- krb5_get_init_creds_opt_init (&default_opt);
- options = &default_opt;
- } else {
- _krb5_get_init_creds_opt_free_krb5_error(options);
+ const char *realm = krb5_principal_get_realm(context, client);
+
+ krb5_get_init_creds_opt_alloc (context, &default_opt);
+ options = default_opt;
+ krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options);
}
if (options->opt_private) {
- ctx->password = options->opt_private->password;
- ctx->key_proc = options->opt_private->key_proc;
+ if (options->opt_private->password) {
+ ret = krb5_init_creds_set_password(context, ctx,
+ options->opt_private->password);
+ if (ret)
+ goto out;
+ }
+
+ ctx->keyproc = options->opt_private->key_proc;
ctx->req_pac = options->opt_private->req_pac;
ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
ctx->ic_flags = options->opt_private->flags;
} else
ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
- if (ctx->key_proc == NULL)
- ctx->key_proc = default_s2k_func;
+ if (ctx->keyproc == NULL)
+ ctx->keyproc = default_s2k_func;
- if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
+ /* Enterprise name implicitly turns on canonicalize */
+ if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) ||
+ krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
ctx->flags.canonicalize = 1;
ctx->pre_auth_types = NULL;
ctx->addrs = NULL;
ctx->etypes = NULL;
ctx->pre_auth_types = NULL;
- ctx->in_tkt_service = in_tkt_service;
- ret = init_cred (context, &ctx->cred, client, start_time,
- in_tkt_service, options);
- if (ret)
+ ret = init_cred(context, &ctx->cred, client, start_time, options);
+ if (ret) {
+ if (default_opt)
+ krb5_get_init_creds_opt_free(context, default_opt);
return ret;
+ }
+
+ ret = krb5_init_creds_set_service(context, ctx, NULL);
+ if (ret)
+ goto out;
if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
ctx->flags.forwardable = options->forwardable;
etypes = malloc((options->etype_list_length + 1)
* sizeof(krb5_enctype));
if (etypes == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
}
memcpy (etypes, options->etype_list,
options->etype_list_length * sizeof(krb5_enctype));
pre_auth_types = malloc((options->preauth_list_length + 1)
* sizeof(krb5_preauthtype));
if (pre_auth_types == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
- return ENOMEM;
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
}
memcpy (pre_auth_types, options->preauth_list,
options->preauth_list_length * sizeof(krb5_preauthtype));
; /* XXX */
if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
ctx->flags.request_anonymous = options->anonymous;
+ if (default_opt)
+ krb5_get_init_creds_opt_free(context, default_opt);
return 0;
+ out:
+ if (default_opt)
+ krb5_get_init_creds_opt_free(context, default_opt);
+ return ret;
}
static krb5_error_code
krb5_data result_code_string;
krb5_data result_string;
char *p;
- krb5_get_init_creds_opt options;
+ krb5_get_init_creds_opt *options;
memset (&cpw_cred, 0, sizeof(cpw_cred));
- krb5_get_init_creds_opt_init (&options);
- krb5_get_init_creds_opt_set_tkt_life (&options, 60);
- krb5_get_init_creds_opt_set_forwardable (&options, FALSE);
- krb5_get_init_creds_opt_set_proxiable (&options, FALSE);
+ ret = krb5_get_init_creds_opt_alloc(context, &options);
+ if (ret)
+ return ret;
+ krb5_get_init_creds_opt_set_tkt_life (options, 60);
+ krb5_get_init_creds_opt_set_forwardable (options, FALSE);
+ krb5_get_init_creds_opt_set_proxiable (options, FALSE);
if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
- krb5_get_init_creds_opt_set_preauth_list (&options,
+ krb5_get_init_creds_opt_set_preauth_list (options,
old_options->preauth_list,
- old_options->preauth_list_length);
+ old_options->preauth_list_length);
krb5_data_zero (&result_code_string);
krb5_data_zero (&result_string);
data,
0,
"kadmin/changepw",
- &options);
+ options);
+ krb5_get_init_creds_opt_free(context, options);
if (ret)
goto out;
(int)result_string.length,
result_string.length > 0 ? (char*)result_string.data : "");
- ret = (*prompter) (context, data, NULL, p, 0, NULL);
+ /* return the result */
+ (*prompter) (context, data, NULL, p, 0, NULL);
+
free (p);
if (result_code == 0) {
strlcpy (newpw, buf1, newpw_sz);
return ret;
}
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_keyblock_key_proc (krb5_context context,
krb5_keytype type,
return krb5_copy_keyblock (context, keyseed, key);
}
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_get_init_creds_keytab(krb5_context context,
- krb5_creds *creds,
- krb5_principal client,
- krb5_keytab keytab,
- krb5_deltat start_time,
- const char *in_tkt_service,
- krb5_get_init_creds_opt *options)
-{
- krb5_get_init_creds_ctx ctx;
- krb5_error_code ret;
- krb5_keytab_key_proc_args *a;
-
- ret = get_init_creds_common(context, client, start_time,
- in_tkt_service, options, &ctx);
- if (ret)
- goto out;
-
- a = malloc (sizeof(*a));
- if (a == NULL) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- goto out;
- }
- a->principal = ctx.cred.client;
- a->keytab = keytab;
-
- ret = krb5_get_in_cred (context,
- KDCOptions2int(ctx.flags),
- ctx.addrs,
- ctx.etypes,
- ctx.pre_auth_types,
- NULL,
- krb5_keytab_key_proc,
- a,
- NULL,
- NULL,
- &ctx.cred,
- NULL);
- free (a);
-
- if (ret == 0 && creds)
- *creds = ctx.cred;
- else
- krb5_free_cred_contents (context, &ctx.cred);
-
- out:
- free_init_creds_ctx(context, &ctx);
- return ret;
-}
-
/*
*
*/
static krb5_error_code
-init_creds_init_as_req (krb5_context context,
- KDCOptions opts,
- const krb5_creds *creds,
- const krb5_addresses *addrs,
- const krb5_enctype *etypes,
- AS_REQ *a)
+init_as_req (krb5_context context,
+ KDCOptions opts,
+ const krb5_creds *creds,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ AS_REQ *a)
{
krb5_error_code ret;
krb5_crypto_destroy(context, crypto);
if (ret)
return ret;
-
+
ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
free_EncryptedData(&encdata);
if (ret)
add_enc_ts_padata(krb5_context context,
METHOD_DATA *md,
krb5_principal client,
- krb5_s2k_proc key_proc,
+ krb5_s2k_proc keyproc,
krb5_const_pointer keyseed,
krb5_enctype *enctypes,
unsigned netypes,
if(salt == NULL) {
/* default to standard salt */
ret = krb5_get_pw_salt (context, client, &salt2);
+ if (ret)
+ return ret;
salt = &salt2;
}
if (!enctypes) {
for (i = 0; i < netypes; ++i) {
krb5_keyblock *key;
- ret = (*key_proc)(context, enctypes[i], keyseed,
- *salt, s2kparams, &key);
+ ret = (*keyproc)(context, enctypes[i], keyseed,
+ *salt, s2kparams, &key);
if (ret)
continue;
ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
struct pa_info_data *ppaid,
METHOD_DATA *md)
{
- if (ctx->key_proc == NULL || ctx->password == NULL)
+ if (ctx->keyproc == NULL || ctx->keyseed == NULL)
return 0;
if (ppaid) {
add_enc_ts_padata(context, md, client,
- ctx->key_proc, ctx->password,
+ ctx->keyproc, ctx->keyseed,
&ppaid->etype, 1,
&ppaid->salt, ppaid->s2kparams);
} else {
krb5_salt salt;
-
+
/* make a v5 salted pa-data */
add_enc_ts_padata(context, md, client,
- ctx->key_proc, ctx->password,
+ ctx->keyproc, ctx->keyseed,
a->req_body.etype.val, a->req_body.etype.len,
NULL, NULL);
-
+
/* make a v4 salted pa-data */
salt.salttype = KRB5_PW_SALT;
krb5_data_zero(&salt.saltvalue);
add_enc_ts_padata(context, md, client,
- ctx->key_proc, ctx->password,
+ ctx->keyproc, ctx->keyseed,
a->req_body.etype.val, a->req_body.etype.len,
&salt, NULL);
}
{
krb5_error_code ret;
- ret = (*ctx->key_proc)(context, etype, ctx->password,
+ ret = (*ctx->keyproc)(context, etype, ctx->keyseed,
salt, s2kparams, key);
return ret;
}
break;
case KRB5_INIT_CREDS_TRISTATE_FALSE:
req.include_pac = 0;
- }
+ }
ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
&req, &len, ret);
} else if (in_md->len != 0) {
struct pa_info_data paid, *ppaid;
-
+
memset(&paid, 0, sizeof(paid));
-
+
paid.etype = ENCTYPE_NULL;
ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
-
+
pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
if (ppaid)
free_paid(context, ppaid);
krb5_get_init_creds_ctx *ctx,
krb5_creds *creds,
AS_REQ *a,
- krb5_kdc_rep *rep,
+ AS_REP *rep,
const krb5_krbhst_info *hi,
krb5_keyblock **key)
{
memset(&paid, 0, sizeof(paid));
- etype = rep->kdc_rep.enc_part.etype;
+ etype = rep->enc_part.etype;
- if (rep->kdc_rep.padata) {
+ if (rep->padata) {
paid.etype = etype;
ppaid = process_pa_info(context, creds->client, a, &paid,
- rep->kdc_rep.padata);
+ rep->padata);
}
if (ppaid == NULL) {
ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
}
pa = NULL;
- if (rep->kdc_rep.padata) {
+ if (rep->padata) {
int idx = 0;
- pa = krb5_find_padata(rep->kdc_rep.padata->val,
- rep->kdc_rep.padata->len,
+ pa = krb5_find_padata(rep->padata->val,
+ rep->padata->len,
KRB5_PADATA_PK_AS_REP,
&idx);
if (pa == NULL) {
idx = 0;
- pa = krb5_find_padata(rep->kdc_rep.padata->val,
- rep->kdc_rep.padata->len,
+ pa = krb5_find_padata(rep->padata->val,
+ rep->padata->len,
KRB5_PADATA_PK_AS_REP_19,
&idx);
}
ret = EINVAL;
krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", ""));
#endif
- } else if (ctx->password)
+ } else if (ctx->keyseed)
ret = pa_data_to_key_plain(context, creds->client, ctx,
paid.salt, paid.s2kparams, etype, key);
else {
return ret;
}
-static krb5_error_code
-init_cred_loop(krb5_context context,
- krb5_get_init_creds_opt *init_cred_opts,
- const krb5_prompter_fct prompter,
- void *prompter_data,
- krb5_get_init_creds_ctx *ctx,
- krb5_creds *creds,
- krb5_kdc_rep *ret_as_reply)
+/**
+ * Start a new context to get a new initial credential.
+ *
+ * @param context A Kerberos 5 context.
+ * @param client The Kerberos principal to get the credential for, if
+ * NULL is given, the default principal is used as determined by
+ * krb5_get_default_principal().
+ * @param prompter
+ * @param prompter_data
+ * @param start_time the time the ticket should start to be valid or 0 for now.
+ * @param options a options structure, can be NULL for default options.
+ * @param rctx A new allocated free with krb5_init_creds_free().
+ *
+ * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message().
+ *
+ * @ingroup krb5_credential
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_init(krb5_context context,
+ krb5_principal client,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ krb5_deltat start_time,
+ krb5_get_init_creds_opt *options,
+ krb5_init_creds_context *rctx)
{
+ krb5_init_creds_context ctx;
krb5_error_code ret;
- krb5_kdc_rep rep;
- METHOD_DATA md;
- krb5_data resp;
- size_t len;
- size_t size;
- krb5_krbhst_info *hi = NULL;
- krb5_sendto_ctx stctx = NULL;
+ *rctx = NULL;
- memset(&md, 0, sizeof(md));
- memset(&rep, 0, sizeof(rep));
-
- _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts);
-
- if (ret_as_reply)
- memset(ret_as_reply, 0, sizeof(*ret_as_reply));
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL) {
+ krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
- ret = init_creds_init_as_req(context, ctx->flags, creds,
- ctx->addrs, ctx->etypes, &ctx->as_req);
- if (ret)
+ ret = get_init_creds_common(context, client, start_time, options, ctx);
+ if (ret) {
+ free(ctx);
return ret;
-
- ret = krb5_sendto_ctx_alloc(context, &stctx);
- if (ret)
- goto out;
- krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
+ }
/* Set a new nonce. */
krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
- ctx->nonce &= 0xffffffff;
+ ctx->nonce &= 0x7fffffff;
/* XXX these just needs to be the same when using Windows PK-INIT */
ctx->pk_nonce = ctx->nonce;
- /*
- * Increase counter when we want other pre-auth types then
- * KRB5_PA_ENC_TIMESTAMP.
- */
-#define MAX_PA_COUNTER 3
+ ctx->prompter = prompter;
+ ctx->prompter_data = prompter_data;
- ctx->pa_counter = 0;
- while (ctx->pa_counter < MAX_PA_COUNTER) {
+ *rctx = ctx;
- ctx->pa_counter++;
+ return ret;
+}
- if (ctx->as_req.padata) {
- free_METHOD_DATA(ctx->as_req.padata);
- free(ctx->as_req.padata);
- ctx->as_req.padata = NULL;
- }
+/**
+ * Sets the service that the is requested. This call is only neede for
+ * special initial tickets, by default the a krbtgt is fetched in the default realm.
+ *
+ * @param context a Kerberos 5 context.
+ * @param ctx a krb5_init_creds_context context.
+ * @param service the service given as a string, for example
+ * "kadmind/admin". If NULL, the default krbtgt in the clients
+ * realm is set.
+ *
+ * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
+ * @ingroup krb5_credential
+ */
- /* Set a new nonce. */
- ctx->as_req.req_body.nonce = ctx->nonce;
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_set_service(krb5_context context,
+ krb5_init_creds_context ctx,
+ const char *service)
+{
+ krb5_const_realm client_realm;
+ krb5_principal principal;
+ krb5_error_code ret;
- /* fill_in_md_data */
- ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx,
- &md, &ctx->as_req.padata,
- prompter, prompter_data);
+ client_realm = krb5_principal_get_realm (context, ctx->cred.client);
+
+ if (service) {
+ ret = krb5_parse_name (context, service, &principal);
if (ret)
- goto out;
+ return ret;
+ krb5_principal_set_realm (context, principal, client_realm);
+ } else {
+ ret = krb5_make_principal(context, &principal,
+ client_realm, KRB5_TGS_NAME, client_realm,
+ NULL);
+ if (ret)
+ return ret;
+ }
+ krb5_free_principal(context, ctx->cred.server);
+ ctx->cred.server = principal;
+
+ return 0;
+}
- krb5_data_free(&ctx->req_buffer);
+/**
+ * Sets the password that will use for the request.
+ *
+ * @param context a Kerberos 5 context.
+ * @param ctx ctx krb5_init_creds_context context.
+ * @param password the password to use.
+ *
+ * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
+ * @ingroup krb5_credential
+ */
- ASN1_MALLOC_ENCODE(AS_REQ,
- ctx->req_buffer.data, ctx->req_buffer.length,
- &ctx->as_req, &len, ret);
- if (ret)
- goto out;
- if(len != ctx->req_buffer.length)
- krb5_abortx(context, "internal error in ASN.1 encoder");
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_set_password(krb5_context context,
+ krb5_init_creds_context ctx,
+ const char *password)
+{
+ if (ctx->password)
+ memset(ctx->password, 0, strlen(ctx->password));
+ if (password) {
+ ctx->password = strdup(password);
+ if (ctx->password == NULL) {
+ krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+ ctx->keyseed = (void *) ctx->password;
+ } else {
+ ctx->keyseed = NULL;
+ ctx->password = NULL;
+ }
- ret = krb5_sendto_context (context, stctx, &ctx->req_buffer,
- creds->client->realm, &resp);
- if (ret)
- goto out;
+ return 0;
+}
+
+static krb5_error_code
+keytab_key_proc(krb5_context context, krb5_enctype enctype,
+ krb5_const_pointer keyseed,
+ krb5_salt salt, krb5_data *s2kparms,
+ krb5_keyblock **key)
+{
+ krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed);
+ krb5_keytab keytab = args->keytab;
+ krb5_principal principal = args->principal;
+ krb5_error_code ret;
+ krb5_keytab real_keytab;
+ krb5_keytab_entry entry;
+
+ if(keytab == NULL)
+ krb5_kt_default(context, &real_keytab);
+ else
+ real_keytab = keytab;
+
+ ret = krb5_kt_get_entry (context, real_keytab, principal,
+ 0, enctype, &entry);
+
+ if (keytab == NULL)
+ krb5_kt_close (context, real_keytab);
+
+ if (ret)
+ return ret;
+
+ ret = krb5_copy_keyblock (context, &entry.keyblock, key);
+ krb5_kt_free_entry(context, &entry);
+ return ret;
+}
+
+
+/**
+ * Set the keytab to use for authentication.
+ *
+ * @param context a Kerberos 5 context.
+ * @param ctx ctx krb5_init_creds_context context.
+ * @param keytab the keytab to read the key from.
+ *
+ * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
+ * @ingroup krb5_credential
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_set_keytab(krb5_context context,
+ krb5_init_creds_context ctx,
+ krb5_keytab keytab)
+{
+ krb5_keytab_key_proc_args *a;
+
+ a = malloc(sizeof(*a));
+ if (a == NULL) {
+ krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+
+ a->principal = ctx->cred.client;
+ a->keytab = keytab;
+
+ ctx->keytab_data = a;
+ ctx->keyseed = (void *)a;
+ ctx->keyproc = keytab_key_proc;
+
+ return 0;
+}
+
+static krb5_error_code
+keyblock_key_proc(krb5_context context, krb5_enctype enctype,
+ krb5_const_pointer keyseed,
+ krb5_salt salt, krb5_data *s2kparms,
+ krb5_keyblock **key)
+{
+ return krb5_copy_keyblock (context, keyseed, key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_set_keyblock(krb5_context context,
+ krb5_init_creds_context ctx,
+ krb5_keyblock *keyblock)
+{
+ ctx->keyseed = (void *)keyblock;
+ ctx->keyproc = keyblock_key_proc;
+
+ return 0;
+}
+
+/**
+ * The core loop if krb5_get_init_creds() function family. Create the
+ * packets and have the caller send them off to the KDC.
+ *
+ * If the caller want all work been done for them, use
+ * krb5_init_creds_get() instead.
+ *
+ * @param context a Kerberos 5 context.
+ * @param ctx ctx krb5_init_creds_context context.
+ * @param in input data from KDC, first round it should be reset by krb5_data_zer().
+ * @param out reply to KDC.
+ * @param hostinfo KDC address info, first round it can be NULL.
+ * @param flags status of the round, if 1 is set, continue one more round.
+ *
+ * @return 0 for success, or an Kerberos 5 error code, see
+ * krb5_get_error_message().
+ *
+ * @ingroup krb5_credential
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_step(krb5_context context,
+ krb5_init_creds_context ctx,
+ krb5_data *in,
+ krb5_data *out,
+ krb5_krbhst_info *hostinfo,
+ unsigned int *flags)
+{
+ krb5_error_code ret;
+ size_t len;
+ size_t size;
+
+ krb5_data_zero(out);
+
+ if (ctx->as_req.req_body.cname == NULL) {
+ ret = init_as_req(context, ctx->flags, &ctx->cred,
+ ctx->addrs, ctx->etypes, &ctx->as_req);
+ if (ret) {
+ free_init_creds_ctx(context, ctx);
+ return ret;
+ }
+ }
+
+#define MAX_PA_COUNTER 10
+ if (ctx->pa_counter > MAX_PA_COUNTER) {
+ krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
+ N_("Looping %d times while getting "
+ "initial credentials", ""),
+ ctx->pa_counter);
+ return KRB5_GET_IN_TKT_LOOP;
+ }
+ ctx->pa_counter++;
- memset (&rep, 0, sizeof(rep));
- ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
+ /* Lets process the input packet */
+ if (in && in->length) {
+ krb5_kdc_rep rep;
+
+ memset(&rep, 0, sizeof(rep));
+
+ ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
if (ret == 0) {
- krb5_data_free(&resp);
- krb5_clear_error_message(context);
- break;
+ krb5_keyblock *key = NULL;
+ unsigned eflags = EXTRACT_TICKET_AS_REQ;
+
+ if (ctx->flags.canonicalize) {
+ eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
+ eflags |= EXTRACT_TICKET_MATCH_REALM;
+ }
+ if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
+ eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
+
+ ret = process_pa_data_to_key(context, ctx, &ctx->cred,
+ &ctx->as_req, &rep.kdc_rep, hostinfo, &key);
+ if (ret) {
+ free_AS_REP(&rep.kdc_rep);
+ goto out;
+ }
+
+ ret = _krb5_extract_ticket(context,
+ &rep,
+ &ctx->cred,
+ key,
+ NULL,
+ KRB5_KU_AS_REP_ENC_PART,
+ NULL,
+ ctx->nonce,
+ eflags,
+ NULL,
+ NULL);
+ krb5_free_keyblock(context, key);
+
+ *flags = 0;
+
+ if (ret == 0)
+ ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);
+
+ free_AS_REP(&rep.kdc_rep);
+
+ return ret;
+
} else {
/* let's try to parse it as a KRB-ERROR */
- KRB_ERROR error;
- ret = krb5_rd_error(context, &resp, &error);
- if(ret && resp.data && ((char*)resp.data)[0] == 4)
+ free_KRB_ERROR(&ctx->error);
+
+ ret = krb5_rd_error(context, in, &ctx->error);
+ if(ret && in->length && ((char*)in->data)[0] == 4)
ret = KRB5KRB_AP_ERR_V4_REPLY;
- krb5_data_free(&resp);
if (ret)
goto out;
- ret = krb5_error_from_rd_error(context, &error, creds);
+ ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);
/*
* If no preauth was set and KDC requires it, give it one
*/
if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
- free_METHOD_DATA(&md);
- memset(&md, 0, sizeof(md));
- if (error.e_data) {
- ret = decode_METHOD_DATA(error.e_data->data,
- error.e_data->length,
- &md,
+ free_METHOD_DATA(&ctx->md);
+ memset(&ctx->md, 0, sizeof(ctx->md));
+
+ if (ctx->error.e_data) {
+ ret = decode_METHOD_DATA(ctx->error.e_data->data,
+ ctx->error.e_data->length,
+ &ctx->md,
NULL);
if (ret)
krb5_set_error_message(context, ret,
- N_("failed to decode METHOD DATA", ""));
+ N_("Failed to decode METHOD-DATA", ""));
} else {
- /* XXX guess what the server want here add add md */
+ krb5_set_error_message(context, ret,
+ N_("Preauth required but no preauth "
+ "options send by KDC", ""));
}
- krb5_free_error_contents(context, &error);
- if (ret)
+ } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) {
+ /*
+ * Try adapt to timeskrew when we are using pre-auth, and
+ * if there was a time skew, try again.
+ */
+ krb5_set_real_time(context, ctx->error.stime, -1);
+ if (context->kdc_sec_offset)
+ ret = 0;
+ } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) {
+ /* client referal to a new realm */
+ if (ctx->error.crealm) {
+ krb5_set_error_message(context, ret,
+ N_("Got a client referral, not but no realm", ""));
goto out;
- } else {
- _krb5_get_init_creds_opt_set_krb5_error(context,
- init_cred_opts,
- &error);
- if (ret_as_reply)
- rep.error = error;
- else
- krb5_free_error_contents(context, &error);
- goto out;
+ }
+ ret = krb5_principal_set_realm(context,
+ ctx->cred.client,
+ *ctx->error.crealm);
}
+ if (ret)
+ goto out;
}
}
- {
- krb5_keyblock *key = NULL;
- unsigned flags = EXTRACT_TICKET_AS_REQ;
+ if (ctx->as_req.padata) {
+ free_METHOD_DATA(ctx->as_req.padata);
+ free(ctx->as_req.padata);
+ ctx->as_req.padata = NULL;
+ }
- if (ctx->flags.request_anonymous)
- flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
- if (ctx->flags.canonicalize) {
- flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
- flags |= EXTRACT_TICKET_MATCH_REALM;
- }
- if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
- flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
+ /* Set a new nonce. */
+ ctx->as_req.req_body.nonce = ctx->nonce;
+
+ /* fill_in_md_data */
+ ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx,
+ &ctx->md, &ctx->as_req.padata,
+ ctx->prompter, ctx->prompter_data);
+ if (ret)
+ goto out;
- ret = process_pa_data_to_key(context, ctx, creds,
- &ctx->as_req, &rep, hi, &key);
- if (ret)
- goto out;
-
- ret = _krb5_extract_ticket(context,
- &rep,
- creds,
- key,
- NULL,
- KRB5_KU_AS_REP_ENC_PART,
- NULL,
- ctx->nonce,
- flags,
- NULL,
- NULL);
- krb5_free_keyblock(context, key);
- }
-out:
- if (stctx)
- krb5_sendto_ctx_free(context, stctx);
krb5_data_free(&ctx->req_buffer);
- free_METHOD_DATA(&md);
- memset(&md, 0, sizeof(md));
- if (ret == 0 && ret_as_reply)
- *ret_as_reply = rep;
- else
- krb5_free_kdc_rep (context, &rep);
+ ASN1_MALLOC_ENCODE(AS_REQ,
+ ctx->req_buffer.data, ctx->req_buffer.length,
+ &ctx->as_req, &len, ret);
+ if (ret)
+ goto out;
+ if(len != ctx->req_buffer.length)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ out->data = ctx->req_buffer.data;
+ out->length = ctx->req_buffer.length;
+
+ *flags = 1;
+
+ return 0;
+ out:
return ret;
}
+/**
+ * Extract the newly acquired credentials from krb5_init_creds_context
+ * context.
+ *
+ * @param context A Kerberos 5 context.
+ * @param ctx
+ * @param cred credentials, free with krb5_free_cred_contents().
+ *
+ * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
-krb5_get_init_creds(krb5_context context,
- krb5_creds *creds,
- krb5_principal client,
- krb5_prompter_fct prompter,
- void *data,
- krb5_deltat start_time,
- const char *in_tkt_service,
- krb5_get_init_creds_opt *options)
+krb5_init_creds_get_creds(krb5_context context,
+ krb5_init_creds_context ctx,
+ krb5_creds *cred)
{
- krb5_get_init_creds_ctx ctx;
- krb5_kdc_rep kdc_reply;
- krb5_error_code ret;
- char buf[BUFSIZ];
- int done;
+ return krb5_copy_creds_contents(context, &ctx->cred, cred);
+}
+
+/**
+ * Get the last error from the transaction.
+ *
+ * @return Returns 0 or an error code
+ *
+ * @ingroup krb5_credential
+ */
- memset(&kdc_reply, 0, sizeof(kdc_reply));
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_get_error(krb5_context context,
+ krb5_init_creds_context ctx,
+ KRB_ERROR *error)
+{
+ krb5_error_code ret;
- ret = get_init_creds_common(context, client, start_time,
- in_tkt_service, options, &ctx);
+ ret = copy_KRB_ERROR(&ctx->error, error);
if (ret)
- goto out;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- done = 0;
- while(!done) {
- memset(&kdc_reply, 0, sizeof(kdc_reply));
-
- ret = init_cred_loop(context,
- options,
- prompter,
- data,
- &ctx,
- &ctx.cred,
- &kdc_reply);
-
- switch (ret) {
- case 0 :
- done = 1;
- break;
- case KRB5KDC_ERR_KEY_EXPIRED :
- /* try to avoid recursion */
+ return ret;
+}
- /* don't try to change password where then where none */
- if (prompter == NULL || ctx.password == NULL)
- goto out;
+/**
+ * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
+ *
+ * @param context A Kerberos 5 context.
+ * @param ctx The krb5_init_creds_context to free.
+ *
+ * @ingroup krb5_credential
+ */
- krb5_clear_error_message (context);
+void KRB5_LIB_FUNCTION
+krb5_init_creds_free(krb5_context context,
+ krb5_init_creds_context ctx)
+{
+ free_init_creds_ctx(context, ctx);
+ free(ctx);
+}
- if (ctx.in_tkt_service != NULL
- && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0)
- goto out;
+/**
+ * Get new credentials as setup by the krb5_init_creds_context.
+ *
+ * @param context A Kerberos 5 context.
+ * @param ctx The krb5_init_creds_context to process.
+ *
+ * @ingroup krb5_credential
+ */
- ret = change_password (context,
- client,
- ctx.password,
- buf,
- sizeof(buf),
- prompter,
- data,
- options);
- if (ret)
- goto out;
- ctx.password = buf;
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx)
+{
+ krb5_sendto_ctx stctx = NULL;
+ krb5_krbhst_info *hostinfo = NULL;
+ krb5_error_code ret;
+ krb5_data in, out;
+ unsigned int flags = 0;
+
+ krb5_data_zero(&in);
+ krb5_data_zero(&out);
+
+ ret = krb5_sendto_ctx_alloc(context, &stctx);
+ if (ret)
+ goto out;
+ krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
+
+ while (1) {
+ flags = 0;
+ ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &flags);
+ krb5_data_free(&in);
+ if (ret)
+ goto out;
+
+ if ((flags & 1) == 0)
break;
- default:
+
+ ret = krb5_sendto_context (context, stctx, &out,
+ ctx->cred.client->realm, &in);
+ if (ret)
goto out;
- }
- }
- if (prompter)
- print_expire (context,
- krb5_principal_get_realm (context, ctx.cred.client),
- &kdc_reply,
- prompter,
- data);
+ }
out:
- memset (buf, 0, sizeof(buf));
- free_init_creds_ctx(context, &ctx);
- krb5_free_kdc_rep (context, &kdc_reply);
- if (ret == 0)
- *creds = ctx.cred;
- else
- krb5_free_cred_contents (context, &ctx.cred);
+ if (stctx)
+ krb5_sendto_ctx_free(context, stctx);
return ret;
}
+/**
+ * Get new credentials using password.
+ *
+ * @ingroup krb5_credential
+ */
+
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_password(krb5_context context,
krb5_creds *creds,
void *data,
krb5_deltat start_time,
const char *in_tkt_service,
- krb5_get_init_creds_opt *in_options)
+ krb5_get_init_creds_opt *options)
{
- krb5_get_init_creds_opt *options;
+ krb5_init_creds_context ctx;
char buf[BUFSIZ];
krb5_error_code ret;
+ int chpw = 0;
- if (in_options == NULL) {
- const char *realm = krb5_principal_get_realm(context, client);
- ret = krb5_get_init_creds_opt_alloc(context, &options);
- if (ret == 0)
- krb5_get_init_creds_opt_set_default_flags(context,
- NULL,
- realm,
- options);
- } else
- ret = _krb5_get_init_creds_opt_copy(context, in_options, &options);
+ again:
+ ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx);
if (ret)
- return ret;
+ goto out;
- if (password == NULL &&
- options->opt_private->password == NULL &&
- options->opt_private->pk_init_ctx == NULL)
- {
+ ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
+ if (ret)
+ goto out;
+
+ if (ctx->password == NULL && password == NULL) {
krb5_prompt prompt;
krb5_data password_data;
char *p, *q;
free (q);
if (ret) {
memset (buf, 0, sizeof(buf));
- krb5_get_init_creds_opt_free(context, options);
ret = KRB5_LIBOS_PWDINTR;
krb5_clear_error_message (context);
- return ret;
+ goto out;
}
password = password_data.data;
}
- if (options->opt_private->password == NULL) {
- ret = krb5_get_init_creds_opt_set_pa_password(context, options,
- password, NULL);
- if (ret) {
- krb5_get_init_creds_opt_free(context, options);
- memset(buf, 0, sizeof(buf));
- return ret;
- }
+ if (password) {
+ ret = krb5_init_creds_set_password(context, ctx, password);
+ if (ret)
+ goto out;
}
- ret = krb5_get_init_creds(context, creds, client, prompter,
- data, start_time, in_tkt_service, options);
- krb5_get_init_creds_opt_free(context, options);
+ ret = krb5_init_creds_get(context, ctx);
+
+ if (ret == 0)
+ process_last_request(context, options, ctx);
+
+
+ if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
+ char buf[1024];
+
+ /* try to avoid recursion */
+ if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
+ goto out;
+
+ /* don't try to change password where then where none */
+ if (prompter == NULL)
+ goto out;
+
+ ret = change_password (context,
+ client,
+ ctx->password,
+ buf,
+ sizeof(buf),
+ prompter,
+ data,
+ options);
+ if (ret)
+ goto out;
+ chpw = 1;
+ krb5_init_creds_free(context, ctx);
+ goto again;
+ }
+
+ out:
+ if (ret == 0)
+ krb5_init_creds_get_creds(context, ctx, creds);
+
+ if (ctx)
+ krb5_init_creds_free(context, ctx);
+
memset(buf, 0, sizeof(buf));
return ret;
}
-static krb5_error_code
-init_creds_keyblock_key_proc (krb5_context context,
- krb5_enctype type,
- krb5_salt salt,
- krb5_const_pointer keyseed,
- krb5_keyblock **key)
-{
- return krb5_copy_keyblock (context, keyseed, key);
-}
+/**
+ * Get new credentials using keyblock.
+ *
+ * @ingroup krb5_credential
+ */
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_keyblock(krb5_context context,
const char *in_tkt_service,
krb5_get_init_creds_opt *options)
{
- struct krb5_get_init_creds_ctx ctx;
+ krb5_init_creds_context ctx;
krb5_error_code ret;
- ret = get_init_creds_common(context, client, start_time,
- in_tkt_service, options, &ctx);
+ memset(creds, 0, sizeof(*creds));
+
+ ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
if (ret)
goto out;
- ret = krb5_get_in_cred (context,
- KDCOptions2int(ctx.flags),
- ctx.addrs,
- ctx.etypes,
- ctx.pre_auth_types,
- NULL,
- init_creds_keyblock_key_proc,
- keyblock,
- NULL,
- NULL,
- &ctx.cred,
- NULL);
-
- if (ret == 0 && creds)
- *creds = ctx.cred;
- else
- krb5_free_cred_contents (context, &ctx.cred);
+ ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
+ if (ret)
+ goto out;
+
+ ret = krb5_init_creds_set_keyblock(context, ctx, keyblock);
+ if (ret)
+ goto out;
+
+ ret = krb5_init_creds_get(context, ctx);
+
+ if (ret == 0)
+ process_last_request(context, options, ctx);
+
+ out:
+ if (ret == 0)
+ krb5_init_creds_get_creds(context, ctx, creds);
+
+ if (ctx)
+ krb5_init_creds_free(context, ctx);
+
+ return ret;
+}
+
+/**
+ * Get new credentials using keytab.
+ *
+ * @ingroup krb5_credential
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_keytab(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ krb5_keytab keytab,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
+{
+ krb5_init_creds_context ctx;
+ krb5_error_code ret;
+
+ memset(creds, 0, sizeof(*creds));
+
+ ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
+ if (ret)
+ goto out;
+
+ ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
+ if (ret)
+ goto out;
+
+ ret = krb5_init_creds_set_keytab(context, ctx, keytab);
+ if (ret)
+ goto out;
+
+ ret = krb5_init_creds_get(context, ctx);
+ if (ret == 0)
+ process_last_request(context, options, ctx);
out:
- free_init_creds_ctx(context, &ctx);
+ if (ret == 0)
+ krb5_init_creds_get_creds(context, ctx, creds);
+
+ if (ctx)
+ krb5_init_creds_free(context, ctx);
+
return ret;
}
char *door_path;
} krb5_kcmcache;
+typedef struct krb5_kcm_cursor {
+ unsigned long offset;
+ unsigned long length;
+ kcmuuid_t *uuids;
+} *krb5_kcm_cursor;
+
+
#define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data)
#define CACHENAME(X) (KCMCACHE(X)->name)
-#define KCMCURSOR(C) (*(uint32_t *)(C))
+#define KCMCURSOR(C) ((krb5_kcm_cursor)(C))
+
+#ifdef HAVE_DOOR_CREATE
static krb5_error_code
try_door(krb5_context context,
krb5_data *request_data,
krb5_data *response_data)
{
-#ifdef HAVE_DOOR_CREATE
door_arg_t arg;
int fd;
int ret;
return ret;
return 0;
-#else
- return KRB5_CC_IO;
-#endif
}
+#endif /* HAVE_DOOR_CREATE */
static krb5_error_code
try_unix_socket(krb5_context context,
ret = KRB5_CC_NOSUPP;
for (i = 0; i < context->max_retries; i++) {
+#ifdef HAVE_DOOR_CREATE
ret = try_door(context, k, &request_data, response_data);
if (ret == 0 && response_data->length != 0)
break;
+#endif
ret = try_unix_socket(context, k, &request_data, response_data);
if (ret == 0 && response_data->length != 0)
break;
k = malloc(sizeof(*k));
if (k == NULL) {
- krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", ""));
+ krb5_set_error_message(context, KRB5_CC_NOMEM,
+ N_("malloc: out of memory", ""));
return KRB5_CC_NOMEM;
}
krb5_cc_cursor *cursor)
{
krb5_error_code ret;
+ krb5_kcm_cursor c;
krb5_kcmcache *k = KCMCACHE(id);
krb5_storage *request, *response;
krb5_data response_data;
- int32_t tmp;
ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request);
if (ret)
}
ret = kcm_call(context, k, request, &response, &response_data);
- if (ret) {
- krb5_storage_free(request);
+ krb5_storage_free(request);
+ if (ret)
+ return ret;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret,
+ N_("malloc: out of memory", ""));
return ret;
}
- ret = krb5_ret_int32(response, &tmp);
- if (ret || tmp < 0)
- ret = KRB5_CC_IO;
+ while (1) {
+ ssize_t sret;
+ kcmuuid_t uuid;
+ void *ptr;
+
+ sret = krb5_storage_read(response, &uuid, sizeof(uuid));
+ if (sret == 0) {
+ ret = 0;
+ break;
+ } else if (sret != sizeof(uuid)) {
+ ret = EINVAL;
+ break;
+ }
+
+ ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
+ if (ptr == NULL) {
+ free(c->uuids);
+ free(c);
+ krb5_set_error_message(context, ENOMEM,
+ N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+ c->uuids = ptr;
+
+ memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
+ c->length += 1;
+ }
- krb5_storage_free(request);
krb5_storage_free(response);
krb5_data_free(&response_data);
- if (ret)
+ if (ret) {
+ free(c->uuids);
+ free(c);
return ret;
+ }
- *cursor = malloc(sizeof(tmp));
- if (*cursor == NULL)
- return KRB5_CC_NOMEM;
-
- KCMCURSOR(*cursor) = tmp;
+ *cursor = c;
return 0;
}
{
krb5_error_code ret;
krb5_kcmcache *k = KCMCACHE(id);
+ krb5_kcm_cursor c = KCMCURSOR(*cursor);
krb5_storage *request, *response;
krb5_data response_data;
+ ssize_t sret;
+
+ again:
+
+ if (c->offset >= c->length)
+ return KRB5_CC_END;
ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request);
if (ret)
return ret;
}
- ret = krb5_store_int32(request, KCMCURSOR(*cursor));
- if (ret) {
+ sret = krb5_storage_write(request,
+ &c->uuids[c->offset],
+ sizeof(c->uuids[c->offset]));
+ c->offset++;
+ if (sret != sizeof(c->uuids[c->offset])) {
krb5_storage_free(request);
- return ret;
+ krb5_clear_error_message(context);
+ return ENOMEM;
}
ret = kcm_call(context, k, request, &response, &response_data);
- if (ret) {
- krb5_storage_free(request);
- return ret;
+ krb5_storage_free(request);
+ if (ret == KRB5_CC_END) {
+ goto again;
}
ret = krb5_ret_creds(response, creds);
if (ret)
ret = KRB5_CC_IO;
- krb5_storage_free(request);
krb5_storage_free(response);
krb5_data_free(&response_data);
{
krb5_error_code ret;
krb5_kcmcache *k = KCMCACHE(id);
+ krb5_kcm_cursor c = KCMCURSOR(*cursor);
krb5_storage *request;
ret = kcm_storage_request(context, KCM_OP_END_GET, &request);
return ret;
}
- ret = krb5_store_int32(request, KCMCURSOR(*cursor));
- if (ret) {
- krb5_storage_free(request);
- return ret;
- }
-
ret = kcm_call(context, k, request, NULL, NULL);
- if (ret) {
- krb5_storage_free(request);
+ krb5_storage_free(request);
+ if (ret)
return ret;
- }
- krb5_storage_free(request);
+ free(c->uuids);
+ free(c);
- KCMCURSOR(*cursor) = 0;
- free(*cursor);
*cursor = NULL;
return ret;
const krb5_keyblock *inblock,
krb5_keyblock **to)
{
+ krb5_error_code ret;
krb5_keyblock *k;
+
+ *to = NULL;
- k = malloc (sizeof(*k));
+ k = calloc (1, sizeof(*k));
if (k == NULL) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
+
+ ret = krb5_copy_keyblock_contents (context, inblock, k);
+ if (ret) {
+ free(k);
+ return ret;
+ }
*to = k;
- return krb5_copy_keyblock_contents (context, inblock, k);
+ return 0;
}
krb5_enctype
RCSID("$Id$");
-/*
- * Register a new keytab in `ops'
- * Return 0 or an error.
+/**
+ * @page krb5_keytab_intro The keytab handing functions
+ * @section section_krb5_keytab Kerberos Keytabs
+ *
+ * See the library functions here: @ref krb5_keytab
+ *
+ * Keytabs are long term key storage for servers, their equvalment of
+ * password files.
+ *
+ * Normally the only function that useful for server are to specify
+ * what keytab to use to other core functions like krb5_rd_req()
+ * krb5_kt_resolve(), and krb5_kt_close().
+ *
+ * @subsection krb5_keytab_names Keytab names
+ *
+ * A keytab name is on the form type:residual. The residual part is
+ * specific to each keytab-type.
+ *
+ * When a keytab-name is resolved, the type is matched with an internal
+ * list of keytab types. If there is no matching keytab type,
+ * the default keytab is used. The current default type is FILE.
+ *
+ * The default value can be changed in the configuration file
+ * /etc/krb5.conf by setting the variable
+ * [defaults]default_keytab_name.
+ *
+ * The keytab types that are implemented in Heimdal are:
+ * - file
+ * store the keytab in a file, the type's name is FILE . The
+ * residual part is a filename. For compatibility with other
+ * Kerberos implemtation WRFILE and JAVA14 is also accepted. WRFILE
+ * has the same format as FILE. JAVA14 have a format that is
+ * compatible with older versions of MIT kerberos and SUN's Java
+ * based installation. They store a truncted kvno, so when the knvo
+ * excess 255, they are truncted in this format.
+ *
+ * - keytab
+ * store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ),
+ * the type's name is AFSKEYFILE. The residual part is a filename.
+ *
+ * - krb4
+ * the keytab is a Kerberos 4 srvtab that is on-the-fly converted to
+ * a keytab. The type's name is krb4 The residual part is a
+ * filename.
+ *
+ * - memory
+ * The keytab is stored in a memory segment. This allows sensitive
+ * and/or temporary data not to be stored on disk. The type's name
+ * is MEMORY. Each MEMORY keytab is referenced counted by and
+ * opened by the residual name, so two handles can point to the
+ * same memory area. When the last user closes the entry, it
+ * disappears.
+ *
+ *
+ * @subsection krb5_keytab_example Keytab example
+ *
+ * This is a minimalistic version of ktutil.
+ *
+ * @code
+int
+main (int argc, char **argv)
+{
+ krb5_context context;
+ krb5_keytab keytab;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ krb5_error_code ret;
+ char *principal;
+
+ if (krb5_init_context (&context) != 0)
+ errx(1, "krb5_context");
+
+ ret = krb5_kt_default (context, &keytab);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_kt_default");
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_kt_start_seq_get");
+ while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
+ krb5_unparse_name_short(context, entry.principal, &principal);
+ printf("principal: %s\n", principal);
+ free(principal);
+ krb5_kt_free_entry(context, &entry);
+ }
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_kt_end_seq_get");
+ ret = krb5_kt_close(context, keytab);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_kt_close");
+ krb5_free_context(context);
+ return 0;
+}
+ * @endcode
+ *
+ */
+
+
+/**
+ * Register a new keytab backend.
+ *
+ * @param context a Keberos context.
+ * @param ops a backend to register.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
tmp = realloc(context->kt_types,
(context->num_kt_types + 1) * sizeof(*context->kt_types));
if(tmp == NULL) {
- krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ krb5_set_error_message(context, ENOMEM,
+ N_("malloc: out of memory", ""));
return ENOMEM;
}
memcpy(&tmp[context->num_kt_types], ops,
return 0;
}
-/*
+/**
* Resolve the keytab name (of the form `type:residual') in `name'
* into a keytab in `id'.
- * Return 0 or an error
+ *
+ * @param context a Keberos context.
+ * @param name name to resolve
+ * @param id resulting keytab, free with krb5_kt_close().
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_resolve(krb5_context context,
const char *name,
return ret;
}
-/*
+/**
* copy the name of the default keytab into `name'.
- * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
+ *
+ * @param context a Keberos context.
+ * @param name buffer where the name will be written
+ * @param namesize length of name
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return 0;
}
-/*
- * copy the name of the default modify keytab into `name'.
- * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
+/**
+ * Copy the name of the default modify keytab into `name'.
+ *
+ * @param context a Keberos context.
+ * @param name buffer where the name will be written
+ * @param namesize length of name
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return 0;
}
-/*
+/**
* Set `id' to the default keytab.
- * Return 0 or an error.
+ *
+ * @param context a Keberos context.
+ * @param id the new default keytab.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return krb5_kt_resolve (context, context->default_keytab, id);
}
-/*
+/**
* Read the key identified by `(principal, vno, enctype)' from the
* keytab in `keyprocarg' (the default if == NULL) into `*key'.
- * Return 0 or an error.
+ *
+ * @param context a Keberos context.
+ * @param keyprocarg
+ * @param principal
+ * @param vno
+ * @param enctype
+ * @param key
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return ret;
}
-/*
+/**
* Return the type of the `keytab' in the string `prefix of length
* `prefixsize'.
+ *
+ * @param context a Keberos context.
+ * @param keytab the keytab to get the prefix for
+ * @param prefix prefix buffer
+ * @param prefixsize length of prefix buffer
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return 0;
}
-/*
+/**
* Retrieve the name of the keytab `keytab' into `name', `namesize'
- * Return 0 or an error.
+ *
+ * @param context a Keberos context.
+ * @param keytab the keytab to get the name for.
+ * @param name name buffer.
+ * @param namesize size of name buffer.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return (*keytab->get_name)(context, keytab, name, namesize);
}
-/*
+/**
* Retrieve the full name of the keytab `keytab' and store the name in
- * `str'. `str' needs to be freed by the caller using free(3).
- * Returns 0 or an error. On error, *str is set to NULL.
+ * `str'.
+ *
+ * @param context a Keberos context.
+ * @param keytab keytab to get name for.
+ * @param str the name of the keytab name, usee krb5_xfree() to free
+ * the string. On error, *str is set to NULL.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return 0;
}
-/*
+/**
* Finish using the keytab in `id'. All resources will be released,
- * even on errors. Return 0 or an error.
+ * even on errors.
+ *
+ * @param context a Keberos context.
+ * @param id keytab to close.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return ret;
}
+/**
+ * Destroy (remove) the keytab in `id'. All resources will be released,
+ * even on errors, does the equvalment of krb5_kt_close() on the resources.
+ *
+ * @param context a Keberos context.
+ * @param id keytab to destroy.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_destroy(krb5_context context,
+ krb5_keytab id)
+{
+ krb5_error_code ret;
+
+ ret = (*id->destroy)(context, id);
+ krb5_kt_close(context, id);
+ return ret;
+}
+
/*
+ * Match any aliases in keytab `entry' with `principal'.
+ */
+
+static krb5_boolean
+compare_aliseses(krb5_context context,
+ krb5_keytab_entry *entry,
+ krb5_const_principal principal)
+{
+ unsigned int i;
+ if (entry->aliases == NULL)
+ return FALSE;
+ for (i = 0; i < entry->aliases->len; i++)
+ if (krb5_principal_compare(context, &entry->aliases->val[i], principal))
+ return TRUE;
+ return FALSE;
+}
+
+/**
* Compare `entry' against `principal, vno, enctype'.
* Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
* Return TRUE if they compare the same, FALSE otherwise.
+ *
+ * @param context a Keberos context.
+ * @param entry an entry to match with.
+ * @param principal principal to match, NULL matches all principals.
+ * @param vno key version to match, 0 matches all key version numbers.
+ * @param enctype encryption type to match, 0 matches all encryption types.
+ *
+ * @return Return TRUE or match, FALSE if not matched.
+ *
+ * @ingroup krb5_keytab
*/
krb5_boolean KRB5_LIB_FUNCTION
krb5_enctype enctype)
{
if(principal != NULL &&
- !krb5_principal_compare(context, entry->principal, principal))
+ !(krb5_principal_compare(context, entry->principal, principal) ||
+ compare_aliseses(context, entry, principal)))
return FALSE;
if(vno && vno != entry->vno)
return FALSE;
return TRUE;
}
-/*
+krb5_error_code
+_krb5_kt_principal_not_found(krb5_context context,
+ krb5_error_code ret,
+ krb5_keytab id,
+ krb5_const_principal principal,
+ krb5_enctype enctype,
+ int kvno)
+{
+ char princ[256], kvno_str[25], *kt_name;
+ char *enctype_str = NULL;
+
+ krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
+ krb5_kt_get_full_name (context, id, &kt_name);
+ krb5_enctype_to_string(context, enctype, &enctype_str);
+
+ if (kvno)
+ snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
+ else
+ kvno_str[0] = '\0';
+
+ krb5_set_error_message (context, ret,
+ N_("Failed to find %s%s in keytab %s (%s)",
+ "principal, kvno, keytab file, enctype"),
+ princ,
+ kvno_str,
+ kt_name ? kt_name : "unknown keytab",
+ enctype_str ? enctype_str : "unknown enctype");
+ free(kt_name);
+ free(enctype_str);
+ return ret;
+}
+
+
+/**
* Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
- * from the keytab `id'.
- * kvno == 0 is a wildcard and gives the keytab with the highest vno.
- * Return 0 or an error.
+ * from the keytab `id'. Matching is done like krb5_kt_compare().
+ *
+ * @param context a Keberos context.
+ * @param id a keytab.
+ * @param principal principal to match, NULL matches all principals.
+ * @param kvno key version to match, 0 matches all key version numbers.
+ * @param enctype encryption type to match, 0 matches all encryption types.
+ * @param entry the returned entry, free with krb5_kt_free_entry().
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_free_entry(context, &tmp);
}
krb5_kt_end_seq_get (context, id, &cursor);
- if (entry->vno) {
- return 0;
- } else {
- char princ[256], kvno_str[25], *kt_name;
- char *enctype_str = NULL;
-
- krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
- krb5_kt_get_full_name (context, id, &kt_name);
- krb5_enctype_to_string(context, enctype, &enctype_str);
-
- if (kvno)
- snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
- else
- kvno_str[0] = '\0';
-
- krb5_set_error_message (context, KRB5_KT_NOTFOUND,
- N_("Failed to find %s%s in keytab %s (%s)",
- "principal, kvno, keytab file, enctype"),
- princ,
- kvno_str,
- kt_name ? kt_name : "unknown keytab",
- enctype_str ? enctype_str : "unknown enctype");
- free(kt_name);
- free(enctype_str);
- return KRB5_KT_NOTFOUND;
- }
+ if (entry->vno == 0)
+ return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
+ id, principal, enctype, kvno);
+ return 0;
}
-/*
+/**
* Copy the contents of `in' into `out'.
- * Return 0 or an error. */
+ *
+ * @param context a Keberos context.
+ * @param in the keytab entry to copy.
+ * @param out the copy of the keytab entry, free with krb5_kt_free_entry().
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
+ */
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_copy_entry_contents(krb5_context context,
return ret;
}
-/*
+/**
* Free the contents of `entry'.
+ *
+ * @param context a Keberos context.
+ * @param entry the entry to free
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return 0;
}
-/*
+/**
* Set `cursor' to point at the beginning of `id'.
- * Return 0 or an error.
+ *
+ * @param context a Keberos context.
+ * @param id a keytab.
+ * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get().
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return (*id->start_seq_get)(context, id, cursor);
}
-/*
- * Get the next entry from `id' pointed to by `cursor' and advance the
- * `cursor'.
- * Return 0 or an error.
+/**
+ * Get the next entry from keytab, advance the cursor. On last entry
+ * the function will return KRB5_KT_END.
+ *
+ * @param context a Keberos context.
+ * @param id a keytab.
+ * @param entry the returned entry, free with krb5_kt_free_entry().
+ * @param cursor the cursor of the iteration.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return (*id->next_entry)(context, id, entry, cursor);
}
-/*
+/**
* Release all resources associated with `cursor'.
+ *
+ * @param context a Keberos context.
+ * @param id a keytab.
+ * @param cursor the cursor to free.
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return (*id->end_seq_get)(context, id, cursor);
}
-/*
+/**
* Add the entry in `entry' to the keytab `id'.
- * Return 0 or an error.
+ *
+ * @param context a Keberos context.
+ * @param id a keytab.
+ * @param entry the entry to add
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
return (*id->add)(context, id,entry);
}
-/*
- * Remove the entry `entry' from the keytab `id'.
- * Return 0 or an error.
+/**
+ * Remove an entry from the keytab, matching is done using
+ * krb5_kt_compare().
+
+ * @param context a Keberos context.
+ * @param id a keytab.
+ * @param entry the entry to remove
+ *
+ * @return Return an error code or 0, see krb5_get_error_message().
+ *
+ * @ingroup krb5_keytab
*/
krb5_error_code KRB5_LIB_FUNCTION
any_resolve,
any_get_name,
any_close,
+ NULL, /* destroy */
NULL, /* get */
any_start_seq_get,
any_next_entry,
return 0;
}
+static krb5_error_code
+fkt_destroy(krb5_context context, krb5_keytab id)
+{
+ struct fkt_data *d = id->data;
+ _krb5_erase_file(context, d->filename);
+ return 0;
+}
+
static krb5_error_code
fkt_get_name(krb5_context context,
krb5_keytab id,
int ret;
int8_t tmp8;
int32_t tmp32;
+ uint32_t utmp32;
off_t pos, curpos;
pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
if (ret)
goto out;
- ret = krb5_ret_int32(cursor->sp, &tmp32);
- entry->timestamp = tmp32;
+ ret = krb5_ret_uint32(cursor->sp, &utmp32);
+ entry->timestamp = utmp32;
if (ret)
goto out;
ret = krb5_ret_int8(cursor->sp, &tmp8);
curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
if(len + 4 + pos - curpos >= 4) {
ret = krb5_ret_int32(cursor->sp, &tmp32);
- if (ret == 0 && tmp32 != 0) {
+ if (ret == 0 && tmp32 != 0)
entry->vno = tmp32;
- }
}
+ /* there might be a flags field here */
+ if(len + 4 + pos - curpos >= 8) {
+ ret = krb5_ret_uint32(cursor->sp, &utmp32);
+ if (ret == 0)
+ entry->flags = tmp32;
+ } else
+ entry->flags = 0;
+
+ entry->aliases = NULL;
+
if(start) *start = pos;
if(end) *end = pos + 4 + len;
out:
krb5_storage_free(emem);
goto out;
}
+ ret = krb5_store_uint32 (emem, entry->flags);
+ if (ret) {
+ krb5_set_error_message(context, ret,
+ N_("Failed storing extended kvno "
+ "in keytab %s", ""),
+ d->filename);
+ krb5_storage_free(emem);
+ goto out;
+ }
}
ret = krb5_storage_to_data(emem, &keytab);
fkt_resolve,
fkt_get_name,
fkt_close,
+ fkt_destroy,
NULL, /* get */
fkt_start_seq_get,
fkt_next_entry,
fkt_resolve,
fkt_get_name,
fkt_close,
+ fkt_destroy,
NULL, /* get */
fkt_start_seq_get,
fkt_next_entry,
fkt_resolve_java14,
fkt_get_name,
fkt_close,
+ fkt_destroy,
NULL, /* get */
fkt_start_seq_get,
fkt_next_entry,
ret = 0;
entry->timestamp = time(NULL);
+ entry->flags = 0;
+ entry->aliases = NULL;
out:
krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET);
akf_resolve,
akf_get_name,
akf_close,
+ NULL, /* destroy */
NULL, /* get */
akf_start_seq_get,
akf_next_entry,
mkt_resolve,
mkt_get_name,
mkt_close,
+ NULL, /* destroy */
NULL, /* get */
mkt_start_seq_get,
mkt_next_entry,
#define KRB5KDC_ERR_KEY_EXP KRB5KDC_ERR_KEY_EXPIRED
#endif
+#ifndef KRB5_DEPRECATED
+#define KRB5_DEPRECATED __attribute__((deprecated))
+#endif
+
/* simple constants */
#ifndef TRUE
typedef ENCTYPE krb5_enctype;
+typedef struct krb5_get_init_creds_ctx *krb5_init_creds_context;
+
typedef heim_octet_string krb5_data;
/* PKINIT related forward declarations */
/* Keyusage for the server referral in a TGS req */
KRB5_KU_SAM_ENC_NONCE_SAD = 27,
/* Encryption of the SAM-NONCE-OR-SAD field */
+ KRB5_KU_PA_PKINIT_KX = 44,
+ /* Encryption type of the kdc session contribution in pk-init */
KRB5_KU_DIGEST_ENCRYPT = -18,
/* Encryption key usage used in the digest encryption field */
KRB5_KU_DIGEST_OPAQUE = -19,
typedef HostAddresses krb5_addresses;
typedef enum krb5_keytype {
- KEYTYPE_NULL = 0,
- KEYTYPE_DES = 1,
- KEYTYPE_DES3 = 7,
- KEYTYPE_AES128 = 17,
- KEYTYPE_AES256 = 18,
- KEYTYPE_ARCFOUR = 23,
- KEYTYPE_ARCFOUR_56 = 24
+ KEYTYPE_NULL = ETYPE_NULL,
+ KEYTYPE_DES = ETYPE_DES_CBC_CRC,
+ KEYTYPE_DES3 = ETYPE_OLD_DES3_CBC_SHA1,
+ KEYTYPE_AES128 = ETYPE_AES128_CTS_HMAC_SHA1_96,
+ KEYTYPE_AES256 = ETYPE_AES256_CTS_HMAC_SHA1_96,
+ KEYTYPE_ARCFOUR = ETYPE_ARCFOUR_HMAC_MD5,
+ KEYTYPE_ARCFOUR_56 = ETYPE_ARCFOUR_HMAC_MD5_56
} krb5_keytype;
typedef EncryptionKey krb5_keyblock;
typedef Principal krb5_principal_data;
typedef struct Principal *krb5_principal;
typedef const struct Principal *krb5_const_principal;
+typedef struct Principals *krb5_principals;
typedef time_t krb5_deltat;
typedef time_t krb5_timestamp;
krb5_kvno vno;
krb5_keyblock keyblock;
uint32_t timestamp;
+ uint32_t flags;
+ krb5_principals aliases;
} krb5_keytab_entry;
typedef struct krb5_kt_cursor {
krb5_error_code (*resolve)(krb5_context, const char*, krb5_keytab);
krb5_error_code (*get_name)(krb5_context, krb5_keytab, char*, size_t);
krb5_error_code (*close)(krb5_context, krb5_keytab);
+ krb5_error_code (*destroy)(krb5_context, krb5_keytab);
krb5_error_code (*get)(krb5_context, krb5_keytab, krb5_const_principal,
krb5_kvno, krb5_enctype, krb5_keytab_entry*);
krb5_error_code (*start_seq_get)(krb5_context, krb5_keytab, krb5_kt_cursor*);
#define KRB5_TGS_NAME_SIZE (6)
#define KRB5_TGS_NAME ("krbtgt")
-
+#define KRB5_WELLKNOWN_NAME ("WELLKNOWN")
+#define KRB5_ANON_NAME ("ANONYMOUS")
#define KRB5_DIGEST_NAME ("digest")
typedef enum {
struct _krb5_get_init_creds_opt_private;
-typedef struct _krb5_get_init_creds_opt {
+struct _krb5_get_init_creds_opt {
krb5_flags flags;
krb5_deltat tkt_life;
krb5_deltat renew_life;
int preauth_list_length;
krb5_data *salt;
struct _krb5_get_init_creds_opt_private *opt_private;
-} krb5_get_init_creds_opt;
+};
+
+typedef struct _krb5_get_init_creds_opt krb5_get_init_creds_opt;
#define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE 0x0001
#define KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE 0x0002
const krb5_data *,
krb5_data *);
-/* flags for krb5_parse_name_flags */
+/** flags for krb5_parse_name_flags */
enum {
- KRB5_PRINCIPAL_PARSE_NO_REALM = 1,
- KRB5_PRINCIPAL_PARSE_MUST_REALM = 2,
- KRB5_PRINCIPAL_PARSE_ENTERPRISE = 4
+ KRB5_PRINCIPAL_PARSE_NO_REALM = 1, /**< Require that there are no realm */
+ KRB5_PRINCIPAL_PARSE_REQUIRE_REALM = 2, /**< Require a realm present */
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE = 4 /**< Parse as a NT-ENTERPRISE name */
};
-/* flags for krb5_unparse_name_flags */
+/** flags for krb5_unparse_name_flags */
enum {
- KRB5_PRINCIPAL_UNPARSE_SHORT = 1,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2,
- KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4
+ KRB5_PRINCIPAL_UNPARSE_SHORT = 1, /**< No realm if it is the default realm */
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2, /**< No realm */
+ KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4 /**< No quoting */
};
typedef struct krb5_sendto_ctx_data *krb5_sendto_ctx;
} krb5_crypto_iov;
+/* Glue for MIT */
+
+typedef struct {
+ int32_t lr_type;
+ krb5_timestamp value;
+} krb5_last_req_entry;
+
+typedef krb5_error_code
+(*krb5_gic_process_last_req)(krb5_context, krb5_last_req_entry **, void *);
+
+/*
+ *
+ */
+
#include <krb5-protos.h>
/* variables */
#include <krb5-types.h>
+ #ifdef __APPLE__
+#pragma pack(push,2)
+#endif
+
enum {
cc_credentials_v5 = 2
};
typedef struct cc_credentials_t *cc_credentials_t;
typedef struct cc_credentials_iterator_t *cc_credentials_iterator_t;
typedef struct cc_string_t *cc_string_t;
-typedef time_t cc_time_t;
+typedef cc_uint32 cc_time_t;
typedef struct cc_data {
cc_uint32 type;
typedef cc_int32
(*cc_initialize_func)(cc_context_t*, cc_int32, cc_int32 *, char const **);
+#ifdef __APPLE__
+#pragma pack(pop)
+#endif
+
+
#endif /* KRB5_CCAPI_H */
#ifndef __KRB5_LOCL_H__
#define __KRB5_LOCL_H__
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <errno.h>
#include <ctype.h>
krb5_get_init_creds_tristate req_pac;
/* PKINIT */
krb5_pk_init_ctx pk_init_ctx;
- KRB_ERROR *error;
krb5_get_init_creds_tristate addressless;
int flags;
#define KRB5_INIT_CREDS_CANONICALIZE 1
#define KRB5_INIT_CREDS_NO_C_CANON_CHECK 2
+ struct {
+ krb5_gic_process_last_req func;
+ void *ctx;
+ } lr;
};
typedef struct krb5_context_data {
int flags;
#define KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME 1
#define KRB5_CTX_F_CHECK_PAC 2
+#define KRB5_CTX_F_HOMEDIR_ACCESS 4
struct send_to_kdc *send_to_kdc;
} krb5_context_data;
hx509_context hx509ctx;
hx509_verify_ctx verify_ctx;
hx509_certs certs;
+ hx509_cert cert;
hx509_certs anchors;
hx509_certs certpool;
hx509_revoke_ctx revokectx;
#include <resolve.h>
#include "locate_plugin.h"
-RCSID("$Id$");
-
static int
string_to_proto(const char *string)
{
const char *proto, const char *service, int port)
{
char domain[1024];
- struct dns_reply *r;
- struct resource_record *rr;
+ struct rk_dns_reply *r;
+ struct rk_resource_record *rr;
int num_srv;
int proto_num;
int def_port;
snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
- r = dns_lookup(domain, dns_type);
+ r = rk_dns_lookup(domain, dns_type);
if(r == NULL)
return KRB5_KDC_UNREACH;
for(num_srv = 0, rr = r->head; rr; rr = rr->next)
- if(rr->type == T_SRV)
+ if(rr->type == rk_ns_t_srv)
num_srv++;
*res = malloc(num_srv * sizeof(**res));
if(*res == NULL) {
- dns_free_data(r);
+ rk_dns_free_data(r);
krb5_set_error_message(context, ENOMEM,
N_("malloc: out of memory", ""));
return ENOMEM;
}
- dns_srv_order(r);
+ rk_dns_srv_order(r);
for(num_srv = 0, rr = r->head; rr; rr = rr->next)
- if(rr->type == T_SRV) {
+ if(rr->type == rk_ns_t_srv) {
krb5_krbhst_info *hi;
size_t len = strlen(rr->u.srv->target);
hi = calloc(1, sizeof(*hi) + len);
if(hi == NULL) {
- dns_free_data(r);
+ rk_dns_free_data(r);
while(--num_srv >= 0)
free((*res)[num_srv]);
free(*res);
*count = num_srv;
- dns_free_data(r);
+ rk_dns_free_data(r);
return 0;
}
return ENOMEM;
}
}
- (*hostlist)[nhost++] = NULL;
+ (*hostlist)[nhost] = NULL;
krb5_krbhst_free(context, handle);
return 0;
}
#include "krb5_locl.h"
RCSID("$Id$");
+#undef KRB5_DEPRECATED
+#define KRB5_DEPRECATED
+
#ifndef HEIMDAL_SMALLER
/*
krb5_enctype e1,
krb5_enctype e2,
krb5_boolean *similar)
+ KRB5_DEPRECATED
{
- *similar = krb5_enctypes_compatible_keys(context, e1, e2);
+ *similar = (e1 == e2);
return 0;
}
unsigned char *tmp = malloc(maxlen);
unsigned char *buf = malloc(len);
- if (tmp == NULL || buf == NULL)
- return ENOMEM;
+ if (tmp == NULL || buf == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
memcpy(buf, str, len);
memset(key, 0, size);
}
} while(l != 0);
out:
- memset(buf, 0, len);
- free(buf);
- memset(tmp, 0, maxlen);
- free(tmp);
+ if (buf) {
+ memset(buf, 0, len);
+ free(buf);
+ }
+ if (tmp) {
+ memset(tmp, 0, maxlen);
+ free(tmp);
+ }
return ret;
}
ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len);
free(ucs2);
if (ret) {
+ free(s);
krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
return ret;
}
struct krb5_pk_init_ctx_data {
struct krb5_pk_identity *id;
- DH *dh;
+ enum { USE_RSA, USE_DH, USE_ECDH } keyex;
+ union {
+ DH *dh;
+#ifdef HAVE_OPENSSL
+ EC_KEY *eckey;
+#endif
+ } u;
krb5_data *clientDHNonce;
struct krb5_dh_moduli **m;
hx509_peer_info peer;
return bn;
}
+static krb5_error_code
+select_dh_group(krb5_context context, DH *dh, unsigned long bits,
+ struct krb5_dh_moduli **moduli)
+{
+ const struct krb5_dh_moduli *m;
+
+ if (bits == 0) {
+ m = moduli[1]; /* XXX */
+ if (m == NULL)
+ m = moduli[0]; /* XXX */
+ } else {
+ int i;
+ for (i = 0; moduli[i] != NULL; i++) {
+ if (bits < moduli[i]->bits)
+ break;
+ }
+ if (moduli[i] == NULL) {
+ krb5_set_error_message(context, EINVAL,
+ N_("Did not find a DH group parameter "
+ "matching requirement of %lu bits", ""),
+ bits);
+ return EINVAL;
+ }
+ m = moduli[i];
+ }
+
+ dh->p = integer_to_BN(context, "p", &m->p);
+ if (dh->p == NULL)
+ return ENOMEM;
+ dh->g = integer_to_BN(context, "g", &m->g);
+ if (dh->g == NULL)
+ return ENOMEM;
+ dh->q = integer_to_BN(context, "q", &m->q);
+ if (dh->q == NULL)
+ return ENOMEM;
+
+ return 0;
+}
+
struct certfind {
const char *type;
const heim_oid *oid;
struct certfind cf[3] = {
{ "PKINIT EKU" },
{ "MS EKU" },
- { "no" }
+ { "any (or no)" }
};
int i, ret;
if (ret == 0)
break;
pk_copy_error(context, id->hx509ctx, ret,
- "Failed cert for finding %s OID", cf[i].type);
+ "Failed finding certificate with %s OID", cf[i].type);
}
return ret;
}
hx509_peer_info peer,
krb5_data *sd_data)
{
- hx509_cert cert = NULL;
- hx509_query *q = NULL;
- int ret;
+ int ret, flags = 0;
- ret = hx509_query_alloc(id->hx509ctx, &q);
- if (ret) {
- pk_copy_error(context, id->hx509ctx, ret,
- "Allocate query to find signing certificate");
- return ret;
- }
-
- hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
- hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
-
- ret = find_cert(context, id, q, &cert);
- hx509_query_free(id->hx509ctx, q);
- if (ret)
- return ret;
+ if (id->cert == NULL)
+ flags |= HX509_CMS_SIGNATURE_NO_SIGNER;
ret = hx509_cms_create_signed_1(id->hx509ctx,
- 0,
+ flags,
eContentType,
eContent->data,
eContent->length,
NULL,
- cert,
+ id->cert,
peer,
NULL,
id->certs,
sd_data);
- hx509_cert_free(cert);
if (ret) {
pk_copy_error(context, id->hx509ctx, ret,
"Create CMS signedData");
build_auth_pack(krb5_context context,
unsigned nonce,
krb5_pk_init_ctx ctx,
- DH *dh,
const KDC_REQ_BODY *body,
AuthPack *a)
{
if (ret)
return ret;
- if (dh) {
- DomainParameters dp;
- heim_integer dh_pub_key;
+ if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) {
+ const char *moduli_file;
+ unsigned long dh_min_bits;
krb5_data dhbuf;
size_t size;
+ krb5_data_zero(&dhbuf);
+
+
+
+ moduli_file = krb5_config_get_string(context, NULL,
+ "libdefaults",
+ "moduli",
+ NULL);
+
+ dh_min_bits =
+ krb5_config_get_int_default(context, NULL, 0,
+ "libdefaults",
+ "pkinit_dh_min_bits",
+ NULL);
+
+ ret = _krb5_parse_moduli(context, moduli_file, &ctx->m);
+ if (ret)
+ return ret;
+
+ ctx->u.dh = DH_new();
+ if (ctx->u.dh == NULL) {
+ krb5_set_error_message(context, ENOMEM,
+ N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
+
+ ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m);
+ if (ret)
+ return ret;
+
+ if (DH_generate_key(ctx->u.dh) != 1) {
+ krb5_set_error_message(context, ENOMEM,
+ N_("pkinit: failed to generate DH key", ""));
+ return ENOMEM;
+ }
+
+
if (1 /* support_cached_dh */) {
ALLOC(a->clientDHNonce, 1);
if (a->clientDHNonce == NULL) {
krb5_clear_error_message(context);
return ret;
}
- memset(a->clientDHNonce->data, 0, a->clientDHNonce->length);
+ RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length);
ret = krb5_copy_data(context, a->clientDHNonce,
&ctx->clientDHNonce);
if (ret)
ALLOC(a->clientPublicValue, 1);
if (a->clientPublicValue == NULL)
return ENOMEM;
- ret = der_copy_oid(oid_id_dhpublicnumber(),
- &a->clientPublicValue->algorithm.algorithm);
- if (ret)
- return ret;
-
- memset(&dp, 0, sizeof(dp));
- ret = BN_to_integer(context, dh->p, &dp.p);
- if (ret) {
- free_DomainParameters(&dp);
- return ret;
- }
- ret = BN_to_integer(context, dh->g, &dp.g);
- if (ret) {
- free_DomainParameters(&dp);
- return ret;
- }
- ret = BN_to_integer(context, dh->q, &dp.q);
- if (ret) {
- free_DomainParameters(&dp);
- return ret;
- }
- dp.j = NULL;
- dp.validationParms = NULL;
+ if (ctx->keyex == USE_DH) {
+ DH *dh = ctx->u.dh;
+ DomainParameters dp;
+ heim_integer dh_pub_key;
- a->clientPublicValue->algorithm.parameters =
- malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
- if (a->clientPublicValue->algorithm.parameters == NULL) {
+ ret = der_copy_oid(oid_id_dhpublicnumber(),
+ &a->clientPublicValue->algorithm.algorithm);
+ if (ret)
+ return ret;
+
+ memset(&dp, 0, sizeof(dp));
+
+ ret = BN_to_integer(context, dh->p, &dp.p);
+ if (ret) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+ ret = BN_to_integer(context, dh->g, &dp.g);
+ if (ret) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+ ret = BN_to_integer(context, dh->q, &dp.q);
+ if (ret) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+ dp.j = NULL;
+ dp.validationParms = NULL;
+
+ a->clientPublicValue->algorithm.parameters =
+ malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
+ if (a->clientPublicValue->algorithm.parameters == NULL) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+
+ ASN1_MALLOC_ENCODE(DomainParameters,
+ a->clientPublicValue->algorithm.parameters->data,
+ a->clientPublicValue->algorithm.parameters->length,
+ &dp, &size, ret);
free_DomainParameters(&dp);
- return ret;
- }
+ if (ret)
+ return ret;
+ if (size != a->clientPublicValue->algorithm.parameters->length)
+ krb5_abortx(context, "Internal ASN1 encoder error");
+
+ ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
+ &dh_pub_key, &size, ret);
+ der_free_heim_integer(&dh_pub_key);
+ if (ret)
+ return ret;
+ if (size != dhbuf.length)
+ krb5_abortx(context, "asn1 internal error");
+ } else if (ctx->keyex == USE_ECDH) {
+#ifdef HAVE_OPENSSL
+ ECParameters ecp;
+ unsigned char *p;
+ int len;
+
+ /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
+
+ ecp.element = choice_ECParameters_namedCurve;
+ ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
+ &ecp.u.namedCurve);
+ if (ret)
+ return ret;
- ASN1_MALLOC_ENCODE(DomainParameters,
- a->clientPublicValue->algorithm.parameters->data,
- a->clientPublicValue->algorithm.parameters->length,
- &dp, &size, ret);
- free_DomainParameters(&dp);
- if (ret)
- return ret;
- if (size != a->clientPublicValue->algorithm.parameters->length)
- krb5_abortx(context, "Internal ASN1 encoder error");
+ ALLOC(a->clientPublicValue->algorithm.parameters, 1);
+ if (a->clientPublicValue->algorithm.parameters == NULL) {
+ free_ECParameters(&ecp);
+ return ENOMEM;
+ }
+ ASN1_MALLOC_ENCODE(ECParameters, p, len, &ecp, &size, ret);
+ free_ECParameters(&ecp);
+ if (ret)
+ return ret;
+ if (size != len)
+ krb5_abortx(context, "asn1 internal error");
+
+ a->clientPublicValue->algorithm.parameters->data = p;
+ a->clientPublicValue->algorithm.parameters->length = size;
- ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
- if (ret)
- return ret;
+ /* copy in public key */
- ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
- &dh_pub_key, &size, ret);
- der_free_heim_integer(&dh_pub_key);
- if (ret)
- return ret;
- if (size != dhbuf.length)
- krb5_abortx(context, "asn1 internal error");
+ ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
+ &a->clientPublicValue->algorithm.algorithm);
+ if (ret)
+ return ret;
+
+ ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ if (ctx->u.eckey == NULL)
+ return ENOMEM;
+ ret = EC_KEY_generate_key(ctx->u.eckey);
+ if (ret != 1)
+ return EINVAL;
+
+ /* encode onto dhkey */
+
+ len = i2o_ECPublicKey(ctx->u.eckey, NULL);
+ if (len <= 0)
+ abort();
+
+ dhbuf.data = malloc(len);
+ if (dhbuf.data == NULL)
+ abort();
+ dhbuf.length = len;
+ p = dhbuf.data;
+
+ len = i2o_ECPublicKey(ctx->u.eckey, &p);
+ if (len <= 0)
+ abort();
+
+ /* XXX verify that this is right with RFC3279 */
+#else
+ return EINVAL;
+#endif
+ } else
+ krb5_abortx(context, "internal error");
a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
}
-
+
{
a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
if (a->supportedCMSTypes == NULL)
memset(&ap, 0, sizeof(ap));
- ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap);
+ ret = build_auth_pack(context, nonce, ctx, req_body, &ap);
if (ret) {
free_AuthPack(&ap);
goto out;
if (ret)
free(buf.data);
- if (ret == 0 && ctx->type == PKINIT_WIN2K)
- krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
+ if (ret == 0)
+ krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
out:
free_ContentInfo(&content_info);
ret = hx509_cms_verify_signed(id->hx509ctx,
id->verify_ctx,
+ HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH|HX509_CMS_VS_NO_KU_CHECK,
data,
length,
NULL,
struct krb5_pk_cert *host = NULL;
krb5_data content;
heim_oid contentType = { 0, NULL };
+ int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT;
if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) {
krb5_set_error_message(context, EINVAL,
return EINVAL;
}
+ if (ctx->type == PKINIT_WIN2K)
+ flags |= HX509_CMS_UE_ALLOW_WEAK;
+
ret = hx509_cms_unenvelope(ctx->id->hx509ctx,
ctx->id->certs,
- HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT,
+ flags,
indata->data,
indata->length,
NULL,
heim_octet_string out;
ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL);
+ if (ret)
+ goto out;
if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) {
ret = EINVAL; /* XXX */
krb5_set_error_message(context, ret,
PA_DATA *pa,
krb5_keyblock **key)
{
- unsigned char *p, *dh_gen_key = NULL;
+ const unsigned char *p;
+ unsigned char *dh_gen_key = NULL;
struct krb5_pk_cert *host = NULL;
BIGNUM *kdc_dh_pubkey = NULL;
KDCDHKeyInfo kdc_dh_info;
heim_oid contentType = { 0, NULL };
krb5_data content;
krb5_error_code ret;
- int dh_gen_keylen;
+ int dh_gen_keylen = 0;
size_t size;
krb5_data_zero(&content);
p = kdc_dh_info.subjectPublicKey.data;
size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
- {
+ if (ctx->keyex == USE_DH) {
DHPublicKey k;
ret = decode_DHPublicKey(p, size, &k, NULL);
if (ret) {
ret = ENOMEM;
goto out;
}
- }
- dh_gen_keylen = DH_size(ctx->dh);
- size = BN_num_bytes(ctx->dh->p);
- if (size < dh_gen_keylen)
- size = dh_gen_keylen;
- dh_gen_key = malloc(size);
- if (dh_gen_key == NULL) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- goto out;
- }
- memset(dh_gen_key, 0, size - dh_gen_keylen);
+ dh_gen_keylen = DH_size(ctx->u.dh);
+ size = BN_num_bytes(ctx->u.dh->p);
+ if (size < dh_gen_keylen)
+ size = dh_gen_keylen;
- dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
- kdc_dh_pubkey, ctx->dh);
- if (dh_gen_keylen == -1) {
- ret = KRB5KRB_ERR_GENERIC;
- krb5_set_error_message(context, ret,
- N_("PKINIT: Can't compute Diffie-Hellman key", ""));
- goto out;
- }
+ dh_gen_key = malloc(size);
+ if (dh_gen_key == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
+ }
+ memset(dh_gen_key, 0, size - dh_gen_keylen);
+
+ dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
+ kdc_dh_pubkey, ctx->u.dh);
+ if (dh_gen_keylen == -1) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ N_("PKINIT: Can't compute Diffie-Hellman key", ""));
+ goto out;
+ }
+ } else {
+#ifdef HAVE_OPENSSL
+ const EC_GROUP *group;
+ EC_KEY *public = NULL;
+
+ group = EC_KEY_get0_group(ctx->u.eckey);
+
+ public = EC_KEY_new();
+ if (public == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ if (EC_KEY_set_group(public, group) != 1) {
+ EC_KEY_free(public);
+ ret = ENOMEM;
+ goto out;
+ }
+ if (o2i_ECPublicKey(&public, &p, size) == NULL) {
+ EC_KEY_free(public);
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ N_("PKINIT: Can't parse ECDH public key", ""));
+ goto out;
+ }
+
+ size = (EC_GROUP_get_degree(group) + 7) / 8;
+ dh_gen_key = malloc(size);
+ if (dh_gen_key == NULL) {
+ EC_KEY_free(public);
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret,
+ N_("malloc: out of memory", ""));
+ goto out;
+ }
+ dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
+ EC_KEY_get0_public_key(public), ctx->u.eckey, NULL);
+ EC_KEY_free(public);
+ if (dh_gen_keylen == -1) {
+ ret = KRB5KRB_ERR_GENERIC;
+ krb5_set_error_message(context, ret,
+ N_("PKINIT: Can't compute ECDH public key", ""));
+ goto out;
+ }
+#else
+ ret = EINVAL;
+#endif
+ }
+
*key = malloc (sizeof (**key));
if (*key == NULL) {
ret = ENOMEM;
if (kdc_dh_pubkey)
BN_free(kdc_dh_pubkey);
if (dh_gen_key) {
- memset(dh_gen_key, 0, DH_size(ctx->dh));
+ memset(dh_gen_key, 0, dh_gen_keylen);
free(dh_gen_key);
}
if (host)
case choice_PA_PK_AS_REP_encKeyPack:
os = rep.u.encKeyPack;
break;
- default:
+ default: {
+ PA_PK_AS_REP_BTMM btmm;
free_PA_PK_AS_REP(&rep);
- krb5_set_error_message(context, EINVAL,
- N_("PKINIT: -27 reply "
- "invalid content type", ""));
- return EINVAL;
+ memset(&rep, 0, sizeof(rep));
+
+ ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data,
+ pa->padata_value.length,
+ &btmm,
+ &size);
+ if (ret) {
+ krb5_set_error_message(context, EINVAL,
+ N_("PKINIT: -27 reply "
+ "invalid content type", ""));
+ return EINVAL;
+ }
+
+ if (btmm.dhSignedData || btmm.encKeyPack == NULL) {
+ free_PA_PK_AS_REP_BTMM(&btmm);
+ ret = EINVAL;
+ krb5_set_error_message(context, ret,
+ N_("DH mode not supported for BTMM mode", ""));
+ return ret;
+ }
+
+ /*
+ * Transform to IETF style PK-INIT reply so that free works below
+ */
+
+ rep.element = choice_PA_PK_AS_REP_encKeyPack;
+ rep.u.encKeyPack.data = btmm.encKeyPack->data;
+ rep.u.encKeyPack.length = btmm.encKeyPack->length;
+ btmm.encKeyPack->data = NULL;
+ btmm.encKeyPack->length = 0;
+ free_PA_PK_AS_REP_BTMM(&btmm);
+ os = rep.u.encKeyPack;
+ }
}
ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
krb5_error_code KRB5_LIB_FUNCTION
_krb5_pk_load_id(krb5_context context,
struct krb5_pk_identity **ret_id,
+ int flags,
const char *user_id,
const char *anchor_id,
char * const *chain_list,
return HEIM_PKINIT_NO_VALID_CA;
}
- if (user_id == NULL) {
+ if (user_id == NULL && (flags & 4) == 0) {
krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
N_("PKINIT: No user certificate given", ""));
return HEIM_PKINIT_NO_PRIVATE_KEY;
goto out;
ret = hx509_lock_init(id->hx509ctx, &lock);
+ if (ret) {
+ pk_copy_error(context, id->hx509ctx, ret, "Failed init lock");
+ goto out;
+ }
+
if (password && password[0])
hx509_lock_add_password(lock, password);
goto out;
}
- ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
- if (ret) {
- pk_copy_error(context, id->hx509ctx, ret,
- "Failed to init cert certs");
- goto out;
+ if (user_id) {
+ ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
+ if (ret) {
+ pk_copy_error(context, id->hx509ctx, ret,
+ "Failed to init cert certs");
+ goto out;
+ }
+ } else {
+ id->certs = NULL;
}
ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
} else
*ret_id = id;
- hx509_lock_free(lock);
+ if (lock)
+ hx509_lock_free(lock);
return ret;
}
-static krb5_error_code
-select_dh_group(krb5_context context, DH *dh, unsigned long bits,
- struct krb5_dh_moduli **moduli)
-{
- const struct krb5_dh_moduli *m;
-
- if (bits == 0) {
- m = moduli[1]; /* XXX */
- if (m == NULL)
- m = moduli[0]; /* XXX */
- } else {
- int i;
- for (i = 0; moduli[i] != NULL; i++) {
- if (bits < moduli[i]->bits)
- break;
- }
- if (moduli[i] == NULL) {
- krb5_set_error_message(context, EINVAL,
- N_("Did not find a DH group parameter "
- "matching requirement of %lu bits", ""),
- bits);
- return EINVAL;
- }
- m = moduli[i];
- }
-
- dh->p = integer_to_BN(context, "p", &m->p);
- if (dh->p == NULL)
- return ENOMEM;
- dh->g = integer_to_BN(context, "g", &m->g);
- if (dh->g == NULL)
- return ENOMEM;
- dh->q = integer_to_BN(context, "q", &m->q);
- if (dh->q == NULL)
- return ENOMEM;
-
- return 0;
-}
-
/*
*
*/
while (isspace((unsigned char)*p))
p++;
- if (*p == '#')
+ if (*p == '#') {
+ free(m1);
return 0;
+ }
ret = EINVAL;
p1 = strsep(&p, " \t");
goto out;
}
m1->name = strdup(p1);
- if (p1 == NULL) {
+ if (m1->name == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
goto out;
if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
return;
ctx = opt->opt_private->pk_init_ctx;
- if (ctx->dh)
- DH_free(ctx->dh);
- ctx->dh = NULL;
+ switch (ctx->keyex) {
+ case USE_DH:
+ DH_free(ctx->u.dh);
+ break;
+ case USE_RSA:
+ break;
+ case USE_ECDH:
+#ifdef HAVE_OPENSSL
+ EC_KEY_free(ctx->u.eckey);
+#endif
+ break;
+ }
if (ctx->id) {
hx509_verify_destroy_ctx(ctx->id->verify_ctx);
hx509_certs_free(&ctx->id->certs);
+ hx509_cert_free(ctx->id->cert);
hx509_certs_free(&ctx->id->anchors);
hx509_certs_free(&ctx->id->certpool);
hx509_context_free(&ctx->id->hx509ctx);
N_("malloc: out of memory", ""));
return ENOMEM;
}
- opt->opt_private->pk_init_ctx->dh = NULL;
- opt->opt_private->pk_init_ctx->id = NULL;
- opt->opt_private->pk_init_ctx->clientDHNonce = NULL;
opt->opt_private->pk_init_ctx->require_binding = 0;
opt->opt_private->pk_init_ctx->require_eku = 1;
opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
ret = _krb5_pk_load_id(context,
&opt->opt_private->pk_init_ctx->id,
+ flags,
user_id,
x509_anchors,
pool,
return ret;
}
- if ((flags & 2) == 0) {
- const char *moduli_file;
- unsigned long dh_min_bits;
-
- moduli_file = krb5_config_get_string(context, NULL,
- "libdefaults",
- "moduli",
- NULL);
+ if (opt->opt_private->pk_init_ctx->id->certs) {
+ hx509_query *q = NULL;
+ hx509_cert cert = NULL;
+ hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx;
- dh_min_bits =
- krb5_config_get_int_default(context, NULL, 0,
- "libdefaults",
- "pkinit_dh_min_bits",
- NULL);
-
- ret = _krb5_parse_moduli(context, moduli_file,
- &opt->opt_private->pk_init_ctx->m);
+ ret = hx509_query_alloc(hx509ctx, &q);
if (ret) {
- _krb5_get_init_creds_opt_free_pkinit(opt);
+ pk_copy_error(context, hx509ctx, ret,
+ "Allocate query to find signing certificate");
return ret;
}
- opt->opt_private->pk_init_ctx->dh = DH_new();
- if (opt->opt_private->pk_init_ctx->dh == NULL) {
- _krb5_get_init_creds_opt_free_pkinit(opt);
- krb5_set_error_message(context, ENOMEM,
- N_("malloc: out of memory", ""));
- return ENOMEM;
- }
-
- ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh,
- dh_min_bits,
- opt->opt_private->pk_init_ctx->m);
- if (ret) {
- _krb5_get_init_creds_opt_free_pkinit(opt);
+ hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
+ hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+
+ ret = find_cert(context, opt->opt_private->pk_init_ctx->id, q, &cert);
+ hx509_query_free(hx509ctx, q);
+ if (ret)
return ret;
- }
- if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) {
- _krb5_get_init_creds_opt_free_pkinit(opt);
- krb5_set_error_message(context, ENOMEM,
- N_("pkinit: failed to generate DH key", ""));
- return ENOMEM;
+ opt->opt_private->pk_init_ctx->id->cert = cert;
+ } else
+ opt->opt_private->pk_init_ctx->id->cert = NULL;
+
+ if ((flags & 2) == 0) {
+ hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx;
+ hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert;
+
+ opt->opt_private->pk_init_ctx->keyex = USE_DH;
+
+ /*
+ * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
+ */
+ if (cert) {
+ AlgorithmIdentifier alg;
+
+ ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg);
+ if (ret == 0) {
+ if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0)
+ opt->opt_private->pk_init_ctx->keyex = USE_ECDH;
+ free_AlgorithmIdentifier(&alg);
+ }
}
+
+ } else {
+ opt->opt_private->pk_init_ctx->keyex = USE_RSA;
+
+ if (opt->opt_private->pk_init_ctx->id->certs == NULL) {
+ krb5_set_error_message(context, EINVAL,
+ N_("No anonymous pkinit support in RSA mode", ""));
+ return EINVAL;
+ }
}
return 0;
return EINVAL;
#endif
}
+
+#ifdef PKINIT
+
+static int
+match_ms_san(hx509_context context, hx509_cert cert, void *ctx)
+{
+ hx509_octet_string_list list;
+ char **result = ctx;
+ int ret;
+
+ if (*result)
+ return 0;
+
+ ret = hx509_cert_find_subjectAltName_otherName(context,
+ cert,
+ oid_id_pkinit_ms_san(),
+ &list);
+ if (ret)
+ return 0;
+
+ if (list.len > 0 && list.val[0].length > 0) {
+
+ ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length,
+ result, NULL);
+ if (ret)
+ *result = NULL;
+ }
+ hx509_free_octet_string_list(&list);
+
+ if (*result == NULL)
+ return 0;
+ return 1;
+}
+
+#endif
+
+/*
+ * Private since it need to be redesigned using krb5_get_init_creds()
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_enterprise_cert(krb5_context context,
+ const char *user_id,
+ krb5_const_realm realm,
+ krb5_principal *principal)
+{
+#ifdef PKINIT
+ krb5_error_code ret;
+ char *enterprise_name = NULL;
+ hx509_context hx509ctx;
+ hx509_certs certs, result;
+ hx509_query *q;
+
+ *principal = NULL;
+
+ if (user_id == NULL)
+ return ENOENT;
+
+ ret = hx509_context_init(&hx509ctx);
+ if (ret)
+ return ret;
+
+ ret = hx509_certs_init(hx509ctx, user_id, 0, NULL, &certs);
+ if (ret) {
+ pk_copy_error(context, hx509ctx, ret,
+ "Failed to init cert certs");
+ return ret;
+ }
+
+ ret = hx509_query_alloc(hx509ctx, &q);
+ if (ret) {
+ hx509_certs_free(&certs);
+ return ret;
+ }
+
+ hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
+ hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+ hx509_query_match_eku(q, oid_id_pkinit_ms_eku());
+ hx509_query_match_cmp_func(q, match_ms_san, &enterprise_name);
+
+ ret = hx509_certs_filter(hx509ctx, certs, q, &result);
+ hx509_query_free(hx509ctx, q);
+ hx509_certs_free(&certs);
+
+ if (ret)
+ return ret;
+ if (enterprise_name == NULL)
+ return ENOENT; /* XXX */
+
+ ret = krb5_make_principal(context, principal, realm,
+ enterprise_name, NULL);
+ free(enterprise_name);
+ hx509_context_free(&hx509ctx);
+ if (ret)
+ return ret;
+
+
+ krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL);
+
+ return ret;
+#else
+ krb5_set_error_message(context, EINVAL,
+ N_("no support for PKINIT compiled in", ""));
+ return EINVAL;
+#endif
+}
*/
/**
- * @page page_principal The principal handing functions.
+ * @page krb5_principal_intro The principal handing functions.
*
* A Kerberos principal is a email address looking string that
* contains to parts separeted by a @. The later part is the kerbero
* @ingroup krb5_principal
*/
-
-
void KRB5_LIB_FUNCTION
krb5_free_principal(krb5_context context,
krb5_principal p)
}
}
+/**
+ * Set the type of the principal
+ *
+ * @param context A Kerberos context.
+ * @param principal principal to set the type for
+ * @param type the new type
+ *
+ * @return An krb5 error code, see krb5_get_error_message().
+ *
+ * @ingroup krb5_principal
+ */
+
void KRB5_LIB_FUNCTION
krb5_principal_set_type(krb5_context context,
krb5_principal principal,
*
* @param context Kerberos 5 context
* @param principal principal to query
+ *
* @return number of components in string
- * @ingroup krb5
+ *
+ * @ingroup krb5_principal
*/
unsigned int KRB5_LIB_FUNCTION
*principal = NULL;
-#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM)
+#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM)
if ((flags & RFLAGS) == RFLAGS) {
krb5_set_error_message(context, KRB5_ERR_NO_SERVICE,
memcpy(realm, start, q - start);
realm[q - start] = 0;
}else{
- if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) {
+ if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) {
ret = KRB5_PARSE_MALFORMED;
krb5_set_error_message(context, ret,
N_("realm NOT found in principal "
return TRUE;
}
+#ifdef KRB4
static struct v4_name_convert {
const char *from;
if(p){
instance = p;
ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
+ if (ret)
+ return ret;
if(func == NULL || (*func)(context, funcctx, pr)){
*princ = pr;
return 0;
krb5_boolean passed = FALSE;
char *inst = NULL;
#ifdef USE_RESOLVER
- struct dns_reply *r;
+ struct rk_dns_reply *r;
- r = dns_lookup(instance, "aaaa");
+ r = rk_dns_lookup(instance, "aaaa");
if (r) {
- if (r->head && r->head->type == T_AAAA) {
+ if (r->head && r->head->type == rk_ns_t_aaaa) {
inst = strdup(r->head->domain);
passed = TRUE;
}
- dns_free_data(r);
+ rk_dns_free_data(r);
} else {
- r = dns_lookup(instance, "a");
+ r = rk_dns_lookup(instance, "a");
if (r) {
- if(r->head && r->head->type == T_A) {
+ if(r->head && r->head->type == rk_ns_t_a) {
inst = strdup(r->head->domain);
passed = TRUE;
}
- dns_free_data(r);
+ rk_dns_free_data(r);
}
}
#else
snprintf(host, sizeof(host), "%s.%s", instance, realm);
strlwr(host);
ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
+ if (ret)
+ return ret;
if((*func)(context, funcctx, pr)){
*princ = pr;
return 0;
for(d = domains; d && *d; d++){
snprintf(host, sizeof(host), "%s.%s", instance, *d);
ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
+ if (ret) {
+ krb5_config_free_strings(domains);
+ return ret;
+ }
if(func == NULL || (*func)(context, funcctx, pr)){
*princ = pr;
krb5_config_free_strings(domains);
snprintf(host, sizeof(host), "%s.%s", instance, p);
local_host:
ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
+ if (ret)
+ return ret;
if(func == NULL || (*func)(context, funcctx, pr)){
*princ = pr;
return 0;
name = p;
ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
+ if (ret)
+ return ret;
if(func == NULL || (*func)(context, funcctx, pr)){
*princ = pr;
return 0;
return HEIM_ERR_V4_PRINC_NO_CONV;
}
-static krb5_boolean
-convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal)
-{
- krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx;
- return (*func)(conxtext, principal);
-}
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_425_conv_principal_ext(krb5_context context,
- const char *name,
- const char *instance,
- const char *realm,
- krb5_boolean (*func)(krb5_context, krb5_principal),
- krb5_boolean resolve,
- krb5_principal *principal)
-{
- return krb5_425_conv_principal_ext2(context,
- name,
- instance,
- realm,
- func ? convert_func : NULL,
- func,
- resolve,
- principal);
-}
-
-
-
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_425_conv_principal(krb5_context context,
- const char *name,
- const char *instance,
- const char *realm,
- krb5_principal *princ)
-{
- krb5_boolean resolve = krb5_config_get_bool(context,
- NULL,
- "libdefaults",
- "v4_instance_resolve",
- NULL);
-
- return krb5_425_conv_principal_ext(context, name, instance, realm,
- NULL, resolve, princ);
-}
+#endif /* KRB4 */
+#ifndef HEIMDAL_SMALLER
static int
check_list(const krb5_config_binding *l, const char *name, const char **out)
return KRB5_NT_UNKNOWN;
/* didn't find it in config file, try built-in list */
+#ifdef KRB4
{
struct v4_name_convert *q;
for(q = default_v4_name_convert; q->from; q++) {
}
}
}
+#endif
return -1;
}
return 0;
}
+#endif /* !HEIMDAL_SMALLER */
+
/**
* Create a principal for the service running on hostname. If
* KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or
#include <getarg.h>
#include <err.h>
-RCSID("$Id$");
-
void KRB5_LIB_FUNCTION
krb5_std_usage(int code, struct getargs *args, int num_args)
{
goto out;
}
- ret = krb5_decode_EncKrbCredPart (context,
- enc_krb_cred_part_data.data,
- enc_krb_cred_part_data.length,
- &enc_krb_cred_part,
- &len);
+ ret = decode_EncKrbCredPart(enc_krb_cred_part_data.data,
+ enc_krb_cred_part_data.length,
+ &enc_krb_cred_part,
+ &len);
if (enc_krb_cred_part_data.data != cred.enc_part.cipher.data)
krb5_data_free(&enc_krb_cred_part_data);
- if (ret)
+ if (ret) {
+ krb5_set_error_message(context, ret,
+ N_("Failed to decode "
+ "encrypte credential part", ""));
goto out;
+ }
/* check sender address */
krb5_crypto crypto;
krb5_data_zero (&data);
- ret = 0;
ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len);
if (ret)
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
goto out;
}
- ret = krb5_decode_EncAPRepPart(context,
- data.data,
- data.length,
- *repl,
- &len);
- if (ret)
+ ret = decode_EncAPRepPart(data.data, data.length, *repl, &len);
+ if (ret) {
+ krb5_set_error_message(context, ret, N_("Failed to decode EncAPRepPart", ""));
return ret;
+ }
if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
if ((*repl)->ctime != auth_context->authenticator->ctime ||
if (ret)
return ret;
- ret = krb5_decode_EncTicketPart(context, plain.data, plain.length,
- decr_part, &len);
+ ret = decode_EncTicketPart(plain.data, plain.length, decr_part, &len);
+ if (ret)
+ krb5_set_error_message(context, ret,
+ N_("Failed to decode encrypted "
+ "ticket part", ""));
krb5_data_free (&plain);
return ret;
}
if (ret)
return ret;
- ret = krb5_decode_Authenticator(context, plain.data, plain.length,
- authenticator, &len);
+ ret = decode_Authenticator(plain.data, plain.length,
+ authenticator, &len);
krb5_data_free (&plain);
return ret;
}
krb5_keyblock *keyblock;
krb5_flags ap_req_options;
krb5_ticket *ticket;
+ krb5_principal server;
};
-/*
+/**
+ * Allocate a krb5_rd_req_in_ctx as an input parameter to
+ * krb5_rd_req_ctx(). The caller should free the context with
+ * krb5_rd_req_in_ctx_free() when done with the context.
+ *
+ * @param context Keberos 5 context.
+ * @param ctx in ctx to krb5_rd_req_ctx().
+ *
+ * @return Kerberos 5 error code, see krb5_get_error_message().
*
+ * @ingroup krb5_auth
*/
krb5_error_code KRB5_LIB_FUNCTION
return 0;
}
+/**
+ * Set the keytab that krb5_rd_req_ctx() will use.
+ *
+ * @param context Keberos 5 context.
+ * @param in in ctx to krb5_rd_req_ctx().
+ * @param keytab keytab that krb5_rd_req_ctx() will use, only copy the
+ * pointer, so the caller must free they keytab after
+ * krb5_rd_req_in_ctx_free() is called.
+ *
+ * @return Kerberos 5 error code, see krb5_get_error_message().
+ *
+ * @ingroup krb5_auth
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_rd_req_in_set_keytab(krb5_context context,
krb5_rd_req_in_ctx in,
krb5_keytab keytab)
{
- in->keytab = keytab; /* XXX should make copy */
+ in->keytab = keytab;
return 0;
}
*
* @return Kerberos 5 error code, see krb5_get_error_message().
*
- * @ingroup krb5
+ * @ingroup krb5_auth
*/
krb5_error_code KRB5_LIB_FUNCTION
return krb5_copy_keyblock(context, out->keyblock, keyblock);
}
+/**
+ * Get the principal that was used in the request from the
+ * client. Might not match whats in the ticket if krb5_rd_req_ctx()
+ * searched in the keytab for a matching key.
+ *
+ * @param context a Kerberos 5 context.
+ * @param out a krb5_rd_req_out_ctx from krb5_rd_req_ctx().
+ * @param principal return principal, free with krb5_free_principal().
+ *
+ * @ingroup krb5_auth
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_out_get_server(krb5_context context,
+ krb5_rd_req_out_ctx out,
+ krb5_principal *principal)
+{
+ return krb5_copy_principal(context, out->server, principal);
+}
+
void KRB5_LIB_FUNCTION
krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx)
{
free(ctx);
}
-krb5_error_code KRB5_LIB_FUNCTION
-_krb5_rd_req_out_ctx_alloc(krb5_context context, krb5_rd_req_out_ctx *ctx)
-{
- *ctx = calloc(1, sizeof(**ctx));
- if (*ctx == NULL) {
- krb5_set_error_message(context, ENOMEM,
- N_("malloc: out of memory", ""));
- return ENOMEM;
- }
- return 0;
-}
+/**
+ * Free the krb5_rd_req_out_ctx.
+ *
+ * @param context Keberos 5 context.
+ * @param ctx krb5_rd_req_out_ctx context to free.
+ *
+ * @ingroup krb5_auth
+ */
void KRB5_LIB_FUNCTION
krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx)
{
- krb5_free_keyblock(context, ctx->keyblock);
+ if (ctx->ticket)
+ krb5_free_ticket(context, ctx->ticket);
+ if (ctx->keyblock)
+ krb5_free_keyblock(context, ctx->keyblock);
+ if (ctx->server)
+ krb5_free_principal(context, ctx->server);
free(ctx);
}
static krb5_error_code
get_key_from_keytab(krb5_context context,
- krb5_auth_context *auth_context,
krb5_ap_req *ap_req,
krb5_const_principal server,
krb5_keytab keytab,
return ret;
}
-/*
+/**
+ * The core server function that verify application authentication
+ * requests from clients.
*
+ * @param context Keberos 5 context.
+ * @param auth_context the authentication context, can be NULL, then
+ * default values for the authentication context will used.
+ * @param inbuf the (AP-REQ) authentication buffer
+ *
+ * @param server the server with authenticate as, if NULL the function
+ * will try to find any avaiable credentintial in the keytab
+ * that will verify the reply. The function will prefer the
+ * server the server client specified in the AP-REQ, but if
+ * there is no mach, it will try all keytab entries for a
+ * match. This have serious performance issues for larger keytabs.
+ *
+ * @param inctx control the behavior of the function, if NULL, the
+ * default behavior is used.
+ * @param outctx the return outctx, free with krb5_rd_req_out_ctx_free().
+ * @return Kerberos 5 error code, see krb5_get_error_message().
+ *
+ * @ingroup krb5_auth
*/
krb5_error_code KRB5_LIB_FUNCTION
{
krb5_error_code ret;
krb5_ap_req ap_req;
- krb5_principal service = NULL;
krb5_rd_req_out_ctx o = NULL;
+ krb5_keytab id = NULL, keytab = NULL;
+ krb5_principal service = NULL;
- ret = _krb5_rd_req_out_ctx_alloc(context, &o);
- if (ret)
- goto out;
+ *outctx = NULL;
+
+ o = calloc(1, sizeof(*o));
+ if (o == NULL) {
+ krb5_set_error_message(context, ENOMEM,
+ N_("malloc: out of memory", ""));
+ return ENOMEM;
+ }
if (*auth_context == NULL) {
ret = krb5_auth_con_init(context, auth_context);
if(ret)
goto out;
- if(server == NULL){
- ret = _krb5_principalname2krb5_principal(context,
- &service,
- ap_req.ticket.sname,
- ap_req.ticket.realm);
- if (ret)
- goto out;
- server = service;
- }
+ /* Save that principal that was in the request */
+ ret = _krb5_principalname2krb5_principal(context,
+ &o->server,
+ ap_req.ticket.sname,
+ ap_req.ticket.realm);
+ if (ret)
+ goto out;
+
if (ap_req.ap_options.use_session_key &&
(*auth_context)->keyblock == NULL) {
ret = KRB5KRB_AP_ERR_NOKEY;
goto out;
}
+ if (inctx && inctx->keytab)
+ id = inctx->keytab;
+
if((*auth_context)->keyblock){
ret = krb5_copy_keyblock(context,
(*auth_context)->keyblock,
&o->keyblock);
if (ret)
goto out;
- } else if(inctx->keyblock){
+ } else if(inctx && inctx->keyblock){
ret = krb5_copy_keyblock(context,
inctx->keyblock,
&o->keyblock);
if (ret)
goto out;
} else {
- krb5_keytab keytab = NULL;
- if (inctx && inctx->keytab)
- keytab = inctx->keytab;
+ if(id == NULL) {
+ krb5_kt_default(context, &keytab);
+ id = keytab;
+ }
+ if (id == NULL)
+ goto out;
+
+ if (server == NULL) {
+ ret = _krb5_principalname2krb5_principal(context,
+ &service,
+ ap_req.ticket.sname,
+ ap_req.ticket.realm);
+ if (ret)
+ goto out;
+ server = service;
+ }
ret = get_key_from_keytab(context,
- auth_context,
&ap_req,
server,
- keytab,
+ id,
&o->keyblock);
- if(ret)
- goto out;
+ if (ret) {
+ /* If caller specified a server, fail. */
+ if (service == NULL)
+ goto out;
+ /* Otherwise, fall back to iterating over the keytab. This
+ * have serious performace issues for larger keytab.
+ */
+ o->keyblock = NULL;
+ }
}
- ret = krb5_verify_ap_req2(context,
- auth_context,
- &ap_req,
- server,
- o->keyblock,
- 0,
- &o->ap_req_options,
- &o->ticket,
- KRB5_KU_AP_REQ_AUTH);
+ if (o->keyblock) {
+ /*
+ * We got an exact keymatch, use that.
+ */
- if (ret)
- goto out;
+ ret = krb5_verify_ap_req2(context,
+ auth_context,
+ &ap_req,
+ server,
+ o->keyblock,
+ 0,
+ &o->ap_req_options,
+ &o->ticket,
+ KRB5_KU_AP_REQ_AUTH);
+
+ if (ret)
+ goto out;
+
+ } else {
+ /*
+ * Interate over keytab to find a key that can decrypt the request.
+ */
+
+ krb5_keytab_entry entry;
+ krb5_kt_cursor cursor;
+ int done = 0, kvno = 0;
+
+ memset(&cursor, 0, sizeof(cursor));
+
+ if (ap_req.ticket.enc_part.kvno)
+ kvno = *ap_req.ticket.enc_part.kvno;
+
+ ret = krb5_kt_start_seq_get(context, id, &cursor);
+ if (ret)
+ goto out;
+
+ done = 0;
+ while (!done) {
+ krb5_principal p;
+
+ ret = krb5_kt_next_entry(context, id, &entry, &cursor);
+ if (ret) {
+ _krb5_kt_principal_not_found(context, ret, id, o->server,
+ ap_req.ticket.enc_part.etype,
+ kvno);
+ goto out;
+ }
+
+ if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype ||
+ (kvno && kvno != entry.vno)) {
+ krb5_kt_free_entry (context, &entry);
+ continue;
+ }
+
+ ret = krb5_verify_ap_req2(context,
+ auth_context,
+ &ap_req,
+ server,
+ &entry.keyblock,
+ 0,
+ &o->ap_req_options,
+ &o->ticket,
+ KRB5_KU_AP_REQ_AUTH);
+ if (ret) {
+ krb5_kt_free_entry (context, &entry);
+ continue;
+ }
+
+ /*
+ * Found a match, save the keyblock for PAC processing,
+ * and update the service principal in the ticket to match
+ * whatever is in the keytab.
+ */
+
+ ret = krb5_copy_keyblock(context,
+ &entry.keyblock,
+ &o->keyblock);
+ if (ret) {
+ krb5_kt_free_entry (context, &entry);
+ goto out;
+ }
+
+ ret = krb5_copy_principal(context, entry.principal, &p);
+ if (ret) {
+ krb5_kt_free_entry (context, &entry);
+ goto out;
+ }
+ krb5_free_principal(context, o->ticket->server);
+ o->ticket->server = p;
+
+ krb5_kt_free_entry (context, &entry);
+
+ done = 1;
+ }
+ krb5_kt_end_seq_get (context, id, &cursor);
+ }
/* If there is a PAC, verify its server signature */
- if (inctx->check_pac) {
+ if (inctx == NULL || inctx->check_pac) {
krb5_pac pac;
krb5_data data;
krb5_pac_free(context, pac);
if (ret)
goto out;
- }
- ret = 0;
+ } else
+ ret = 0;
}
out:
+
if (ret || outctx == NULL) {
krb5_rd_req_out_ctx_free(context, o);
} else
*outctx = o;
free_AP_REQ(&ap_req);
- if(service)
+
+ if (service)
krb5_free_principal(context, service);
+
+ if (keytab)
+ krb5_kt_close(context, keytab);
+
return ret;
}
ssize_t (*fetch)(struct krb5_storage_data*, void*, size_t);
ssize_t (*store)(struct krb5_storage_data*, const void*, size_t);
off_t (*seek)(struct krb5_storage_data*, off_t, int);
+ int (*trunc)(struct krb5_storage_data*, off_t);
void (*free)(struct krb5_storage_data*);
krb5_flags flags;
int eof_code;
/*
- * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
sp->flags &= ~flags;
}
+/**
+ * Return true or false depending on if the storage flags is set or
+ * not. NB testing for the flag 0 always return true.
+ *
+ * @param sp the storage buffer to check flags on
+ * @param flags The flags to test for
+ *
+ * @return true if all the flags are set, false if not.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_boolean KRB5_LIB_FUNCTION
krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
{
return (sp->flags & flags) == flags;
}
+/**
+ * Set the new byte order of the storage buffer.
+ *
+ * @param sp the storage buffer to set the byte order for.
+ * @param byteorder the new byte order.
+ *
+ * The byte order are: KRB5_STORAGE_BYTEORDER_BE,
+ * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST.
+ *
+ * @ingroup krb5_storage
+ */
+
void KRB5_LIB_FUNCTION
krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
{
sp->flags |= byteorder;
}
+/**
+ * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_flags KRB5_LIB_FUNCTION
-krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder)
+krb5_storage_get_byteorder(krb5_storage *sp)
{
return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
}
+/**
+ * Seek to a new offset.
+ *
+ * @param sp the storage buffer to seek in.
+ * @param offset the offset to seek
+ * @param whence relateive searching, SEEK_CUR from the current
+ * position, SEEK_END from the end, SEEK_SET absolute from the start.
+ *
+ * @return The new current offset
+ *
+ * @ingroup krb5_storage
+ */
+
off_t KRB5_LIB_FUNCTION
krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
{
return (*sp->seek)(sp, offset, whence);
}
+/**
+ * Truncate the storage buffer in sp to offset.
+ *
+ * @param sp the storage buffer to truncate.
+ * @param offset the offset to truncate too.
+ *
+ * @return An Kerberos 5 error code.
+ *
+ * @ingroup krb5_storage
+ */
+
+int KRB5_LIB_FUNCTION
+krb5_storage_truncate(krb5_storage *sp, off_t offset)
+{
+ return (*sp->trunc)(sp, offset);
+}
+
+/**
+ * Read to the storage buffer.
+ *
+ * @param sp the storage buffer to read from
+ * @param buf the buffer to store the data in
+ * @param len the length to read
+ *
+ * @return The length of data read (can be shorter then len), or negative on error.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_ssize_t KRB5_LIB_FUNCTION
krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
{
return sp->fetch(sp, buf, len);
}
+/**
+ * Write to the storage buffer.
+ *
+ * @param sp the storage buffer to write to
+ * @param buf the buffer to write to the storage buffer
+ * @param len the length to write
+ *
+ * @return The length of data written (can be shorter then len), or negative on error.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_ssize_t KRB5_LIB_FUNCTION
krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
{
return sp->store(sp, buf, len);
}
+/**
+ * Set the return code that will be used when end of storage is reached.
+ *
+ * @param sp the storage
+ * @param code the error code to return on end of storage
+ *
+ * @ingroup krb5_storage
+ */
+
void KRB5_LIB_FUNCTION
krb5_storage_set_eof_code(krb5_storage *sp, int code)
{
sp->eof_code = code;
}
+/**
+ * Get the return code that will be used when end of storage is reached.
+ *
+ * @param sp the storage
+ *
+ * @return storage error code
+ *
+ * @ingroup krb5_storage
+ */
+
+int KRB5_LIB_FUNCTION
+krb5_storage_get_eof_code(krb5_storage *sp)
+{
+ return sp->eof_code;
+}
+
krb5_ssize_t KRB5_LIB_FUNCTION
_krb5_put_int(void *buffer, unsigned long value, size_t size)
{
return size;
}
+/**
+ * Free a krb5 storage.
+ *
+ * @param sp the storage to free.
+ *
+ * @return An Kerberos 5 error code.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_storage_free(krb5_storage *sp)
{
return 0;
}
+/**
+ * Copy the contnent of storage
+ *
+ * @param sp the storage to copy to a data
+ * @param data the copied data, free with krb5_data_free()
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
{
- off_t pos;
- size_t size;
+ off_t pos, size;
krb5_error_code ret;
pos = sp->seek(sp, 0, SEEK_CUR);
+ if (pos < 0)
+ return HEIM_ERR_NOT_SEEKABLE;
size = (size_t)sp->seek(sp, 0, SEEK_END);
+ if (size > (size_t)-1)
+ return HEIM_ERR_TOO_BIG;
ret = krb5_data_alloc (data, size);
if (ret) {
sp->seek(sp, pos, SEEK_SET);
return 0;
}
+/**
+ * Store a int32 to storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_int32(krb5_storage *sp,
int32_t value)
return krb5_store_int(sp, value, 4);
}
+/**
+ * Store a uint32 to storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_uint32(krb5_storage *sp,
uint32_t value)
return ret;
}
+/**
+ * Store a int16 to storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_int16(krb5_storage *sp,
int16_t value)
return krb5_store_int(sp, value, 2);
}
+/**
+ * Store a uint16 to storage, byte order is controlled by the settings
+ * on the storage, see krb5_storage_set_byteorder().
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_uint16(krb5_storage *sp,
uint16_t value)
return ret;
}
+/**
+ * Store a int8 to storage.
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_int8(krb5_storage *sp,
int8_t value)
return 0;
}
+/**
+ * Store a uint8 to storage.
+ *
+ * @param sp the storage to write too
+ * @param value the value to store
+ *
+ * @return 0 for success, or a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_uint8(krb5_storage *sp,
uint8_t value)
return ret;
}
+/**
+ * Store a data to the storage.
+ *
+ * @param sp the storage buffer to write to
+ * @param data the buffer to store.
+ *
+ * @return 0 on success, a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_data(krb5_storage *sp,
krb5_data data)
return 0;
}
+/**
+ * Parse a data from the storage.
+ *
+ * @param sp the storage buffer to read from
+ * @param data the parsed data
+ *
+ * @return 0 on success, a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_ret_data(krb5_storage *sp,
krb5_data *data)
return 0;
}
+/**
+ * Store a keyblock to the storage.
+ *
+ * @param sp the storage buffer to write to
+ * @param p the keyblock to write
+ *
+ * @return 0 on success, a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
{
return ret;
}
+/**
+ * Read a keyblock from the storage.
+ *
+ * @param sp the storage buffer to write to
+ * @param p the keyblock read from storage, free using krb5_free_keyblock()
+ *
+ * @return 0 on success, a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
{
return ret;
}
+/**
+ * Write a times block to storage.
+ *
+ * @param sp the storage buffer to write to
+ * @param times the times block to write.
+ *
+ * @return 0 on success, a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_store_times(krb5_storage *sp, krb5_times times)
{
return ret;
}
+/**
+ * Read a times block from the storage.
+ *
+ * @param sp the storage buffer to write to
+ * @param times the times block read from storage
+ *
+ * @return 0 on success, a Kerberos 5 error code on failure.
+ *
+ * @ingroup krb5_storage
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_ret_times(krb5_storage *sp, krb5_times *times)
{
header |= SC_ADDRESSES;
ret = krb5_store_int32(sp, header);
+ if (ret)
+ return ret;
if (creds->client) {
ret = krb5_store_principal(sp, creds->client);
sz *= 2;
base = realloc(s->base, sz);
if(base == NULL)
- return 0;
+ return -1;
s->size = sz;
s->base = base;
s->ptr = (unsigned char*)base + off;
return s->ptr - s->base;
}
+static int
+emem_trunc(krb5_storage *sp, off_t offset)
+{
+ emem_storage *s = (emem_storage*)sp->data;
+ /*
+ * If offset is larget then current size, or current size is
+ * shrunk more then half of the current size, adjust buffer.
+ */
+ if (offset > s->size || (s->size / 2) > offset) {
+ void *base;
+ size_t off;
+ off = s->ptr - s->base;
+ base = realloc(s->base, offset);
+ if(base == NULL)
+ return ENOMEM;
+ if (offset > s->size)
+ memset((char *)base + s->size, 0, offset - s->size);
+ s->size = offset;
+ s->base = base;
+ s->ptr = (unsigned char *)base + off;
+ }
+ s->len = offset;
+ if ((s->ptr - s->base) > offset)
+ s->ptr = s->base + offset;
+ return 0;
+}
+
+
static void
emem_free(krb5_storage *sp)
{
free(s->base);
}
+/**
+ * Create a elastic (allocating) memory storage backend. Memory is
+ * allocated on demand. Free returned krb5_storage with
+ * krb5_storage_free().
+ *
+ * @return A krb5_storage on success, or NULL on out of memory error.
+ *
+ * @ingroup krb5_storage
+ *
+ * @sa krb5_storage_from_mem()
+ * @sa krb5_storage_from_readonly_mem()
+ * @sa krb5_storage_from_fd()
+ * @sa krb5_storage_from_data()
+ */
+
krb5_storage * KRB5_LIB_FUNCTION
krb5_storage_emem(void)
{
sp->fetch = emem_fetch;
sp->store = emem_store;
sp->seek = emem_seek;
+ sp->trunc = emem_trunc;
sp->free = emem_free;
return sp;
}
return lseek(FD(sp), offset, whence);
}
+static int
+fd_trunc(krb5_storage * sp, off_t offset)
+{
+ if (ftruncate(FD(sp), offset) == -1)
+ return errno;
+ return 0;
+}
+
static void
fd_free(krb5_storage * sp)
{
close(FD(sp));
}
+/**
+ *
+ *
+ * @return A krb5_storage on success, or NULL on out of memory error.
+ *
+ * @ingroup krb5_storage
+ *
+ * @sa krb5_storage_from_emem()
+ * @sa krb5_storage_from_mem()
+ * @sa krb5_storage_from_readonly_mem()
+ * @sa krb5_storage_from_data()
+ */
+
krb5_storage * KRB5_LIB_FUNCTION
krb5_storage_from_fd(int fd)
{
sp->fetch = fd_fetch;
sp->store = fd_store;
sp->seek = fd_seek;
+ sp->trunc = fd_trunc;
sp->free = fd_free;
return sp;
}
return s->ptr - s->base;
}
+static int
+mem_trunc(krb5_storage *sp, off_t offset)
+{
+ mem_storage *s = (mem_storage*)sp->data;
+ if(offset > s->size)
+ return ERANGE;
+ s->size = offset;
+ if ((s->ptr - s->base) > offset)
+ s->ptr = s->base + offset;
+ return 0;
+}
+
+static int
+mem_no_trunc(krb5_storage *sp, off_t offset)
+{
+ return EINVAL;
+}
+
+/**
+ *
+ *
+ * @return A krb5_storage on success, or NULL on out of memory error.
+ *
+ * @ingroup krb5_storage
+ *
+ * @sa krb5_storage_from_emem()
+ * @sa krb5_storage_from_readonly_mem()
+ * @sa krb5_storage_from_data()
+ * @sa krb5_storage_from_fd()
+ */
+
krb5_storage * KRB5_LIB_FUNCTION
krb5_storage_from_mem(void *buf, size_t len)
{
sp->fetch = mem_fetch;
sp->store = mem_store;
sp->seek = mem_seek;
+ sp->trunc = mem_trunc;
sp->free = NULL;
return sp;
}
+/**
+ *
+ *
+ * @return A krb5_storage on success, or NULL on out of memory error.
+ *
+ * @ingroup krb5_storage
+ *
+ * @sa krb5_storage_from_emem()
+ * @sa krb5_storage_from_mem()
+ * @sa krb5_storage_from_readonly_mem()
+ * @sa krb5_storage_from_fd()
+ */
+
krb5_storage * KRB5_LIB_FUNCTION
krb5_storage_from_data(krb5_data *data)
{
return krb5_storage_from_mem(data->data, data->length);
}
+/**
+ *
+ *
+ * @return A krb5_storage on success, or NULL on out of memory error.
+ *
+ * @ingroup krb5_storage
+ *
+ * @sa krb5_storage_from_emem()
+ * @sa krb5_storage_from_mem()
+ * @sa krb5_storage_from_data()
+ * @sa krb5_storage_from_fd()
+ */
+
krb5_storage * KRB5_LIB_FUNCTION
krb5_storage_from_readonly_mem(const void *buf, size_t len)
{
sp->fetch = mem_fetch;
sp->store = mem_no_store;
sp->seek = mem_seek;
+ sp->trunc = mem_no_trunc;
sp->free = NULL;
return sp;
}
}
return 0;
}
+
+static krb5_error_code
+check_server_referral(krb5_context context,
+ krb5_kdc_rep *rep,
+ unsigned flags,
+ krb5_const_principal requested,
+ krb5_const_principal returned,
+ krb5_keyblock * key)
+{
+ krb5_error_code ret;
+ PA_ServerReferralData ref;
+ krb5_crypto session;
+ EncryptedData ed;
+ size_t len;
+ krb5_data data;
+ PA_DATA *pa;
+ int i = 0, cmp;
+
+ if (rep->kdc_rep.padata == NULL)
+ goto noreferral;
+
+ pa = krb5_find_padata(rep->kdc_rep.padata->val,
+ rep->kdc_rep.padata->len,
+ KRB5_PADATA_SERVER_REFERRAL, &i);
+ if (pa == NULL)
+ goto noreferral;
+
+ memset(&ed, 0, sizeof(ed));
+ memset(&ref, 0, sizeof(ref));
+
+ ret = decode_EncryptedData(pa->padata_value.data,
+ pa->padata_value.length,
+ &ed, &len);
+ if (ret)
+ return ret;
+ if (len != pa->padata_value.length) {
+ free_EncryptedData(&ed);
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("Referral EncryptedData wrong for realm %s",
+ "realm"), requested->realm);
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ ret = krb5_crypto_init(context, key, 0, &session);
+ if (ret) {
+ free_EncryptedData(&ed);
+ return ret;
+ }
+
+ ret = krb5_decrypt_EncryptedData(context, session,
+ KRB5_KU_PA_SERVER_REFERRAL,
+ &ed, &data);
+ free_EncryptedData(&ed);
+ krb5_crypto_destroy(context, session);
+ if (ret)
+ return ret;
+
+ ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
+ if (ret) {
+ krb5_data_free(&data);
+ return ret;
+ }
+ krb5_data_free(&data);
+
+ if (strcmp(requested->realm, returned->realm) != 0) {
+ free_PA_ServerReferralData(&ref);
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("server ref realm mismatch, "
+ "requested realm %s got back %s", ""),
+ requested->realm, returned->realm);
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (returned->name.name_string.len == 2 &&
+ strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0)
+ {
+ const char *realm = returned->name.name_string.val[1];
+
+ if (ref.referred_realm == NULL
+ || strcmp(*ref.referred_realm, realm) != 0)
+ {
+ free_PA_ServerReferralData(&ref);
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("tgt returned with wrong ref", ""));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+ } else if (krb5_principal_compare(context, returned, requested) == 0) {
+ free_PA_ServerReferralData(&ref);
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("req princ no same as returned", ""));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (ref.requested_principal_name) {
+ cmp = _krb5_principal_compare_PrincipalName(context,
+ requested,
+ ref.requested_principal_name);
+ if (!cmp) {
+ free_PA_ServerReferralData(&ref);
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("referred principal not same "
+ "as requested", ""));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+ } else if (flags & EXTRACT_TICKET_AS_REQ) {
+ free_PA_ServerReferralData(&ref);
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("Requested principal missing on AS-REQ", ""));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ free_PA_ServerReferralData(&ref);
+
+ return ret;
+noreferral:
+ if (krb5_principal_compare(context, requested, returned) == FALSE) {
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("Not same server principal returned "
+ "as requested", ""));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+ return 0;
+}
+
+
+/*
+ * Verify referral data
+ */
+
+
+static krb5_error_code
+check_client_referral(krb5_context context,
+ krb5_kdc_rep *rep,
+ krb5_const_principal requested,
+ krb5_const_principal mapped,
+ krb5_keyblock const * key)
+{
+ krb5_error_code ret;
+ PA_ClientCanonicalized canon;
+ krb5_crypto crypto;
+ krb5_data data;
+ PA_DATA *pa;
+ size_t len;
+ int i = 0;
+
+ if (rep->kdc_rep.padata == NULL)
+ goto noreferral;
+
+ pa = krb5_find_padata(rep->kdc_rep.padata->val,
+ rep->kdc_rep.padata->len,
+ KRB5_PADATA_CLIENT_CANONICALIZED, &i);
+ if (pa == NULL)
+ goto noreferral;
+
+ ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
+ pa->padata_value.length,
+ &canon, &len);
+ if (ret) {
+ krb5_set_error_message(context, ret,
+ N_("Failed to decode ClientCanonicalized "
+ "from realm %s", ""), requested->realm);
+ return ret;
+ }
+
+ ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
+ &canon.names, &len, ret);
+ if (ret) {
+ free_PA_ClientCanonicalized(&canon);
+ return ret;
+ }
+ if (data.length != len)
+ krb5_abortx(context, "internal asn.1 error");
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret) {
+ free(data.data);
+ free_PA_ClientCanonicalized(&canon);
+ return ret;
+ }
+
+ ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
+ data.data, data.length,
+ &canon.canon_checksum);
+ krb5_crypto_destroy(context, crypto);
+ free(data.data);
+ if (ret) {
+ krb5_set_error_message(context, ret,
+ N_("Failed to verify client canonicalized "
+ "data from realm %s", ""),
+ requested->realm);
+ free_PA_ClientCanonicalized(&canon);
+ return ret;
+ }
+
+ if (!_krb5_principal_compare_PrincipalName(context,
+ requested,
+ &canon.names.requested_name))
+ {
+ free_PA_ClientCanonicalized(&canon);
+ krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
+ N_("Requested name doesn't match"
+ " in client referral", ""));
+ return KRB5_PRINC_NOMATCH;
+ }
+ if (!_krb5_principal_compare_PrincipalName(context,
+ mapped,
+ &canon.names.mapped_name))
+ {
+ free_PA_ClientCanonicalized(&canon);
+ krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
+ N_("Mapped name doesn't match"
+ " in client referral", ""));
+ return KRB5_PRINC_NOMATCH;
+ }
+
+ return 0;
+
+noreferral:
+ if (krb5_principal_compare(context, requested, mapped) == FALSE) {
+ krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
+ N_("Not same client principal returned "
+ "as requested", ""));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+ return 0;
+}
+
+
+static krb5_error_code
+decrypt_tkt (krb5_context context,
+ krb5_keyblock *key,
+ krb5_key_usage usage,
+ krb5_const_pointer decrypt_arg,
+ krb5_kdc_rep *dec_rep)
+{
+ krb5_error_code ret;
+ krb5_data data;
+ size_t size;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ usage,
+ &dec_rep->kdc_rep.enc_part,
+ &data);
+ krb5_crypto_destroy(context, crypto);
+
+ if (ret)
+ return ret;
+
+ ret = decode_EncASRepPart(data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ if (ret)
+ ret = decode_EncTGSRepPart(data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ krb5_data_free (&data);
+ if (ret) {
+ krb5_set_error_message(context, ret,
+ N_("Failed to decode encpart in ticket", ""));
+ return ret;
+ }
+ return 0;
+}
+
+int
+_krb5_extract_ticket(krb5_context context,
+ krb5_kdc_rep *rep,
+ krb5_creds *creds,
+ krb5_keyblock *key,
+ krb5_const_pointer keyseed,
+ krb5_key_usage key_usage,
+ krb5_addresses *addrs,
+ unsigned nonce,
+ unsigned flags,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg)
+{
+ krb5_error_code ret;
+ krb5_principal tmp_principal;
+ size_t len;
+ time_t tmp_time;
+ krb5_timestamp sec_now;
+
+ /* decrypt */
+
+ if (decrypt_proc == NULL)
+ decrypt_proc = decrypt_tkt;
+
+ ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
+ if (ret)
+ goto out;
+
+ /* save session key */
+
+ creds->session.keyvalue.length = 0;
+ creds->session.keyvalue.data = NULL;
+ creds->session.keytype = rep->enc_part.key.keytype;
+ ret = krb5_data_copy (&creds->session.keyvalue,
+ rep->enc_part.key.keyvalue.data,
+ rep->enc_part.key.keyvalue.length);
+ if (ret) {
+ krb5_clear_error_message(context);
+ goto out;
+ }
+
+ /*
+ * HACK:
+ * this is really a ugly hack, to support using the Netbios Domain Name
+ * as realm against windows KDC's, they always return the full realm
+ * based on the DNS Name.
+ */
+ flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
+ flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
+
+ /* compare client and save */
+ ret = _krb5_principalname2krb5_principal (context,
+ &tmp_principal,
+ rep->kdc_rep.cname,
+ rep->kdc_rep.crealm);
+ if (ret)
+ goto out;
+
+ /* check client referral and save principal */
+ /* anonymous here ? */
+ if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
+ ret = check_client_referral(context, rep,
+ creds->client,
+ tmp_principal,
+ &creds->session);
+ if (ret) {
+ krb5_free_principal (context, tmp_principal);
+ goto out;
+ }
+ }
+ krb5_free_principal (context, creds->client);
+ creds->client = tmp_principal;
+
+ /* check server referral and save principal */
+ ret = _krb5_principalname2krb5_principal (context,
+ &tmp_principal,
+ rep->kdc_rep.ticket.sname,
+ rep->kdc_rep.ticket.realm);
+ if (ret)
+ goto out;
+ if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
+ ret = check_server_referral(context,
+ rep,
+ flags,
+ creds->server,
+ tmp_principal,
+ &creds->session);
+ if (ret) {
+ krb5_free_principal (context, tmp_principal);
+ goto out;
+ }
+ }
+ krb5_free_principal(context, creds->server);
+ creds->server = tmp_principal;
+
+ /* verify names */
+ if(flags & EXTRACT_TICKET_MATCH_REALM){
+ const char *srealm = krb5_principal_get_realm(context, creds->server);
+ const char *crealm = krb5_principal_get_realm(context, creds->client);
+
+ if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
+ strcmp(rep->enc_part.srealm, crealm) != 0)
+ {
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ krb5_clear_error_message(context);
+ goto out;
+ }
+ }
+
+ /* compare nonces */
+
+ if (nonce != rep->enc_part.nonce) {
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
+ goto out;
+ }
+
+ /* set kdc-offset */
+
+ krb5_timeofday (context, &sec_now);
+ if (rep->enc_part.flags.initial
+ && context->kdc_sec_offset == 0
+ && krb5_config_get_bool (context, NULL,
+ "libdefaults",
+ "kdc_timesync",
+ NULL)) {
+ context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
+ krb5_timeofday (context, &sec_now);
+ }
+
+ /* check all times */
+
+ if (rep->enc_part.starttime) {
+ tmp_time = *rep->enc_part.starttime;
+ } else
+ tmp_time = rep->enc_part.authtime;
+
+ if (creds->times.starttime == 0
+ && abs(tmp_time - sec_now) > context->max_skew) {
+ ret = KRB5KRB_AP_ERR_SKEW;
+ krb5_set_error_message (context, ret,
+ N_("time skew (%d) larger than max (%d)", ""),
+ abs(tmp_time - sec_now),
+ (int)context->max_skew);
+ goto out;
+ }
+
+ if (creds->times.starttime != 0
+ && tmp_time != creds->times.starttime) {
+ krb5_clear_error_message (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ creds->times.starttime = tmp_time;
+
+ if (rep->enc_part.renew_till) {
+ tmp_time = *rep->enc_part.renew_till;
+ } else
+ tmp_time = 0;
+
+ if (creds->times.renew_till != 0
+ && tmp_time > creds->times.renew_till) {
+ krb5_clear_error_message (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ creds->times.renew_till = tmp_time;
+
+ creds->times.authtime = rep->enc_part.authtime;
+
+ if (creds->times.endtime != 0
+ && rep->enc_part.endtime > creds->times.endtime) {
+ krb5_clear_error_message (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ creds->times.endtime = rep->enc_part.endtime;
+
+ if(rep->enc_part.caddr)
+ krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
+ else if(addrs)
+ krb5_copy_addresses (context, addrs, &creds->addresses);
+ else {
+ creds->addresses.len = 0;
+ creds->addresses.val = NULL;
+ }
+ creds->flags.b = rep->enc_part.flags;
+
+ creds->authdata.len = 0;
+ creds->authdata.val = NULL;
+
+ /* extract ticket */
+ ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
+ &rep->kdc_rep.ticket, &len, ret);
+ if(ret)
+ goto out;
+ if (creds->ticket.length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ creds->second_ticket.length = 0;
+ creds->second_ticket.data = NULL;
+
+
+out:
+ memset (rep->enc_part.key.keyvalue.data, 0,
+ rep->enc_part.key.keyvalue.length);
+ return ret;
+}
ret = write(fd, data.data, data.length);
if (ret != data.length)
ret = KRB5_CC_IO;
+ else
+ ret = 0;
- krb5_free_data_contents(context, &data);
+ krb5_data_free(&data);
flock(fd, LOCK_UN);
free(path);
close(fd);
- return 0;
+ return ret;
}
/*
#undef __attribute__
#define __attribute__(X)
+/**
+ * Log a warning to the log, default stderr, include the error from
+ * the last failure.
+ *
+ * @param context A Kerberos 5 context.
+ * @param code error code of the last error
+ * @param fmt message to print
+ * @param ap arguments
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_vwarn(krb5_context context, krb5_error_code code,
const char *fmt, va_list ap)
return _warnerr(context, 1, code, 1, fmt, ap);
}
+/**
+ * Log a warning to the log, default stderr, include the error from
+ * the last failure.
+ *
+ * @param context A Kerberos 5 context.
+ * @param code error code of the last error
+ * @param fmt message to print
+ *
+ * @ingroup krb5_error
+ */
krb5_error_code KRB5_LIB_FUNCTION
krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...)
return ret;
}
+/**
+ * Log a warning to the log, default stderr.
+ *
+ * @param context A Kerberos 5 context.
+ * @param fmt message to print
+ * @param ap arguments
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_vwarnx(krb5_context context, const char *fmt, va_list ap)
__attribute__ ((format (printf, 2, 0)))
return _warnerr(context, 0, 0, 1, fmt, ap);
}
+/**
+ * Log a warning to the log, default stderr.
+ *
+ * @param context A Kerberos 5 context.
+ * @param fmt message to print
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_warnx(krb5_context context, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)))
return ret;
}
+/**
+ * Log a warning to the log, default stderr, include bthe error from
+ * the last failure and then exit.
+ *
+ * @param context A Kerberos 5 context
+ * @param eval the exit code to exit with
+ * @param code error code of the last error
+ * @param fmt message to print
+ * @param ap arguments
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_verr(krb5_context context, int eval, krb5_error_code code,
const char *fmt, va_list ap)
exit(eval);
}
+/**
+ * Log a warning to the log, default stderr, include bthe error from
+ * the last failure and then exit.
+ *
+ * @param context A Kerberos 5 context
+ * @param eval the exit code to exit with
+ * @param code error code of the last error
+ * @param fmt message to print
+ *
+ * @ingroup krb5_error
+ */
krb5_error_code KRB5_LIB_FUNCTION
krb5_err(krb5_context context, int eval, krb5_error_code code,
exit(eval);
}
+/**
+ * Log a warning to the log, default stderr, and then exit.
+ *
+ * @param context A Kerberos 5 context
+ * @param eval the exit code to exit with
+ * @param fmt message to print
+ * @param ap arguments
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap)
__attribute__ ((noreturn, format (printf, 3, 0)))
exit(eval);
}
+/**
+ * Log a warning to the log, default stderr, and then exit.
+ *
+ * @param context A Kerberos 5 context
+ * @param eval the exit code to exit with
+ * @param fmt message to print
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_errx(krb5_context context, int eval, const char *fmt, ...)
__attribute__ ((noreturn, format (printf, 3, 4)))
exit(eval);
}
+/**
+ * Log a warning to the log, default stderr, include bthe error from
+ * the last failure and then abort.
+ *
+ * @param context A Kerberos 5 context
+ * @param code error code of the last error
+ * @param fmt message to print
+ * @param ap arguments
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_vabort(krb5_context context, krb5_error_code code,
const char *fmt, va_list ap)
abort();
}
+/**
+ * Log a warning to the log, default stderr, include bthe error from
+ * the last failure and then abort.
+ *
+ * @param context A Kerberos 5 context
+ * @param code error code of the last error
+ * @param fmt message to print
+ *
+ * @ingroup krb5_error
+ */
krb5_error_code KRB5_LIB_FUNCTION
krb5_abort(krb5_context context, krb5_error_code code, const char *fmt, ...)
abort();
}
+/**
+ * Log a warning to the log, default stderr, and then abort.
+ *
+ * @param context A Kerberos 5 context
+ * @param code error code of the last error
+ * @param fmt message to print
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_abortx(krb5_context context, const char *fmt, ...)
__attribute__ ((noreturn, format (printf, 2, 3)))
abort();
}
+/**
+ * Set the default logging facility.
+ *
+ * @param context A Kerberos 5 context
+ * @param fac Facility to use for logging.
+ *
+ * @ingroup krb5_error
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac)
{
return 0;
}
+/**
+ * Get the default logging facility.
+ *
+ * @param context A Kerberos 5 context
+ *
+ * @ingroup krb5_error
+ */
+
krb5_log_facility * KRB5_LIB_FUNCTION
krb5_get_warn_dest(krb5_context context)
{
#include <config.h>
-RCSID("$Id$");
-
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
CHECK(ret_string(in, 0, &hostname, &data->hostname), 0);
out:
- krb5_storage_free(in);
+ if (in)
+ krb5_storage_free(in);
if (ret)
heim_ntlm_free_type1(data);
ret = 0;
out:
- krb5_storage_free(in);
+ if (in)
+ krb5_storage_free(in);
if (ret)
heim_ntlm_free_type2(type2);
CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0);
out:
- krb5_storage_free(in);
+ if (in)
+ krb5_storage_free(in);
if (ret)
heim_ntlm_free_type3(type3);
* @param target the name of the target, assumed to be in UTF8.
* @param ntlmv2 the ntlmv2 session key
*
+ * @return 0 on success, or an error code on failure.
+ *
* @ingroup ntlm_core
*/
-void
+int
heim_ntlm_ntlmv2_key(const void *key, size_t len,
const char *username,
const char *target,
unsigned char ntlmv2[16])
{
+ int ret;
unsigned int hmaclen;
HMAC_CTX c;
{
struct ntlm_buf buf;
/* uppercase username and turn it into ucs2-le */
- ascii2ucs2le(username, 1, &buf);
+ ret = ascii2ucs2le(username, 1, &buf);
+ if (ret)
+ goto out;
HMAC_Update(&c, buf.data, buf.length);
free(buf.data);
/* uppercase target and turn into ucs2-le */
- ascii2ucs2le(target, 1, &buf);
+ ret = ascii2ucs2le(target, 1, &buf);
+ if (ret)
+ goto out;
HMAC_Update(&c, buf.data, buf.length);
free(buf.data);
}
HMAC_Final(&c, ntlmv2, &hmaclen);
+ out:
HMAC_CTX_cleanup(&c);
+ return ret;
}
/*
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
+
#include <stdlib.h>
#include <string.h>
#include "base64.h"
const unsigned char *q;
p = s = (char *) malloc(size * 4 / 3 + 4);
- if (p == NULL)
+ if (p == NULL) {
+ *str = NULL;
return -1;
+ }
q = (const unsigned char *) data;
for (i = 0; i < size;) {
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include "roken.h"
-RCSID("$Id$");
-
#ifndef HAVE_BSWAP32
unsigned int ROKEN_LIB_FUNCTION
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <unistd.h>
#include <fcntl.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <unistd.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdlib.h>
#include <err.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdlib.h>
#include <err.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdlib.h>
#include <err.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdlib.h>
#include <err.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdio.h>
#include <stdlib.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#ifndef HAVE_H_ERRNO
int h_errno = -17; /* Some magic number */
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
#include <ctype.h>
#include "hex.h"
char *p;
/* check for overflow */
- if (size * 2 < size)
+ if (size * 2 < size) {
+ *str = NULL;
return -1;
+ }
p = malloc(size * 2 + 1);
- if (p == NULL)
+ if (p == NULL) {
+ *str = NULL;
return -1;
+ }
for (i = 0; i < size; i++) {
p[i * 2] = hexchar[(*q >> 4) & 0xf];
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <sys/types.h>
#include <unistd.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <sys/types.h>
#include <unistd.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <parse_units.h>
#include "parse_time.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdio.h>
#include <ctype.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-#endif
+
#include "roken.h"
#ifdef HAVE_ARPA_NAMESER_H
#include <arpa/nameser.h>
#ifdef HAVE_RESOLV_H
#include <resolv.h>
#endif
+#ifdef HAVE_DNS_H
+#include <dns.h>
+#endif
#include "resolve.h"
#include <assert.h>
int _resolve_debug = 0;
int ROKEN_LIB_FUNCTION
-dns_string_to_type(const char *name)
+rk_dns_string_to_type(const char *name)
{
struct stot *p = stot;
for(p = stot; p->name; p++)
}
const char * ROKEN_LIB_FUNCTION
-dns_type_to_string(int type)
+rk_dns_type_to_string(int type)
{
struct stot *p = stot;
for(p = stot; p->name; p++)
#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
static void
-dns_free_rr(struct resource_record *rr)
+dns_free_rr(struct rk_resource_record *rr)
{
if(rr->domain)
free(rr->domain);
}
void ROKEN_LIB_FUNCTION
-dns_free_data(struct dns_reply *r)
+rk_dns_free_data(struct rk_dns_reply *r)
{
- struct resource_record *rr;
+ struct rk_resource_record *rr;
if(r->q.domain)
free(r->q.domain);
for(rr = r->head; rr;){
- struct resource_record *tmp = rr;
+ struct rk_resource_record *tmp = rr;
rr = rr->next;
dns_free_rr(tmp);
}
static int
parse_record(const unsigned char *data, const unsigned char *end_data,
- const unsigned char **pp, struct resource_record **ret_rr)
+ const unsigned char **pp, struct rk_resource_record **ret_rr)
{
- struct resource_record *rr;
+ struct rk_resource_record *rr;
int type, class, ttl;
unsigned size;
int status;
#ifndef TEST_RESOLVE
static
#endif
-struct dns_reply*
+struct rk_dns_reply*
parse_reply(const unsigned char *data, size_t len)
{
const unsigned char *p;
int i;
char host[MAXDNAME];
const unsigned char *end_data = data + len;
- struct dns_reply *r;
- struct resource_record **rr;
+ struct rk_dns_reply *r;
+ struct rk_resource_record **rr;
r = calloc(1, sizeof(*r));
if (r == NULL)
}
status = dn_expand(data, end_data, p, host, sizeof(host));
if(status < 0){
- dns_free_data(r);
+ rk_dns_free_data(r);
return NULL;
}
r->q.domain = strdup(host);
if(r->q.domain == NULL) {
- dns_free_data(r);
+ rk_dns_free_data(r);
return NULL;
}
if (p + status + 4 > end_data) {
- dns_free_data(r);
+ rk_dns_free_data(r);
return NULL;
}
p += status;
rr = &r->head;
for(i = 0; i < r->h.ancount; i++) {
if(parse_record(data, end_data, &p, rr) != 0) {
- dns_free_data(r);
+ rk_dns_free_data(r);
return NULL;
}
rr = &(*rr)->next;
}
for(i = 0; i < r->h.nscount; i++) {
if(parse_record(data, end_data, &p, rr) != 0) {
- dns_free_data(r);
+ rk_dns_free_data(r);
return NULL;
}
rr = &(*rr)->next;
}
for(i = 0; i < r->h.arcount; i++) {
if(parse_record(data, end_data, &p, rr) != 0) {
- dns_free_data(r);
+ rk_dns_free_data(r);
return NULL;
}
rr = &(*rr)->next;
#endif
#endif
-static struct dns_reply *
+#if defined(HAVE_DNS_SEARCH)
+#define resolve_search(h,n,c,t,r,l) \
+ ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize))
+#define resolve_free_handle(h) dns_free(h)
+#elif defined(HAVE_RES_NSEARCH)
+#define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l)
+#define resolve_free_handle(h) rk_res_free(h);
+#else
+#define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l)
+#define handle 0
+#define resolve_free_handle(h)
+#endif
+
+
+static struct rk_dns_reply *
dns_lookup_int(const char *domain, int rr_class, int rr_type)
{
- struct dns_reply *r;
- unsigned char *reply = NULL;
+ struct rk_dns_reply *r;
+ void *reply = NULL;
int size;
int len;
-#ifdef HAVE_RES_NSEARCH
+#if defined(HAVE_DNS_SEARCH)
+ struct sockaddr_storage from;
+ uint32_t fromsize = sizeof(from);
+ dns_handle_t handle;
+
+ handle = dns_open(NULL);
+ if (handle == NULL)
+ return NULL;
+#elif defined(HAVE_RES_NSEARCH)
struct __res_state state;
+ struct __res_state *handle = &state;
+
memset(&state, 0, sizeof(state));
- if(res_ninit(&state))
+ if(res_ninit(handle))
return NULL; /* is this the best we can do? */
-#elif defined(HAVE__RES)
- u_long old_options = 0;
#endif
size = 0;
if (size <= len)
size = len;
if (_resolve_debug) {
-#ifdef HAVE_RES_NSEARCH
+#if defined(HAVE_DNS_SEARCH)
+ dns_set_debug(handle, 1);
+#elif defined(HAVE_RES_NSEARCH)
state.options |= RES_DEBUG;
-#elif defined(HAVE__RES)
- old_options = _res.options;
- _res.options |= RES_DEBUG;
#endif
fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
- rr_class, dns_type_to_string(rr_type), size);
+ rr_class, rk_dns_type_to_string(rr_type), size);
}
reply = malloc(size);
if (reply == NULL) {
-#ifdef HAVE_RES_NSEARCH
- rk_res_free(&state);
-#endif
+ resolve_free_handle(handle);
return NULL;
}
-#ifdef HAVE_RES_NSEARCH
- len = res_nsearch(&state, domain, rr_class, rr_type, reply, size);
-#else
- len = res_search(domain, rr_class, rr_type, reply, size);
-#endif
+
+ len = resolve_search(handle, domain, rr_class, rr_type, reply, size);
+
if (_resolve_debug) {
-#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
- _res.options = old_options;
-#endif
fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
- domain, rr_class, dns_type_to_string(rr_type), len);
+ domain, rr_class, rk_dns_type_to_string(rr_type), len);
}
- if (len < 0) {
-#ifdef HAVE_RES_NSEARCH
- rk_res_free(&state);
-#endif
+ if (len <= 0) {
+ resolve_free_handle(handle);
free(reply);
return NULL;
}
} while (size < len && len < rk_DNS_MAX_PACKET_SIZE);
-#ifdef HAVE_RES_NSEARCH
- rk_res_free(&state);
-#endif
+ resolve_free_handle(handle);
len = min(len, size);
r = parse_reply(reply, len);
return r;
}
-struct dns_reply * ROKEN_LIB_FUNCTION
-dns_lookup(const char *domain, const char *type_name)
+struct rk_dns_reply * ROKEN_LIB_FUNCTION
+rk_dns_lookup(const char *domain, const char *type_name)
{
int type;
- type = dns_string_to_type(type_name);
+ type = rk_dns_string_to_type(type_name);
if(type == -1) {
if(_resolve_debug)
fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
type_name);
return NULL;
}
- return dns_lookup_int(domain, C_IN, type);
+ return dns_lookup_int(domain, rk_ns_c_in, type);
}
static int
compare_srv(const void *a, const void *b)
{
- const struct resource_record *const* aa = a, *const* bb = b;
+ const struct rk_resource_record *const* aa = a, *const* bb = b;
if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
/* try to rearrange the srv-records by the algorithm in RFC2782 */
void ROKEN_LIB_FUNCTION
-dns_srv_order(struct dns_reply *r)
+rk_dns_srv_order(struct rk_dns_reply *r)
{
- struct resource_record **srvs, **ss, **headp;
- struct resource_record *rr;
+ struct rk_resource_record **srvs, **ss, **headp;
+ struct rk_resource_record *rr;
int num_srv = 0;
#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
for(ss = srvs; ss < srvs + num_srv; ) {
int sum, rnd, count;
- struct resource_record **ee, **tt;
+ struct rk_resource_record **ee, **tt;
/* find the last record with the same priority and count the
sum of all weights */
for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
-struct dns_reply * ROKEN_LIB_FUNCTION
-dns_lookup(const char *domain, const char *type_name)
+struct rk_dns_reply * ROKEN_LIB_FUNCTION
+rk_dns_lookup(const char *domain, const char *type_name)
{
return NULL;
}
void ROKEN_LIB_FUNCTION
-dns_free_data(struct dns_reply *r)
+rk_dns_free_data(struct rk_dns_reply *r)
{
}
void ROKEN_LIB_FUNCTION
-dns_srv_order(struct dns_reply *r)
+rk_dns_srv_order(struct rk_dns_reply *r)
{
}
#endif
#endif
-typedef enum {
+enum {
+ rk_ns_c_in = 1
+};
+
+enum {
rk_ns_t_invalid = 0, /* Cookie. */
rk_ns_t_a = 1, /* Host address. */
rk_ns_t_ns = 2, /* Authoritative server. */
rk_ns_t_any = 255, /* Wildcard match. */
rk_ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
rk_ns_t_max = 65536
-} rk_ns_type;
-
-/* We use these, but they are not always present in <arpa/nameser.h> */
-
-#ifndef C_IN
-#define C_IN 1
-#endif
-
-#ifndef T_A
-#define T_A 1
-#endif
-#ifndef T_NS
-#define T_NS 2
-#endif
-#ifndef T_CNAME
-#define T_CNAME 5
-#endif
-#ifndef T_SOA
-#define T_SOA 5
-#endif
-#ifndef T_PTR
-#define T_PTR 12
-#endif
-#ifndef T_MX
-#define T_MX 15
-#endif
-#ifndef T_TXT
-#define T_TXT 16
-#endif
-#ifndef T_AFSDB
-#define T_AFSDB 18
-#endif
-#ifndef T_SIG
-#define T_SIG 24
-#endif
-#ifndef T_KEY
-#define T_KEY 25
-#endif
-#ifndef T_AAAA
-#define T_AAAA 28
-#endif
-#ifndef T_SRV
-#define T_SRV 33
-#endif
-#ifndef T_NAPTR
-#define T_NAPTR 35
-#endif
-#ifndef T_CERT
-#define T_CERT 37
-#endif
-#ifndef T_SSHFP
-#define T_SSHFP 44
-#endif
+};
#ifndef MAXDNAME
#define MAXDNAME 1025
#endif
-#define dns_query rk_dns_query
#define mx_record rk_mx_record
#define srv_record rk_srv_record
#define key_record rk_key_record
#define sig_record rk_sig_record
#define cert_record rk_cert_record
#define sshfp_record rk_sshfp_record
-#define resource_record rk_resource_record
-#define dns_reply rk_dns_reply
-
-#define dns_lookup rk_dns_lookup
-#define dns_free_data rk_dns_free_data
-#define dns_string_to_type rk_dns_string_to_type
-#define dns_type_to_string rk_dns_type_to_string
-#define dns_srv_order rk_dns_srv_order
-struct dns_query{
+struct rk_dns_query{
char *domain;
unsigned type;
unsigned class;
};
-struct mx_record{
+struct rk_mx_record{
unsigned preference;
char domain[1];
};
-struct srv_record{
+struct rk_srv_record{
unsigned priority;
unsigned weight;
unsigned port;
char target[1];
};
-struct key_record {
+struct rk_key_record {
unsigned flags;
unsigned protocol;
unsigned algorithm;
u_char key_data[1];
};
-struct sig_record {
+struct rk_sig_record {
unsigned type;
unsigned algorithm;
unsigned labels;
char sig_data[1]; /* also includes signer */
};
-struct cert_record {
+struct rk_cert_record {
unsigned type;
unsigned tag;
unsigned algorithm;
u_char cert_data[1];
};
-struct sshfp_record {
+struct rk_sshfp_record {
unsigned algorithm;
unsigned type;
size_t sshfp_len;
u_char sshfp_data[1];
};
-struct ds_record {
+struct rk_ds_record {
unsigned key_tag;
unsigned algorithm;
unsigned digest_type;
u_char digest_data[1];
};
-struct resource_record{
+struct rk_resource_record{
char *domain;
unsigned type;
unsigned class;
unsigned size;
union {
void *data;
- struct mx_record *mx;
- struct mx_record *afsdb; /* mx and afsdb are identical */
- struct srv_record *srv;
+ struct rk_mx_record *mx;
+ struct rk_mx_record *afsdb; /* mx and afsdb are identical */
+ struct rk_srv_record *srv;
struct in_addr *a;
char *txt;
- struct key_record *key;
- struct cert_record *cert;
- struct sig_record *sig;
- struct sshfp_record *sshfp;
- struct ds_record *ds;
+ struct rk_key_record *key;
+ struct rk_cert_record *cert;
+ struct rk_sig_record *sig;
+ struct rk_sshfp_record *sshfp;
+ struct rk_ds_record *ds;
}u;
- struct resource_record *next;
+ struct rk_resource_record *next;
};
#define rk_DNS_MAX_PACKET_SIZE 0xffff
-struct dns_header {
+struct rk_dns_header {
unsigned id;
unsigned flags;
#define rk_DNS_HEADER_RESPONSE_FLAG 1
unsigned arcount;
};
-struct dns_reply{
- struct dns_header h;
- struct dns_query q;
- struct resource_record *head;
+struct rk_dns_reply{
+ struct rk_dns_header h;
+ struct rk_dns_query q;
+ struct rk_resource_record *head;
};
-struct dns_reply* ROKEN_LIB_FUNCTION
- dns_lookup(const char *, const char *);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rk_dns_reply* ROKEN_LIB_FUNCTION
+ rk_dns_lookup(const char *, const char *);
void ROKEN_LIB_FUNCTION
- dns_free_data(struct dns_reply *);
+ rk_dns_free_data(struct rk_dns_reply *);
int ROKEN_LIB_FUNCTION
- dns_string_to_type(const char *name);
+ rk_dns_string_to_type(const char *name);
const char *ROKEN_LIB_FUNCTION
- dns_type_to_string(int type);
+ rk_dns_type_to_string(int type);
void ROKEN_LIB_FUNCTION
- dns_srv_order(struct dns_reply*);
+ rk_dns_srv_order(struct rk_dns_reply*);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* __RESOLVE_H__ */
#include <util.h>
#endif
+#ifdef STREAMSPTY
+#include <stropts.h>
+#endif /* STREAMPTY */
+
#include "roken.h"
#include <getarg.h>
if(openpty(&master, &slave, line, 0, 0) == 0)
return;
#endif /* HAVE_OPENPTY .... */
+#ifdef STREAMSPTY
+ {
+ char *clone[] = {
+ "/dev/ptc",
+ "/dev/ptmx",
+ "/dev/ptm",
+ "/dev/ptym/clone",
+ NULL
+ };
+ char **q;
+
+ for(q = clone; *q; q++){
+ master = open(*q, O_RDWR);
+ if(master >= 0){
+#ifdef HAVE_GRANTPT
+ grantpt(master);
+#endif
+#ifdef HAVE_UNLOCKPT
+ unlockpt(master);
+#endif
+ strlcpy(line, ptsname(master), sizeof(line));
+ slave = open(line, O_RDWR);
+ if (slave < 0)
+ errx(1, "failed to open slave when using %s", q);
+ ioctl(slave, I_PUSH, "ptem");
+ ioctl(slave, I_PUSH, "ldterm");
+
+ return;
+ }
+ }
+ }
+#endif /* STREAMSPTY */
+
/* more cases, like open /dev/ptmx, etc */
exit(77);
parse_configuration(argv[0]);
argv += 1;
- argc -= 1;
open_pty();
#endif
#endif
+#define simple_execve rk_simple_execve
int ROKEN_LIB_FUNCTION
simple_execve(const char*, char*const[], char*const[]);
+#define simple_execve_timed rk_simple_execve_timed
int ROKEN_LIB_FUNCTION
simple_execve_timed(const char *, char *const[],
char *const [], time_t (*)(void *),
void *, time_t);
+
+#define simple_execvp rk_simple_execvp
int ROKEN_LIB_FUNCTION
simple_execvp(const char*, char *const[]);
+#define simple_execvp_timed rk_simple_execvp_timed
int ROKEN_LIB_FUNCTION
simple_execvp_timed(const char *, char *const[],
time_t (*)(void *), void *, time_t);
+
+#define simple_execlp rk_simple_execlp
int ROKEN_LIB_FUNCTION
simple_execlp(const char*, ...);
+#define simple_execle rk_simple_execle
int ROKEN_LIB_FUNCTION
simple_execle(const char*, ...);
-int ROKEN_LIB_FUNCTION
-simple_execl(const char *file, ...);
-
+#define wait_for_process rk_wait_for_process
int ROKEN_LIB_FUNCTION
wait_for_process(pid_t);
+#define wait_for_process_timed rk_wait_for_process_timed
int ROKEN_LIB_FUNCTION
wait_for_process_timed(pid_t, time_t (*)(void *),
void *, time_t);
+#define pipe_execv rk_pipe_execv
int ROKEN_LIB_FUNCTION
pipe_execv(FILE**, FILE**, FILE**, const char*, ...);
+#define print_version rk_print_version
void ROKEN_LIB_FUNCTION
print_version(const char *);
+#define eread rk_eread
ssize_t ROKEN_LIB_FUNCTION
eread (int fd, void *buf, size_t nbytes);
+#define ewrite rk_ewrite
ssize_t ROKEN_LIB_FUNCTION
ewrite (int fd, const void *buf, size_t nbytes);
struct hostent;
+#define hostent_find_fqdn rk_hostent_find_fqdn
const char * ROKEN_LIB_FUNCTION
hostent_find_fqdn (const struct hostent *);
+#define esetenv rk_esetenv
void ROKEN_LIB_FUNCTION
esetenv(const char *, const char *, int);
+#define socket_set_address_and_port rk_socket_set_address_and_port
void ROKEN_LIB_FUNCTION
socket_set_address_and_port (struct sockaddr *, const void *, int);
+#define socket_addr_size rk_socket_addr_size
size_t ROKEN_LIB_FUNCTION
socket_addr_size (const struct sockaddr *);
+#define socket_set_any rk_socket_set_any
void ROKEN_LIB_FUNCTION
socket_set_any (struct sockaddr *, int);
+#define socket_sockaddr_size rk_socket_sockaddr_size
size_t ROKEN_LIB_FUNCTION
socket_sockaddr_size (const struct sockaddr *);
+#define socket_get_address rk_socket_get_address
void * ROKEN_LIB_FUNCTION
socket_get_address (struct sockaddr *);
+#define socket_get_port rk_socket_get_port
int ROKEN_LIB_FUNCTION
socket_get_port (const struct sockaddr *);
+#define socket_set_port rk_socket_set_port
void ROKEN_LIB_FUNCTION
socket_set_port (struct sockaddr *, int);
+#define socket_set_portrange rk_socket_set_portrange
void ROKEN_LIB_FUNCTION
socket_set_portrange (int, int, int);
+#define socket_set_debug rk_socket_set_debug
void ROKEN_LIB_FUNCTION
socket_set_debug (int);
+#define socket_set_tos rk_socket_set_tos
void ROKEN_LIB_FUNCTION
socket_set_tos (int, int);
+#define socket_set_reuseaddr rk_socket_set_reuseaddr
void ROKEN_LIB_FUNCTION
socket_set_reuseaddr (int, int);
+#define socket_set_ipv6only rk_socket_set_ipv6only
void ROKEN_LIB_FUNCTION
socket_set_ipv6only (int, int);
+#define vstrcollect rk_vstrcollect
char ** ROKEN_LIB_FUNCTION
vstrcollect(va_list *ap);
+#define strcollect rk_strcollect
char ** ROKEN_LIB_FUNCTION
strcollect(char *first, ...);
+#define timevalfix rk_timevalfix
void ROKEN_LIB_FUNCTION
timevalfix(struct timeval *t1);
+#define timevaladd rk_timevaladd
void ROKEN_LIB_FUNCTION
timevaladd(struct timeval *t1, const struct timeval *t2);
+#define timevalsub rk_timevalsub
void ROKEN_LIB_FUNCTION
timevalsub(struct timeval *t1, const struct timeval *t2);
+#define pid_file_write rk_pid_file_write
char *ROKEN_LIB_FUNCTION
pid_file_write (const char *progname);
+#define pid_file_delete rk_pid_file_delete
void ROKEN_LIB_FUNCTION
pid_file_delete (char **);
+#define read_environment rk_read_environment
int ROKEN_LIB_FUNCTION
read_environment(const char *file, char ***env);
+#define free_environment rk_free_environment
void ROKEN_LIB_FUNCTION
free_environment(char **);
+#define warnerr rk_warnerr
void ROKEN_LIB_FUNCTION
-warnerr(int doerrno, const char *fmt, va_list ap)
+rk_warnerr(int doerrno, const char *fmt, va_list ap)
__attribute__ ((format (printf, 2, 0)));
void * ROKEN_LIB_FUNCTION
#else
#include <time.h>
#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifndef HAVE_PUTENV
+#define putenv rk_putenv
int ROKEN_LIB_FUNCTION putenv(const char *);
#endif
#if !defined(HAVE_SETENV) || defined(NEED_SETENV_PROTO)
+#ifndef HAVE_SETENV
+#define setenv rk_setenv
+#endif
int ROKEN_LIB_FUNCTION setenv(const char *, const char *, int);
#endif
#if !defined(HAVE_UNSETENV) || defined(NEED_UNSETENV_PROTO)
+#ifndef HAVE_UNSETENV
+#define unsetenv rk_unsetenv
+#endif
void ROKEN_LIB_FUNCTION unsetenv(const char *);
#endif
#if !defined(HAVE_GETUSERSHELL) || defined(NEED_GETUSERSHELL_PROTO)
+#ifndef HAVE_GETUSERSHELL
+#define getusershell rk_getusershell
+#define endusershell rk_endusershell
+#endif
char * ROKEN_LIB_FUNCTION getusershell(void);
void ROKEN_LIB_FUNCTION endusershell(void);
#endif
#if !defined(HAVE_SNPRINTF) || defined(NEED_SNPRINTF_PROTO)
-int ROKEN_LIB_FUNCTION snprintf (char *, size_t, const char *, ...)
+#ifndef HAVE_SNPRINTF
+#define snprintf rk_snprintf
+#endif
+int ROKEN_LIB_FUNCTION
+ rk_snprintf (char *, size_t, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
#endif
#if !defined(HAVE_VSNPRINTF) || defined(NEED_VSNPRINTF_PROTO)
+#ifndef HAVE_VSNPRINTF
+#define vsnprintf rk_vsnprintf
+#endif
int ROKEN_LIB_FUNCTION
- vsnprintf (char *, size_t, const char *, va_list)
+ rk_vsnprintf (char *, size_t, const char *, va_list)
__attribute__((format (printf, 3, 0)));
#endif
#if !defined(HAVE_ASPRINTF) || defined(NEED_ASPRINTF_PROTO)
+#ifndef HAVE_ASPRINTF
+#define asprintf rk_asprintf
+#endif
int ROKEN_LIB_FUNCTION
- asprintf (char **, const char *, ...)
+ rk_asprintf (char **, const char *, ...)
__attribute__ ((format (printf, 2, 3)));
#endif
#if !defined(HAVE_VASPRINTF) || defined(NEED_VASPRINTF_PROTO)
+#ifndef HAVE_VASPRINTF
+#define vasprintf rk_vasprintf
+#endif
int ROKEN_LIB_FUNCTION
- vasprintf (char **, const char *, va_list)
+ rk_vasprintf (char **, const char *, va_list)
__attribute__((format (printf, 2, 0)));
#endif
#if !defined(HAVE_ASNPRINTF) || defined(NEED_ASNPRINTF_PROTO)
+#ifndef HAVE_ASNPRINTF
+#define asnprintf rk_asnprintf
+#endif
int ROKEN_LIB_FUNCTION
- asnprintf (char **, size_t, const char *, ...)
+ rk_asnprintf (char **, size_t, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
#endif
#if !defined(HAVE_VASNPRINTF) || defined(NEED_VASNPRINTF_PROTO)
+#ifndef HAVE_VASNPRINTF
+#define vasnprintf rk_vasnprintf
+#endif
int ROKEN_LIB_FUNCTION
vasnprintf (char **, size_t, const char *, va_list)
__attribute__((format (printf, 3, 0)));
#endif
#ifndef HAVE_STRDUP
+#define strdup rk_strdup
char * ROKEN_LIB_FUNCTION strdup(const char *);
#endif
#if !defined(HAVE_STRNDUP) || defined(NEED_STRNDUP_PROTO)
+#ifndef HAVE_STRNDUP
+#define strndup rk_strndup
+#endif
char * ROKEN_LIB_FUNCTION strndup(const char *, size_t);
#endif
#ifndef HAVE_STRLWR
+#define strlwr rk_strlwr
char * ROKEN_LIB_FUNCTION strlwr(char *);
#endif
#ifndef HAVE_STRNLEN
+#define strnlen rk_strnlen
size_t ROKEN_LIB_FUNCTION strnlen(const char*, size_t);
#endif
#if !defined(HAVE_STRSEP) || defined(NEED_STRSEP_PROTO)
+#ifndef HAVE_STRSEP
+#define strsep rk_strsep
+#endif
char * ROKEN_LIB_FUNCTION strsep(char**, const char*);
#endif
#if !defined(HAVE_STRSEP_COPY) || defined(NEED_STRSEP_COPY_PROTO)
+#ifndef HAVE_STRSEP_COPY
+#define strsep_copy rk_strsep_copy
+#endif
ssize_t ROKEN_LIB_FUNCTION strsep_copy(const char**, const char*, char*, size_t);
#endif
#ifndef HAVE_STRCASECMP
+#define strcasecmp rk_strcasecmp
int ROKEN_LIB_FUNCTION strcasecmp(const char *, const char *);
#endif
#endif
#ifndef HAVE_STRUPR
+#define strupr rk_strupr
char * ROKEN_LIB_FUNCTION strupr(char *);
#endif
#ifndef HAVE_STRLCPY
+#define strlcpy rk_strlcpy
size_t ROKEN_LIB_FUNCTION strlcpy (char *, const char *, size_t);
#endif
#ifndef HAVE_STRLCAT
+#define strlcat rk_strlcat
size_t ROKEN_LIB_FUNCTION strlcat (char *, const char *, size_t);
#endif
#ifndef HAVE_GETDTABLESIZE
+#define getdtablesize rk_getdtablesize
int ROKEN_LIB_FUNCTION getdtablesize(void);
#endif
#if !defined(HAVE_STRERROR) && !defined(strerror)
+#define strerror rk_strerror
char * ROKEN_LIB_FUNCTION strerror(int);
#endif
#if !defined(HAVE_HSTRERROR) || defined(NEED_HSTRERROR_PROTO)
+#ifndef HAVE_HSTRERROR
+#define hstrerror rk_hstrerror
+#endif
/* This causes a fatal error under Psoriasis */
#if !(defined(SunOS) && (SunOS >= 50))
const char * ROKEN_LIB_FUNCTION hstrerror(int);
#endif
#if !defined(HAVE_INET_ATON) || defined(NEED_INET_ATON_PROTO)
+#ifndef HAVE_INET_ATON
+#define inet_aton rk_inet_aton
+#endif
int ROKEN_LIB_FUNCTION inet_aton(const char *, struct in_addr *);
#endif
#ifndef HAVE_INET_NTOP
+#define inet_ntop rk_inet_ntop
const char * ROKEN_LIB_FUNCTION
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#ifndef HAVE_INET_PTON
+#define inet_pton rk_inet_pton
int ROKEN_LIB_FUNCTION
inet_pton(int, const char *, void *);
#endif
#if !defined(HAVE_GETCWD)
+#define getcwd rk_getcwd
char* ROKEN_LIB_FUNCTION getcwd(char *, size_t);
#endif
const char * ROKEN_LIB_FUNCTION get_default_username (void);
#ifndef HAVE_SETEUID
+#define seteuid rk_seteuid
int ROKEN_LIB_FUNCTION seteuid(uid_t);
#endif
#ifndef HAVE_SETEGID
+#define setegid rk_setegid
int ROKEN_LIB_FUNCTION setegid(gid_t);
#endif
#ifndef HAVE_LSTAT
+#define lstat rk_lstat
int ROKEN_LIB_FUNCTION lstat(const char *, struct stat *);
#endif
#if !defined(HAVE_MKSTEMP) || defined(NEED_MKSTEMP_PROTO)
+#ifndef HAVE_MKSTEMP
+#define mkstemp rk_mkstemp
+#endif
int ROKEN_LIB_FUNCTION mkstemp(char *);
#endif
#ifndef HAVE_CGETENT
+#define cgetent rk_cgetent
+#define cgetstr rk_cgetstr
int ROKEN_LIB_FUNCTION cgetent(char **, char **, const char *);
int ROKEN_LIB_FUNCTION cgetstr(char *, const char *, char **);
#endif
#ifndef HAVE_INITGROUPS
+#define initgroups rk_initgroups
int ROKEN_LIB_FUNCTION initgroups(const char *, gid_t);
#endif
#ifndef HAVE_FCHOWN
+#define fchown rk_fchown
int ROKEN_LIB_FUNCTION fchown(int, uid_t, gid_t);
#endif
#if !defined(HAVE_DAEMON) || defined(NEED_DAEMON_PROTO)
-int ROKEN_LIB_FUNCTION daemon(int, int);
+#ifndef HAVE_DAEMON
+#define daemon rk_daemon
#endif
-
-#ifndef HAVE_INNETGR
-int ROKEN_LIB_FUNCTION innetgr(const char *, const char *,
- const char *, const char *);
+int ROKEN_LIB_FUNCTION daemon(int, int);
#endif
#ifndef HAVE_CHOWN
+#define chown rk_chown
int ROKEN_LIB_FUNCTION chown(const char *, uid_t, gid_t);
#endif
#ifndef HAVE_RCMD
+#define rcmd rk_rcmd
int ROKEN_LIB_FUNCTION
rcmd(char **, unsigned short, const char *,
const char *, const char *, int *);
#endif
#if !defined(HAVE_INNETGR) || defined(NEED_INNETGR_PROTO)
+#ifndef HAVE_INNETGR
+#define innetgr rk_innetgr
+#endif
int ROKEN_LIB_FUNCTION innetgr(const char*, const char*,
const char*, const char*);
#endif
#ifndef HAVE_IRUSEROK
+#define iruserok rk_iruserok
int ROKEN_LIB_FUNCTION iruserok(unsigned, int,
const char *, const char *);
#endif
#if !defined(HAVE_GETHOSTNAME) || defined(NEED_GETHOSTNAME_PROTO)
+#ifndef HAVE_GETHOSTNAME
+#define gethostname rk_gethostname
+#endif
int ROKEN_LIB_FUNCTION gethostname(char *, int);
#endif
#ifndef HAVE_WRITEV
+#define writev rk_writev
ssize_t ROKEN_LIB_FUNCTION
writev(int, const struct iovec *, int);
#endif
#ifndef HAVE_READV
+#define readv rk_readv
ssize_t ROKEN_LIB_FUNCTION
readv(int, const struct iovec *, int);
#endif
-#ifndef HAVE_MKSTEMP
-int ROKEN_LIB_FUNCTION
-mkstemp(char *);
-#endif
-
#ifndef HAVE_PIDFILE
+#define pidfile rk_pidfile
void ROKEN_LIB_FUNCTION pidfile (const char*);
#endif
#ifndef HAVE_BSWAP32
+#define bswap32 rk_bswap32
unsigned int ROKEN_LIB_FUNCTION bswap32(unsigned int);
#endif
#ifndef HAVE_BSWAP16
+#define bswap16 rk_bswap16
unsigned short ROKEN_LIB_FUNCTION bswap16(unsigned short);
#endif
#define LOCK_UN 8 /* Unlock */
#endif
+#define flock rk_flock
int flock(int fd, int operation);
#endif /* HAVE_FLOCK */
int ROKEN_LIB_FUNCTION get_window_size(int fd, struct winsize *);
#ifndef HAVE_VSYSLOG
+#define vsyslog rk_vsyslog
void ROKEN_LIB_FUNCTION vsyslog(int, const char *, va_list);
#endif
#endif
#ifndef HAVE_GETIPNODEBYNAME
+#define getipnodebyname rk_getipnodebyname
struct hostent * ROKEN_LIB_FUNCTION
getipnodebyname (const char *, int, int, int *);
#endif
#ifndef HAVE_GETIPNODEBYADDR
+#define getipnodebyaddr rk_getipnodebyaddr
struct hostent * ROKEN_LIB_FUNCTION
getipnodebyaddr (const void *, size_t, int, int *);
#endif
#ifndef HAVE_FREEHOSTENT
+#define freehostent rk_freehostent
void ROKEN_LIB_FUNCTION
freehostent (struct hostent *);
#endif
#ifndef HAVE_COPYHOSTENT
+#define copyhostent rk_copyhostent
struct hostent * ROKEN_LIB_FUNCTION
copyhostent (const struct hostent *);
#endif
#endif
#ifndef HAVE_GETADDRINFO
+#define getaddrinfo rk_getaddrinfo
int ROKEN_LIB_FUNCTION
getaddrinfo(const char *,
const char *,
#endif
#ifndef HAVE_GETNAMEINFO
+#define getnameinfo rk_getnameinfo
int ROKEN_LIB_FUNCTION
getnameinfo(const struct sockaddr *, socklen_t,
char *, size_t,
#endif
#ifndef HAVE_FREEADDRINFO
+#define freeaddrinfo rk_freeaddrinfo
void ROKEN_LIB_FUNCTION
freeaddrinfo(struct addrinfo *);
#endif
#ifndef HAVE_GAI_STRERROR
+#define gai_strerror rk_gai_strerror
const char * ROKEN_LIB_FUNCTION
gai_strerror(int);
#endif
roken_getaddrinfo_hostspec2(const char *, int, int, struct addrinfo **);
#ifndef HAVE_STRFTIME
+#define strftime rk_strftime
size_t ROKEN_LIB_FUNCTION
strftime (char *, size_t, const char *, const struct tm *);
#endif
#ifndef HAVE_STRPTIME
+#define strptime rk_strptime
char * ROKEN_LIB_FUNCTION
strptime (const char *, const char *, struct tm *);
#endif
#ifndef HAVE_EMALLOC
+#define emalloc rk_emalloc
void * ROKEN_LIB_FUNCTION emalloc (size_t);
#endif
#ifndef HAVE_ECALLOC
+#define ecalloc rk_ecalloc
void * ROKEN_LIB_FUNCTION ecalloc(size_t, size_t);
#endif
#ifndef HAVE_EREALLOC
+#define erealloc rk_erealloc
void * ROKEN_LIB_FUNCTION erealloc (void *, size_t);
#endif
#ifndef HAVE_ESTRDUP
+#define estrdup rk_estrdup
char * ROKEN_LIB_FUNCTION estrdup (const char *);
#endif
#endif
#ifndef HAVE_SETPROGNAME
+#define setprogname rk_setprogname
void ROKEN_LIB_FUNCTION setprogname(const char *);
#endif
#ifndef HAVE_GETPROGNAME
+#define getprogname rk_getprogname
const char * ROKEN_LIB_FUNCTION getprogname(void);
#endif
void ROKEN_LIB_FUNCTION mini_inetd (int);
#ifndef HAVE_LOCALTIME_R
+#define localtime_r rk_localtime_r
struct tm * ROKEN_LIB_FUNCTION
localtime_r(const time_t *, struct tm *);
#endif
#if !defined(HAVE_STRSVIS) || defined(NEED_STRSVIS_PROTO)
+#ifndef HAVE_STRSVIS
+#define strsvis rk_strsvis
+#endif
int ROKEN_LIB_FUNCTION
strsvis(char *, const char *, int, const char *);
#endif
#if !defined(HAVE_STRUNVIS) || defined(NEED_STRUNVIS_PROTO)
+#ifndef HAVE_STRUNVIS
+#define strunvis rk_strunvis
+#endif
int ROKEN_LIB_FUNCTION
strunvis(char *, const char *);
#endif
#if !defined(HAVE_STRVIS) || defined(NEED_STRVIS_PROTO)
+#ifndef HAVE_STRVIS
+#define strvis rk_strvis
+#endif
int ROKEN_LIB_FUNCTION
strvis(char *, const char *, int);
#endif
#if !defined(HAVE_STRVISX) || defined(NEED_STRVISX_PROTO)
+#ifndef HAVE_STRVISX
+#define strvisx rk_strvisx
+#endif
int ROKEN_LIB_FUNCTION
strvisx(char *, const char *, size_t, int);
#endif
#if !defined(HAVE_SVIS) || defined(NEED_SVIS_PROTO)
+#ifndef HAVE_SVIS
+#define svis rk_svis
+#endif
char * ROKEN_LIB_FUNCTION
svis(char *, int, int, int, const char *);
#endif
#if !defined(HAVE_UNVIS) || defined(NEED_UNVIS_PROTO)
+#ifndef HAVE_UNVIS
+#define unvis rk_unvis
+#endif
int ROKEN_LIB_FUNCTION
unvis(char *, int, int *, int);
#endif
#if !defined(HAVE_VIS) || defined(NEED_VIS_PROTO)
+#ifndef HAVE_VIS
+#define vis rk_vis
+#endif
char * ROKEN_LIB_FUNCTION
vis(char *, int, int, int);
#endif
#if !defined(HAVE_CLOSEFROM)
+#define closefrom rk_closefrom
int ROKEN_LIB_FUNCTION
closefrom(int);
#endif
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID ("$Id$");
-#endif
+
#include "roken.h"
#include "rtbl.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <signal.h>
#include "roken.h"
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdarg.h>
#include <stdlib.h>
#include "roken.h"
-#if !HAVE_DECL_ENVIRON
-extern char **environ;
-#endif
-
#define EX_NOEXEC 126
#define EX_NOTFOUND 127
free(argv);
return ret;
}
-
-int ROKEN_LIB_FUNCTION
-simple_execl(const char *file, ...)
-{
- va_list ap;
- char **argv;
- int ret;
-
- va_start(ap, file);
- argv = vstrcollect(&ap);
- va_end(ap);
- if(argv == NULL)
- return -1;
- ret = simple_execve(file, argv, environ);
- free(argv);
- return ret;
-}
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
#include <err.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdarg.h>
#include <stdlib.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <string.h>
#include <ctype.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <stdarg.h>
#include <stdlib.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <string.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <string.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <string.h>
#include <ctype.h>
*/
#if 1
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include "roken.h"
#ifndef _DIAGASSERT
#define _DIAGASSERT(X)
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-RCSID("$Id$");
-#endif
#include <unistd.h>
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
+
#include <config.h>
-RCSID("$Id$");
-#endif
+
#include "roken.h"
-#include "print_version.h"
+#include "version.h"
void
print_version(const char *progname)
{
- const char *package_list = VERSIONLIST;
+ const char *package_list = heimdal_version;
if(progname == NULL)
progname = getprogname();
int ostarter;
unsigned o = 0;
int old_cc;
- int cc;
for (i = 0; i < in_len;) {
- while (i < in_len && (cc = _wind_combining_class(in[i])) != 0) {
+ while (i < in_len && _wind_combining_class(in[i]) != 0) {
out[o++] = in[i++];
}
if (i < in_len) {
while (i < in_len) {
uint32_t comb;
uint32_t v[2];
+ int cc;
v[0] = out[ostarter];
v[1] = in[i];
return ret;
}
-static struct {
+const static struct {
const char *name;
wind_profile_flags flags;
} profiles[] = {
* SUCH DAMAGE.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include "windlocl.h"
RCSID("$Id$");
error_code NO_PROFILE, "No such profile"
error_code OVERRUN, "Buffer overrun"
error_code UNDERUN, "Buffer underrun"
-error_code LENGTH_NOT_MOD2, "Lenght not mod2"
-error_code LENGTH_NOT_MOD4, "Lenght not mod4"
+error_code LENGTH_NOT_MOD2, "Length not mod2"
+error_code LENGTH_NOT_MOD4, "Length not mod4"
error_code INVALID_UTF8, "Invalid UTF-8 combination in string"
error_code INVALID_UTF16, "Invalid UTF-16 combination in string"
error_code INVALID_UTF32, "Invalid UTF-32 combination in string"