From: Greg Hudson Date: Fri, 15 Feb 2019 16:59:06 +0000 (-0500) Subject: Modernize KRB-PRIV/KRB-SAFE/KRB-CRED functions X-Git-Tag: krb5-1.18-beta1~187 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F896%2Fhead;p=thirdparty%2Fkrb5.git Modernize KRB-PRIV/KRB-SAFE/KRB-CRED functions In krb5_mk_safe(), krb5_mk_priv(), krb5_mk_ncred(), krb5_rd_safe(), and krb5_rd_priv(), modify naming, formatting, and memory management to meet current standards. Add k5_privsafe helpers to generate replay data and addresses and to store replay records. For krb5_mk_ncred(), expand the contract of the encoding function to be similar to the other two krb5_mk functions, and use pointer aliases to reduce the number of copies required. --- diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index 15b7677f3a..a67eec1cfb 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -3310,20 +3310,20 @@ krb5_rd_error(krb5_context context, const krb5_data *enc_errbuf, * @param [in] context Library context * @param [in] auth_context Authentication context * @param [in] inbuf @c KRB-SAFE message to be parsed - * @param [out] outbuf Data parsed from @c KRB-SAFE message - * @param [out] outdata Replay data. Specify NULL if not needed + * @param [out] userdata_out Data parsed from @c KRB-SAFE message + * @param [out] rdata_out Replay data. Specify NULL if not needed * * This function parses a @c KRB-SAFE message, verifies its integrity, and - * stores its data into @a outbuf. + * stores its data into @a userdata_out. * - * @note The @a outdata argument is required if #KRB5_AUTH_CONTEXT_RET_TIME or - * #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in the @a auth_context. + * @note The @a rdata_out argument is required if #KRB5_AUTH_CONTEXT_RET_TIME + * or #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in the @a auth_context. * * @note @a auth_context must have a remote address set. This address will be - * used to verify the sender address in the KRB-SAFE message. If @a - * auth_context has a local address set, it will be used to verify the - * receiver address in the KRB-SAFE message if the message contains one. - * Both addresses must use type @c ADDRTYPE_ADDRPORT. + * used to verify the sender address in the KRB-SAFE message. If @a + * auth_context has a local address set, it will be used to verify the receiver + * address in the KRB-SAFE message if the message contains one. Both addresses + * must use type @c ADDRTYPE_ADDRPORT. * * If the #KRB5_AUTH_CONTEXT_DO_SEQUENCE flag is set in @a auth_context, the * sequence number of the KRB-SAFE message is checked against the remote @@ -3336,14 +3336,15 @@ krb5_rd_error(krb5_context context, const krb5_data *enc_errbuf, * (which is usually five minutes). * @li The message must not be a replayed message field in @a auth_context. * - * Use krb5_free_data_contents() to free @a outbuf when it is no longer needed. + * Use krb5_free_data_contents() to free @a userdata_out when it is no longer + * needed. * * @retval 0 Success; otherwise - Kerberos error codes */ krb5_error_code KRB5_CALLCONV krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, - const krb5_data *inbuf, krb5_data *outbuf, - krb5_replay_data *outdata); + const krb5_data *inbuf, krb5_data *userdata_out, + krb5_replay_data *rdata_out); /** * Process a @c KRB-PRIV message. @@ -3351,21 +3352,20 @@ krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, * @param [in] context Library context * @param [in] auth_context Authentication structure * @param [in] inbuf @c KRB-PRIV message to be parsed - * @param [out] outbuf Data parsed from @c KRB-PRIV message - * @param [out] outdata Replay data. Specify NULL if not needed + * @param [out] userdata_out Data parsed from @c KRB-PRIV message + * @param [out] rdata_out Replay data. Specify NULL if not needed * * This function parses a @c KRB-PRIV message, verifies its integrity, and - * stores its unencrypted data into @a outbuf. + * stores its unencrypted data into @a userdata_out. * - * @note If the #KRB5_AUTH_CONTEXT_RET_TIME or - * #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in @a auth_context, @a - * outdata is required. + * @note If the #KRB5_AUTH_CONTEXT_RET_TIME or #KRB5_AUTH_CONTEXT_RET_SEQUENCE + * flag is set in @a auth_context, @a rdata_out is required. * * @note @a auth_context must have a remote address set. This address will be - * used to verify the sender address in the KRB-PRIV message. If @a - * auth_context has a local address set, it will be used to verify the - * receiver address in the KRB-PRIV message if the message contains one. - * Both addresses must use type @c ADDRTYPE_ADDRPORT. + * used to verify the sender address in the KRB-PRIV message. If @a + * auth_context has a local address set, it will be used to verify the receiver + * address in the KRB-PRIV message if the message contains one. Both addresses + * must use type @c ADDRTYPE_ADDRPORT. * * If the #KRB5_AUTH_CONTEXT_DO_SEQUENCE flag is set in @a auth_context, the * sequence number of the KRB-SAFE message is checked against the remote @@ -3378,12 +3378,15 @@ krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, * (which is usually five minutes). * @li The message must not be a replayed message field in @a auth_context. * + * Use krb5_free_data_contents() to free @a userdata_out when it is no longer + * needed. + * * @retval 0 Success; otherwise - Kerberos error codes */ krb5_error_code KRB5_CALLCONV krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, - const krb5_data *inbuf, krb5_data *outbuf, - krb5_replay_data *outdata); + const krb5_data *inbuf, krb5_data *userdata_out, + krb5_replay_data *rdata_out); /** * Convert a string principal name to a krb5_principal structure. @@ -5245,8 +5248,8 @@ krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, * @param [in] context Library context * @param [in] auth_context Authentication context * @param [in] userdata User data in the message - * @param [out] outbuf Formatted @c KRB-SAFE buffer - * @param [out] outdata Replay data. Specify NULL if not needed + * @param [out] der_out Formatted @c KRB-SAFE buffer + * @param [out] rdata_out Replay data. Specify NULL if not needed * * This function creates an integrity protected @c KRB-SAFE message * using data supplied by the application. @@ -5268,19 +5271,20 @@ krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, * * If either #KRB5_AUTH_CONTEXT_DO_SEQUENCE or * #KRB5_AUTH_CONTEXT_RET_SEQUENCE is set, the @a auth_context local sequence - * number will be placed in @a outdata as its sequence number. + * number will be placed in @a rdata_out as its sequence number. * - * @note The @a outdata argument is required if #KRB5_AUTH_CONTEXT_RET_TIME or - * #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in the @a auth_context. + * @note The @a rdata_out argument is required if #KRB5_AUTH_CONTEXT_RET_TIME + * or #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in the @a auth_context. * - * Use krb5_free_data_contents() to free @a outbuf when it is no longer needed. + * Use krb5_free_data_contents() to free @a der_out when it is no longer + * needed. * * @retval 0 Success; otherwise - Kerberos error codes */ krb5_error_code KRB5_CALLCONV krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, - const krb5_data *userdata, krb5_data *outbuf, - krb5_replay_data *outdata); + const krb5_data *userdata, krb5_data *der_out, + krb5_replay_data *rdata_out); /** * Format a @c KRB-PRIV message. @@ -5288,8 +5292,8 @@ krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, * @param [in] context Library context * @param [in] auth_context Authentication context * @param [in] userdata User data for @c KRB-PRIV message - * @param [out] outbuf Formatted @c KRB-PRIV message - * @param [out] outdata Replay cache handle (NULL if not needed) + * @param [out] der_out Formatted @c KRB-PRIV message + * @param [out] rdata_out Replay cache handle (NULL if not needed) * * This function is similar to krb5_mk_safe(), but the message is encrypted and * integrity-protected, not just integrity-protected. @@ -5301,7 +5305,7 @@ krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, * * @note If the #KRB5_AUTH_CONTEXT_RET_TIME or * #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in @a auth_context, the @a - * outdata is required. + * rdata_out is required. * * @note The flags from @a auth_context specify whether sequence numbers or * timestamps will be used to identify the message. Valid values are: @@ -5312,14 +5316,14 @@ krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, * @a auth_context in replay cache. * @li #KRB5_AUTH_CONTEXT_RET_SEQUENCE - Use local sequence numbers from * @a auth_context as a sequence number - * in the encrypted message @a outbuf. + * in the encrypted message @a der_out. * * @retval 0 Success; otherwise - Kerberos error codes */ krb5_error_code KRB5_CALLCONV krb5_mk_priv(krb5_context context, krb5_auth_context auth_context, - const krb5_data *userdata, krb5_data *outbuf, - krb5_replay_data *outdata); + const krb5_data *userdata, krb5_data *der_out, + krb5_replay_data *rdata_out); /** * Client function for @c sendauth protocol. @@ -5437,15 +5441,15 @@ krb5_recvauth_version(krb5_context context, * * @param [in] context Library context * @param [in] auth_context Authentication context - * @param [in] ppcreds Null-terminated array of credentials - * @param [out] ppdata Encoded credentials - * @param [out] outdata Replay cache information (NULL if not needed) + * @param [in] creds Null-terminated array of credentials + * @param [out] der_out Encoded credentials + * @param [out] rdata_out Replay cache information (NULL if not needed) * - * This function takes an array of credentials @a ppcreds and formats - * a @c KRB-CRED message @a ppdata to pass to krb5_rd_cred(). + * This function takes an array of credentials @a creds and formats + * a @c KRB-CRED message @a der_out to pass to krb5_rd_cred(). * * @note If the #KRB5_AUTH_CONTEXT_RET_TIME or #KRB5_AUTH_CONTEXT_RET_SEQUENCE - * flag is set in @a auth_context, @a outdata is required. + * flag is set in @a auth_context, @a rdata_out is required. * * The message will be encrypted using the send subkey of @a auth_context if it * is present, or the session key otherwise. @@ -5461,17 +5465,17 @@ krb5_recvauth_version(krb5_context context, */ krb5_error_code KRB5_CALLCONV krb5_mk_ncred(krb5_context context, krb5_auth_context auth_context, - krb5_creds **ppcreds, krb5_data **ppdata, - krb5_replay_data *outdata); + krb5_creds **creds, krb5_data **der_out, + krb5_replay_data *rdata_out); /** * Format a @c KRB-CRED message for a single set of credentials. * * @param [in] context Library context * @param [in] auth_context Authentication context - * @param [in] pcreds Pointer to credentials - * @param [out] ppdata Encoded credentials - * @param [out] outdata Replay cache data (NULL if not needed) + * @param [in] creds Pointer to credentials + * @param [out] der_out Encoded credentials + * @param [out] rdata_out Replay cache data (NULL if not needed) * * This is a convenience function that calls krb5_mk_ncred() with a single set * of credentials. @@ -5487,33 +5491,33 @@ krb5_mk_ncred(krb5_context context, krb5_auth_context auth_context, */ krb5_error_code KRB5_CALLCONV krb5_mk_1cred(krb5_context context, krb5_auth_context auth_context, - krb5_creds *pcreds, krb5_data **ppdata, - krb5_replay_data *outdata); + krb5_creds *creds, krb5_data **der_out, + krb5_replay_data *rdata_out); /** * Read and validate a @c KRB-CRED message. * * @param [in] context Library context * @param [in] auth_context Authentication context - * @param [in] pcreddata @c KRB-CRED message - * @param [out] pppcreds Null-terminated array of forwarded credentials - * @param [out] outdata Replay data (NULL if not needed) + * @param [in] creddata @c KRB-CRED message + * @param [out] creds_out Null-terminated array of forwarded credentials + * @param [out] rdata_out Replay data (NULL if not needed) * - * @note The @a outdata argument is required if #KRB5_AUTH_CONTEXT_RET_TIME or - * #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in the @a auth_context.` + * @note The @a rdata_out argument is required if #KRB5_AUTH_CONTEXT_RET_TIME + * or #KRB5_AUTH_CONTEXT_RET_SEQUENCE flag is set in the @a auth_context.` * - * @a pcreddata will be decrypted using the receiving subkey if it is present - * in @a auth_context, or the session key if the receiving subkey is not - * present or fails to decrypt the message. + * @a creddata will be decrypted using the receiving subkey if it is present in + * @a auth_context, or the session key if the receiving subkey is not present + * or fails to decrypt the message. * - * Use krb5_free_tgt_creds() to free @a pppcreds when it is no longer needed. + * Use krb5_free_tgt_creds() to free @a creds_out when it is no longer needed. * * @retval 0 Success; otherwise - Kerberos error codes */ krb5_error_code KRB5_CALLCONV krb5_rd_cred(krb5_context context, krb5_auth_context auth_context, - krb5_data *pcreddata, krb5_creds ***pppcreds, - krb5_replay_data *outdata); + krb5_data *creddata, krb5_creds ***creds_out, + krb5_replay_data *rdata_out); /** * Get a forwarded TGT and format a @c KRB-CRED message. diff --git a/src/lib/krb5/krb/cleanup.h b/src/lib/krb5/krb/cleanup.h deleted file mode 100644 index 3a018330ab..0000000000 --- a/src/lib/krb5/krb/cleanup.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ - -#ifndef KRB5_CLEANUP -#define KRB5_CLEANUP - -struct cleanup { - void * arg; - void (*func)(void *); -}; - -#define CLEANUP_INIT(x) \ - struct cleanup cleanup_data[x]; \ - int cleanup_count = 0; - -#define CLEANUP_PUSH(x, y) \ - cleanup_data[cleanup_count].arg = x; \ - cleanup_data[cleanup_count].func = y; \ - cleanup_count++; - -#define CLEANUP_POP(x) \ - if ((--cleanup_count) && x && (cleanup_data[cleanup_count].func)) \ - cleanup_data[cleanup_count].func(cleanup_data[cleanup_count].arg); - -#define CLEANUP_DONE() \ - while(cleanup_count--) \ - if (cleanup_data[cleanup_count].func) \ - cleanup_data[cleanup_count].func(cleanup_data[cleanup_count].arg); - - -#endif diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps index a4a809b140..fc2a16ed5f 100644 --- a/src/lib/krb5/krb/deps +++ b/src/lib/krb5/krb/deps @@ -460,12 +460,13 @@ gen_save_subkey.so gen_save_subkey.po $(OUTPRE)gen_save_subkey.$(OBJEXT): \ get_creds.so get_creds.po $(OUTPRE)get_creds.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ - $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ - $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ - $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ - $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ - $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(COM_ERR_DEPS) $(srcdir)/../os/os-proto.h $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ fast.h get_creds.c int-proto.h get_etype_info.so get_etype_info.po $(OUTPRE)get_etype_info.$(OBJEXT): \ @@ -627,8 +628,8 @@ mk_cred.so mk_cred.po $(OUTPRE)mk_cred.$(OBJEXT): $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h auth_con.h cleanup.h \ - int-proto.h mk_cred.c + $(top_srcdir)/include/socket-utils.h auth_con.h int-proto.h \ + mk_cred.c mk_error.so mk_error.po $(OUTPRE)mk_error.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ @@ -649,7 +650,7 @@ mk_priv.so mk_priv.po $(OUTPRE)mk_priv.$(OBJEXT): $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h auth_con.h cleanup.h \ + $(top_srcdir)/include/socket-utils.h auth_con.h int-proto.h \ mk_priv.c mk_rep.so mk_rep.po $(OUTPRE)mk_rep.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ @@ -692,7 +693,7 @@ mk_safe.so mk_safe.po $(OUTPRE)mk_safe.$(OBJEXT): $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h auth_con.h cleanup.h \ + $(top_srcdir)/include/socket-utils.h auth_con.h int-proto.h \ mk_safe.c pac.so pac.po $(OUTPRE)pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ @@ -875,7 +876,7 @@ rd_cred.so rd_cred.po $(OUTPRE)rd_cred.$(OBJEXT): $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h auth_con.h cleanup.h \ + $(top_srcdir)/include/socket-utils.h auth_con.h int-proto.h \ rd_cred.c rd_error.so rd_error.po $(OUTPRE)rd_error.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ @@ -940,8 +941,8 @@ rd_safe.so rd_safe.po $(OUTPRE)rd_safe.$(OBJEXT): $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h auth_con.h cleanup.h \ - int-proto.h rd_safe.c + $(top_srcdir)/include/socket-utils.h auth_con.h int-proto.h \ + rd_safe.c recvauth.so recvauth.po $(OUTPRE)recvauth.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 978354848e..4464a1344e 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -143,6 +143,30 @@ krb5int_validate_times(krb5_context, krb5_ticket_times *); krb5_error_code krb5int_copy_authdatum(krb5_context, const krb5_authdata *, krb5_authdata **); +/* Set replay data fields in rdata and caller_rdata according to the flags in + * authcon. */ +krb5_error_code +k5_privsafe_gen_rdata(krb5_context context, krb5_auth_context authcon, + krb5_replay_data *rdata, krb5_replay_data *caller_rdata); + +/* + * Set *local_out and *remote_out to addresses based on authcon. The resulting + * pointers should not be freed, but addresses may be placed into *lstorage and + * *rstorage which the caller must free, even on error. + */ +krb5_error_code +k5_privsafe_gen_addrs(krb5_context context, krb5_auth_context authcon, + krb5_address *lstorage, krb5_address *rstorage, + krb5_address **local_out, krb5_address **remote_out); + +/* If the DO_TIME flag is set in authcon, store a replay record. If check_time + * is true, also check that the timestamp is within clock skew. */ +krb5_error_code +k5_privsafe_check_replay(krb5_context context, krb5_auth_context authcon, + krb5_address *addr, const char *uniq, + const krb5_replay_data *rdata, + krb5_boolean check_time); + krb5_boolean k5_privsafe_check_seqnum(krb5_context ctx, krb5_auth_context ac, krb5_ui_4 in_seq); diff --git a/src/lib/krb5/krb/mk_cred.c b/src/lib/krb5/krb/mk_cred.c index 7616c3a7a9..003a0fdbaa 100644 --- a/src/lib/krb5/krb/mk_cred.c +++ b/src/lib/krb5/krb/mk_cred.c @@ -1,308 +1,225 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/mk_cred.c - definition of krb5_mk_ncred(), krb5_mk_1cred() */ /* - * NAME - * cred.c + * Copyright (C) 2019 by the Massachusetts Institute of Technology. + * All rights reserved. * - * DESCRIPTION - * Provide an interface to assemble and disassemble krb5_cred - * structures. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" #include "int-proto.h" -#include "cleanup.h" #include "auth_con.h" -#include /* NULL */ -#include /* malloc */ -#include /* ENOMEM */ - -/*-------------------- encrypt_credencpart --------------------*/ - -/* - * encrypt the enc_part of krb5_cred - */ +/* Encrypt the enc_part of krb5_cred. key may be NULL to use the unencrypted + * KRB-CRED form (RFC 6448). */ static krb5_error_code -encrypt_credencpart(krb5_context context, krb5_cred_enc_part *pcredpart, - krb5_key pkey, krb5_enc_data *pencdata) +encrypt_credencpart(krb5_context context, krb5_cred_enc_part *encpart, + krb5_key key, krb5_enc_data *encdata_out) { - krb5_error_code retval; - krb5_data * scratch; - - /* start by encoding to-be-encrypted part of the message */ - if ((retval = encode_krb5_enc_cred_part(pcredpart, &scratch))) - return retval; - - /* - * If the keyblock is NULL, just copy the data from the encoded - * data to the ciphertext area. - */ - if (pkey == NULL) { - pencdata->ciphertext.data = scratch->data; - pencdata->ciphertext.length = scratch->length; - free(scratch); + krb5_error_code ret; + krb5_data *der_enccred; + + /* Start by encoding to-be-encrypted part of the message. */ + ret = encode_krb5_enc_cred_part(encpart, &der_enccred); + if (ret) + return ret; + + if (key == NULL) { + /* Just copy the encoded data to the ciphertext area. */ + encdata_out->enctype = ENCTYPE_NULL; + encdata_out->ciphertext = *der_enccred; + free(der_enccred); return 0; } - /* call the encryption routine */ - retval = k5_encrypt_keyhelper(context, pkey, - KRB5_KEYUSAGE_KRB_CRED_ENCPART, scratch, - pencdata); + ret = k5_encrypt_keyhelper(context, key, KRB5_KEYUSAGE_KRB_CRED_ENCPART, + der_enccred, encdata_out); - memset(scratch->data, 0, scratch->length); - krb5_free_data(context, scratch); - - return retval; + zap(der_enccred->data, der_enccred->length); + krb5_free_data(context, der_enccred); + return ret; } -/*----------------------- krb5_mk_ncred_basic -----------------------*/ - +/* + * Marshal a KRB-CRED message into der_out, encrypted with key (or unencrypted + * if key is NULL). Use the timestamp and sequence number from rdata and the + * addresses from local_addr and remote_addr (either of which may be NULL). + * der_out should be freed by the caller when finished. + */ static krb5_error_code -krb5_mk_ncred_basic(krb5_context context, - krb5_creds **ppcreds, krb5_int32 nppcreds, - krb5_key key, krb5_replay_data *replaydata, - krb5_address *local_addr, krb5_address *remote_addr, - krb5_cred *pcred) +create_krbcred(krb5_context context, krb5_creds **creds, krb5_key key, + const krb5_replay_data *rdata, krb5_address *local_addr, + krb5_address *remote_addr, krb5_data **der_out) { - krb5_cred_enc_part credenc; - krb5_error_code retval; - size_t size; - int i; - - credenc.magic = KV5M_CRED_ENC_PART; - - credenc.s_address = 0; - credenc.r_address = 0; - if (local_addr) krb5_copy_addr(context, local_addr, &credenc.s_address); - if (remote_addr) krb5_copy_addr(context, remote_addr, &credenc.r_address); - - credenc.nonce = replaydata->seq; - credenc.usec = replaydata->usec; - credenc.timestamp = replaydata->timestamp; - - /* Get memory for creds and initialize it */ - size = sizeof(krb5_cred_info *) * (nppcreds + 1); - credenc.ticket_info = (krb5_cred_info **) calloc(1, size); - if (credenc.ticket_info == NULL) - return ENOMEM; - - /* - * For each credential in the list, initialize a cred info - * structure and copy the ticket into the ticket list. - */ - for (i = 0; i < nppcreds; i++) { - credenc.ticket_info[i] = calloc(1, sizeof(krb5_cred_info)); - if (credenc.ticket_info[i] == NULL) { - retval = ENOMEM; - goto cleanup; - } - credenc.ticket_info[i+1] = NULL; - - credenc.ticket_info[i]->magic = KV5M_CRED_INFO; - credenc.ticket_info[i]->times = ppcreds[i]->times; - credenc.ticket_info[i]->flags = ppcreds[i]->ticket_flags; - - if ((retval = decode_krb5_ticket(&ppcreds[i]->ticket, - &pcred->tickets[i]))) - goto cleanup; - - if ((retval = krb5_copy_keyblock(context, &ppcreds[i]->keyblock, - &credenc.ticket_info[i]->session))) - goto cleanup; - - if ((retval = krb5_copy_principal(context, ppcreds[i]->client, - &credenc.ticket_info[i]->client))) - goto cleanup; - - if ((retval = krb5_copy_principal(context, ppcreds[i]->server, - &credenc.ticket_info[i]->server))) + krb5_error_code ret; + krb5_cred_enc_part credenc; + krb5_cred cred; + krb5_ticket **tickets = NULL; + krb5_cred_info **ticket_info = NULL, *tinfos = NULL; + krb5_enc_data enc; + size_t i, ncreds; + + *der_out = NULL; + memset(&enc, 0, sizeof(enc)); + + for (ncreds = 0; creds[ncreds] != NULL; ncreds++); + + tickets = k5calloc(ncreds + 1, sizeof(*tickets), &ret); + if (tickets == NULL) + goto cleanup; + + ticket_info = k5calloc(ncreds + 1, sizeof(*ticket_info), &ret); + if (ticket_info == NULL) + goto cleanup; + + tinfos = k5calloc(ncreds, sizeof(*tinfos), &ret); + if (tinfos == NULL) + goto cleanup; + + /* For each credential in the list, decode the ticket and create a cred + * info structure using alias pointers. */ + for (i = 0; i < ncreds; i++) { + ret = decode_krb5_ticket(&creds[i]->ticket, &tickets[i]); + if (ret) goto cleanup; - if ((retval = krb5_copy_addresses(context, ppcreds[i]->addresses, - &credenc.ticket_info[i]->caddrs))) - goto cleanup; + tinfos[i].magic = KV5M_CRED_INFO; + tinfos[i].times = creds[i]->times; + tinfos[i].flags = creds[i]->ticket_flags; + tinfos[i].session = &creds[i]->keyblock; + tinfos[i].client = creds[i]->client; + tinfos[i].server = creds[i]->server; + tinfos[i].caddrs = creds[i]->addresses; + ticket_info[i] = &tinfos[i]; } - /* - * NULL terminate the lists. - */ - pcred->tickets[i] = NULL; - - /* encrypt the credential encrypted part */ - retval = encrypt_credencpart(context, &credenc, key, &pcred->enc_part); + /* Encrypt the credential encrypted part. */ + credenc.magic = KV5M_CRED_ENC_PART; + credenc.s_address = local_addr; + credenc.r_address = remote_addr; + credenc.nonce = rdata->seq; + credenc.usec = rdata->usec; + credenc.timestamp = rdata->timestamp; + credenc.ticket_info = ticket_info; + ret = encrypt_credencpart(context, &credenc, key, &enc); + if (ret) + goto cleanup; + + /* Encode the KRB-CRED message. */ + cred.magic = KV5M_CRED; + cred.tickets = tickets; + cred.enc_part = enc; + ret = encode_krb5_cred(&cred, der_out); + if (ret) + goto cleanup; cleanup: - krb5_free_cred_enc_part(context, &credenc); - return retval; + krb5_free_tickets(context, tickets); + krb5_free_data_contents(context, &enc.ciphertext); + free(tinfos); + free(ticket_info); + return ret; } -/*----------------------- krb5_mk_ncred -----------------------*/ - -/* - * This functions takes as input an array of krb5_credentials, and - * outputs an encoded KRB_CRED message suitable for krb5_rd_cred - */ krb5_error_code KRB5_CALLCONV -krb5_mk_ncred(krb5_context context, krb5_auth_context auth_context, - krb5_creds **ppcreds, krb5_data **ppdata, - krb5_replay_data *outdata) +krb5_mk_ncred(krb5_context context, krb5_auth_context authcon, + krb5_creds **creds, krb5_data **der_out, + krb5_replay_data *rdata_out) { - krb5_address * premote_fulladdr = NULL; - krb5_address * plocal_fulladdr = NULL; - krb5_address remote_fulladdr; - krb5_address local_fulladdr; - krb5_error_code retval; - krb5_key key; - krb5_replay_data replaydata; - krb5_cred * pcred; - krb5_int32 ncred; - krb5_boolean increased_sequence = FALSE; + krb5_error_code ret; + krb5_key key; + krb5_replay_data rdata; + krb5_data *der_krbcred = NULL; + krb5_address *local_addr, *remote_addr, lstorage, rstorage; - local_fulladdr.contents = 0; - remote_fulladdr.contents = 0; - memset(&replaydata, 0, sizeof(krb5_replay_data)); + *der_out = NULL; + memset(&lstorage, 0, sizeof(lstorage)); + memset(&rstorage, 0, sizeof(rstorage)); - if (ppcreds == NULL) + if (creds == NULL) return KRB5KRB_AP_ERR_BADADDR; - /* - * Allocate memory for a NULL terminated list of tickets. - */ - for (ncred = 0; ppcreds[ncred]; ncred++) - ; - - if ((pcred = (krb5_cred *)calloc(1, sizeof(krb5_cred))) == NULL) - return ENOMEM; - - if ((pcred->tickets - = (krb5_ticket **)calloc((size_t)ncred+1, - sizeof(krb5_ticket *))) == NULL) { - retval = ENOMEM; - goto error; - } - - /* Get keyblock */ - if ((key = auth_context->send_subkey) == NULL) - key = auth_context->key; - - /* Get replay info */ - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->rcache == NULL)) { - retval = KRB5_RC_REQUIRED; - goto error; - } - - if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) - && (outdata == NULL)) { - /* Need a better error */ - retval = KRB5_RC_REQUIRED; - goto error; - } - - if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, - &replaydata.usec))) - goto error; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { - outdata->timestamp = replaydata.timestamp; - outdata->usec = replaydata.usec; - } - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { - replaydata.seq = auth_context->local_seq_number++; - increased_sequence = TRUE; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) - outdata->seq = replaydata.seq; - } - - if (auth_context->local_addr) { - if (auth_context->local_port) { - if ((retval = krb5_make_fulladdr(context, auth_context->local_addr, - auth_context->local_port, - &local_fulladdr))) - goto error; - plocal_fulladdr = &local_fulladdr; - } else { - plocal_fulladdr = auth_context->local_addr; - } - } - - if (auth_context->remote_addr) { - if (auth_context->remote_port) { - if ((retval = krb5_make_fulladdr(context,auth_context->remote_addr, - auth_context->remote_port, - &remote_fulladdr))) - goto error; - premote_fulladdr = &remote_fulladdr; - } else { - premote_fulladdr = auth_context->remote_addr; - } - } - - /* Setup creds structure */ - if ((retval = krb5_mk_ncred_basic(context, ppcreds, ncred, key, - &replaydata, plocal_fulladdr, - premote_fulladdr, pcred))) { - goto error; + ret = k5_privsafe_gen_rdata(context, authcon, &rdata, rdata_out); + if (ret) + goto cleanup; + /* Historically we always set the timestamp, so keep doing that. */ + if (rdata.timestamp == 0) { + ret = krb5_us_timeofday(context, &rdata.timestamp, &rdata.usec); + if (ret) + goto cleanup; } - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { - krb5_donot_replay replay; + ret = k5_privsafe_gen_addrs(context, authcon, &lstorage, &rstorage, + &local_addr, &remote_addr); + if (ret) + goto cleanup; - if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, - "_forw", &replay.client))) - goto error; - - replay.server = ""; /* XXX */ - replay.msghash = NULL; - replay.cusec = replaydata.usec; - replay.ctime = replaydata.timestamp; - if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { - /* should we really error out here? XXX */ - free(replay.client); - goto error; - } - free(replay.client); - } + key = (authcon->send_subkey != NULL) ? authcon->send_subkey : authcon->key; + ret = create_krbcred(context, creds, key, &rdata, local_addr, remote_addr, + &der_krbcred); + if (ret) + goto cleanup; - /* Encode creds structure */ - retval = encode_krb5_cred(pcred, ppdata); + ret = k5_privsafe_check_replay(context, authcon, authcon->local_addr, + "_forw", &rdata, FALSE); + if (ret) + goto cleanup; -error: - free(local_fulladdr.contents); - free(remote_fulladdr.contents); - krb5_free_cred(context, pcred); + *der_out = der_krbcred; + der_krbcred = NULL; + if ((authcon->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || + (authcon->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) + authcon->local_seq_number++; - if (retval) { - if (increased_sequence) - auth_context->local_seq_number--; +cleanup: + free(lstorage.contents); + free(rstorage.contents); + if (der_krbcred != NULL) { + zap(der_krbcred->data, der_krbcred->length); + krb5_free_data(context, der_krbcred); } - return retval; + return ret; } -/*----------------------- krb5_mk_1cred -----------------------*/ - -/* - * A convenience function that calls krb5_mk_ncred. - */ krb5_error_code KRB5_CALLCONV -krb5_mk_1cred(krb5_context context, krb5_auth_context auth_context, - krb5_creds *pcreds, krb5_data **ppdata, - krb5_replay_data *outdata) +krb5_mk_1cred(krb5_context context, krb5_auth_context authcon, + krb5_creds *creds, krb5_data **der_out, + krb5_replay_data *rdata_out) { krb5_error_code retval; - krb5_creds **ppcreds; + krb5_creds **list; - if ((ppcreds = (krb5_creds **)malloc(sizeof(*ppcreds) * 2)) == NULL) { + list = calloc(2, sizeof(*list)); + if (list == NULL) return ENOMEM; - } - - ppcreds[0] = pcreds; - ppcreds[1] = NULL; - - retval = krb5_mk_ncred(context, auth_context, ppcreds, - ppdata, outdata); - free(ppcreds); + list[0] = creds; + list[1] = NULL; + retval = krb5_mk_ncred(context, authcon, list, der_out, rdata_out); + free(list); return retval; } diff --git a/src/lib/krb5/krb/mk_priv.c b/src/lib/krb5/krb/mk_priv.c index b3d9e68b53..d66ab8ad1f 100644 --- a/src/lib/krb5/krb/mk_priv.c +++ b/src/lib/krb5/krb/mk_priv.c @@ -1,225 +1,153 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* lib/krb5/krb/mk_priv.c */ +/* lib/krb5/krb/mk_priv.c - definition of krb5_mk_priv() */ /* - * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * Copyright 1990,1991,2019 by the Massachusetts Institute of Technology. * All Rights Reserved. * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" -#include "cleanup.h" +#include "int-proto.h" #include "auth_con.h" +/* + * Marshal a KRB-PRIV message into der_out, encrypted with key. Use the + * timestamp and sequence number from rdata and the addresses from local_addr + * and remote_addr (the second of which may be NULL). der_out should be freed + * by the caller when finished. + */ static krb5_error_code -mk_priv_basic(krb5_context context, const krb5_data *userdata, - krb5_key key, krb5_replay_data *replaydata, - krb5_address *local_addr, krb5_address *remote_addr, - krb5_data *cstate, krb5_data *outbuf) +create_krbpriv(krb5_context context, const krb5_data *userdata, + krb5_key key, const krb5_replay_data *rdata, + krb5_address *local_addr, krb5_address *remote_addr, + krb5_data *cstate, krb5_data *der_out) { - krb5_enctype enctype = krb5_k_key_enctype(context, key); - krb5_error_code retval; - krb5_priv privmsg; - krb5_priv_enc_part privmsg_enc_part; - krb5_data *scratch1, *scratch2; - size_t enclen; - - privmsg.enc_part.kvno = 0; /* XXX allow user-set? */ + krb5_enctype enctype = krb5_k_key_enctype(context, key); + krb5_error_code ret; + krb5_priv privmsg; + krb5_priv_enc_part encpart; + krb5_data *der_encpart, *der_krbpriv; + size_t enclen; + + memset(&privmsg, 0, sizeof(privmsg)); + privmsg.enc_part.kvno = 0; privmsg.enc_part.enctype = enctype; - - privmsg_enc_part.user_data = *userdata; - privmsg_enc_part.s_address = local_addr; - privmsg_enc_part.r_address = remote_addr; - - /* We should check too make sure one exists. */ - privmsg_enc_part.timestamp = replaydata->timestamp; - privmsg_enc_part.usec = replaydata->usec; - privmsg_enc_part.seq_number = replaydata->seq; - - /* start by encoding to-be-encrypted part of the message */ - if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1))) - return retval; + encpart.user_data = *userdata; + encpart.s_address = local_addr; + encpart.r_address = remote_addr; + encpart.timestamp = rdata->timestamp; + encpart.usec = rdata->usec; + encpart.seq_number = rdata->seq; + + /* Start by encoding the to-be-encrypted part of the message. */ + ret = encode_krb5_enc_priv_part(&encpart, &der_encpart); + if (ret) + return ret; /* put together an eblock for this encryption */ - if ((retval = krb5_c_encrypt_length(context, enctype, - scratch1->length, &enclen))) - goto clean_scratch; - - privmsg.enc_part.ciphertext.length = enclen; - if (!(privmsg.enc_part.ciphertext.data = - malloc(privmsg.enc_part.ciphertext.length))) { - retval = ENOMEM; - goto clean_scratch; + ret = krb5_c_encrypt_length(context, enctype, der_encpart->length, + &enclen); + if (ret) + goto cleanup; + + ret = alloc_data(&privmsg.enc_part.ciphertext, enclen); + if (ret) + goto cleanup; + + ret = krb5_k_encrypt(context, key, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, + (cstate->length > 0) ? cstate : NULL, der_encpart, + &privmsg.enc_part); + if (ret) + goto cleanup; + + ret = encode_krb5_priv(&privmsg, &der_krbpriv); + if (ret) + goto cleanup; + + *der_out = *der_krbpriv; + free(der_krbpriv); + +cleanup: + zapfree(privmsg.enc_part.ciphertext.data, + privmsg.enc_part.ciphertext.length); + if (der_encpart != NULL) { + zap(der_encpart->data, der_encpart->length); + krb5_free_data(context, der_encpart); } - - if ((retval = krb5_k_encrypt(context, key, - KRB5_KEYUSAGE_KRB_PRIV_ENCPART, - (cstate->length > 0) ? cstate : NULL, - scratch1, &privmsg.enc_part))) - goto clean_encpart; - - if ((retval = encode_krb5_priv(&privmsg, &scratch2))) - goto clean_encpart; - - *outbuf = *scratch2; - free(scratch2); - retval = 0; - -clean_encpart: - memset(privmsg.enc_part.ciphertext.data, 0, - privmsg.enc_part.ciphertext.length); - free(privmsg.enc_part.ciphertext.data); - privmsg.enc_part.ciphertext.length = 0; - privmsg.enc_part.ciphertext.data = 0; - -clean_scratch: - memset(scratch1->data, 0, scratch1->length); - krb5_free_data(context, scratch1); - - return retval; + return ret; } krb5_error_code KRB5_CALLCONV -krb5_mk_priv(krb5_context context, krb5_auth_context auth_context, - const krb5_data *userdata, krb5_data *outbuf, - krb5_replay_data *outdata) +krb5_mk_priv(krb5_context context, krb5_auth_context authcon, + const krb5_data *userdata, krb5_data *der_out, + krb5_replay_data *rdata_out) { - krb5_error_code retval; - krb5_key key; - krb5_replay_data replaydata; - krb5_data buf = empty_data(); - - *outbuf = empty_data(); - - /* Clear replaydata block */ - memset(&replaydata, 0, sizeof(krb5_replay_data)); - - /* Get keyblock */ - if ((key = auth_context->send_subkey) == NULL) - key = auth_context->key; - - /* Get replay info */ - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->rcache == NULL)) - return KRB5_RC_REQUIRED; - - if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && - (outdata == NULL)) - /* Need a better error */ - return KRB5_RC_REQUIRED; - - if (!auth_context->local_addr) + krb5_error_code ret; + krb5_key key; + krb5_replay_data rdata; + krb5_data der_krbpriv = empty_data(); + krb5_address *local_addr, *remote_addr, lstorage, rstorage; + + *der_out = empty_data(); + memset(&lstorage, 0, sizeof(lstorage)); + memset(&rstorage, 0, sizeof(rstorage)); + if (!authcon->local_addr) return KRB5_LOCAL_ADDR_REQUIRED; - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { - if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, - &replaydata.usec))) - return retval; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { - outdata->timestamp = replaydata.timestamp; - outdata->usec = replaydata.usec; - } - } - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { - replaydata.seq = auth_context->local_seq_number++; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) - outdata->seq = replaydata.seq; - } - - { - krb5_address * premote_fulladdr = NULL; - krb5_address * plocal_fulladdr; - krb5_address remote_fulladdr; - krb5_address local_fulladdr; - CLEANUP_INIT(2); - - if (auth_context->local_port) { - if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, - auth_context->local_port, - &local_fulladdr))) { - CLEANUP_PUSH(local_fulladdr.contents, free); - plocal_fulladdr = &local_fulladdr; - } else { - goto error; - } - } else { - plocal_fulladdr = auth_context->local_addr; - } - - if (auth_context->remote_addr) { - if (auth_context->remote_port) { - if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, - auth_context->remote_port, - &remote_fulladdr))){ - CLEANUP_PUSH(remote_fulladdr.contents, free); - premote_fulladdr = &remote_fulladdr; - } else { - CLEANUP_DONE(); - goto error; - } - } else { - premote_fulladdr = auth_context->remote_addr; - } - } - - if ((retval = mk_priv_basic(context, userdata, key, &replaydata, - plocal_fulladdr, premote_fulladdr, - &auth_context->cstate, &buf))) { - CLEANUP_DONE(); - goto error; - } - - CLEANUP_DONE(); - } - - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { - krb5_donot_replay replay; - - if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, - "_priv", &replay.client))) - goto error; - - replay.server = ""; /* XXX */ - replay.msghash = NULL; - replay.cusec = replaydata.usec; - replay.ctime = replaydata.timestamp; - if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { - /* should we really error out here? XXX */ - free(replay.client); - goto error; - } - free(replay.client); - } - - *outbuf = buf; - return 0; - -error: - krb5_free_data_contents(context, &buf); - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) - auth_context->local_seq_number--; - - return retval; + ret = k5_privsafe_gen_rdata(context, authcon, &rdata, rdata_out); + if (ret) + goto cleanup; + + ret = k5_privsafe_gen_addrs(context, authcon, &lstorage, &rstorage, + &local_addr, &remote_addr); + if (ret) + goto cleanup; + + key = (authcon->send_subkey != NULL) ? authcon->send_subkey : authcon->key; + ret = create_krbpriv(context, userdata, key, &rdata, local_addr, + remote_addr, &authcon->cstate, &der_krbpriv); + if (ret) + goto cleanup; + + ret = k5_privsafe_check_replay(context, authcon, authcon->local_addr, + "_priv", &rdata, FALSE); + if (ret) + goto cleanup; + + *der_out = der_krbpriv; + der_krbpriv = empty_data(); + if ((authcon->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || + (authcon->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) + authcon->local_seq_number++; + +cleanup: + krb5_free_data_contents(context, &der_krbpriv); + free(lstorage.contents); + free(rstorage.contents); + return ret; } diff --git a/src/lib/krb5/krb/mk_safe.c b/src/lib/krb5/krb/mk_safe.c index 1453365570..02ee7256a3 100644 --- a/src/lib/krb5/krb/mk_safe.c +++ b/src/lib/krb5/krb/mk_safe.c @@ -1,59 +1,56 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* lib/krb5/krb/mk_safe.c */ +/* lib/krb5/krb/mk_safe.c - definition of krb5_mk_safe() */ /* - * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * Copyright 1990,1991,2019 by the Massachusetts Institute of Technology. * All Rights Reserved. * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" -#include "cleanup.h" +#include "int-proto.h" #include "auth_con.h" /* - Formats a KRB_SAFE message into outbuf. - - userdata is formatted as the user data in the message. - sumtype specifies the encryption type; key specifies the key which - might be used to seed the checksum; sender_addr and recv_addr specify - the full addresses (host and port) of the sender and receiver. - The host portion of sender_addr is used to form the addresses used in the - KRB_SAFE message. - - The outbuf buffer storage is allocated, and should be freed by the - caller when finished. - - returns system errors -*/ + * Marshal a KRB-SAFE message into der_out, with a keyed checksum of type + * sumtype. Use the timestamp and sequence number from rdata and the addresses + * from local_addr and remote_addr (the second of which may be NULL). der_out + * should be freed by the caller when finished. + */ static krb5_error_code -krb5_mk_safe_basic(krb5_context context, const krb5_data *userdata, - krb5_key key, krb5_replay_data *replaydata, - krb5_address *local_addr, krb5_address *remote_addr, - krb5_cksumtype sumtype, krb5_data *outbuf) +create_krbsafe(krb5_context context, const krb5_data *userdata, krb5_key key, + const krb5_replay_data *rdata, krb5_address *local_addr, + krb5_address *remote_addr, krb5_cksumtype sumtype, + krb5_data *der_out) { - krb5_error_code retval; + krb5_error_code ret; krb5_safe safemsg; krb5_octet zero_octet = 0; krb5_checksum safe_checksum; - krb5_data *scratch1, *scratch2; + krb5_data *der_krbsafe; if (sumtype && !krb5_c_valid_cksumtype(sumtype)) return KRB5_PROG_SUMTYPE_NOSUPP; @@ -61,48 +58,40 @@ krb5_mk_safe_basic(krb5_context context, const krb5_data *userdata, return KRB5KRB_AP_ERR_INAPP_CKSUM; safemsg.user_data = *userdata; - safemsg.s_address = (krb5_address *) local_addr; - safemsg.r_address = (krb5_address *) remote_addr; - - /* We should check too make sure one exists. */ - safemsg.timestamp = replaydata->timestamp; - safemsg.usec = replaydata->usec; - safemsg.seq_number = replaydata->seq; - - /* - * To do the checksum stuff, we need to encode the message with a - * zero-length zero-type checksum, then checksum the encoding, then - * re-encode with the checksum. - */ + safemsg.s_address = local_addr; + safemsg.r_address = remote_addr; + safemsg.timestamp = rdata->timestamp; + safemsg.usec = rdata->usec; + safemsg.seq_number = rdata->seq; + /* Encode the message with a zero-length zero-type checksum. */ safe_checksum.length = 0; safe_checksum.checksum_type = 0; safe_checksum.contents = &zero_octet; - safemsg.checksum = &safe_checksum; - - if ((retval = encode_krb5_safe(&safemsg, &scratch1))) - return retval; - - if ((retval = krb5_k_make_checksum(context, sumtype, key, - KRB5_KEYUSAGE_KRB_SAFE_CKSUM, - scratch1, &safe_checksum))) - goto cleanup_checksum; - + ret = encode_krb5_safe(&safemsg, &der_krbsafe); + if (ret) + return ret; + + /* Checksum the encoding. */ + ret = krb5_k_make_checksum(context, sumtype, key, + KRB5_KEYUSAGE_KRB_SAFE_CKSUM, der_krbsafe, + &safe_checksum); + zap(der_krbsafe->data, der_krbsafe->length); + krb5_free_data(context, der_krbsafe); + if (ret) + return ret; + + /* Encode the message again with the real checksum. */ safemsg.checksum = &safe_checksum; - if ((retval = encode_krb5_safe(&safemsg, &scratch2))) { - goto cleanup_checksum; - } - *outbuf = *scratch2; - free(scratch2); - retval = 0; + ret = encode_krb5_safe(&safemsg, &der_krbsafe); + krb5_free_checksum_contents(context, &safe_checksum); + if (ret) + return ret; -cleanup_checksum: - free(safe_checksum.contents); - - memset(scratch1->data, 0, scratch1->length); - krb5_free_data(context, scratch1); - return retval; + *der_out = *der_krbsafe; + free(der_krbsafe); + return 0; } /* Return the checksum type for the KRB-SAFE message, or 0 to use the enctype's @@ -111,15 +100,14 @@ static krb5_cksumtype safe_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_enctype enctype) { - krb5_error_code retval; + krb5_error_code ret; unsigned int nsumtypes, i; krb5_cksumtype *sumtypes; /* Use the auth context's safe_cksumtype if it is valid for the enctype. * Otherwise return 0 for the mandatory checksum. */ - retval = krb5_c_keyed_checksum_types(context, enctype, &nsumtypes, - &sumtypes); - if (retval != 0) + ret = krb5_c_keyed_checksum_types(context, enctype, &nsumtypes, &sumtypes); + if (ret != 0) return 0; for (i = 0; i < nsumtypes; i++) { if (auth_context->safe_cksumtype == sumtypes[i]) @@ -130,129 +118,53 @@ safe_cksumtype(krb5_context context, krb5_auth_context auth_context, } krb5_error_code KRB5_CALLCONV -krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, - const krb5_data *userdata, krb5_data *outbuf, - krb5_replay_data *outdata) +krb5_mk_safe(krb5_context context, krb5_auth_context authcon, + const krb5_data *userdata, krb5_data *der_out, + krb5_replay_data *rdata_out) { - krb5_error_code retval; - krb5_key key; - krb5_replay_data replaydata; - krb5_data buf = empty_data(); - - *outbuf = empty_data(); - - /* Clear replaydata block */ - memset(&replaydata, 0, sizeof(krb5_replay_data)); - - /* Get key */ - if ((key = auth_context->send_subkey) == NULL) - key = auth_context->key; - - /* Get replay info */ - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->rcache == NULL)) - return KRB5_RC_REQUIRED; - - if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && - (outdata == NULL)) - /* Need a better error */ - return KRB5_RC_REQUIRED; - - if (!auth_context->local_addr) + krb5_error_code ret; + krb5_key key; + krb5_replay_data rdata; + krb5_data der_krbsafe = empty_data(); + krb5_address *local_addr, *remote_addr, lstorage, rstorage; + krb5_cksumtype sumtype; + + *der_out = empty_data(); + memset(&lstorage, 0, sizeof(lstorage)); + memset(&rstorage, 0, sizeof(rstorage)); + if (authcon->local_addr == NULL) return KRB5_LOCAL_ADDR_REQUIRED; - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { - if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, - &replaydata.usec))) - return retval; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { - outdata->timestamp = replaydata.timestamp; - outdata->usec = replaydata.usec; - } - } - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { - replaydata.seq = auth_context->local_seq_number++; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) - outdata->seq = replaydata.seq; - } - - { - krb5_address * premote_fulladdr = NULL; - krb5_address * plocal_fulladdr; - krb5_address remote_fulladdr; - krb5_address local_fulladdr; - krb5_cksumtype sumtype; - - CLEANUP_INIT(2); - - if (auth_context->local_port) { - if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, - auth_context->local_port, - &local_fulladdr))){ - CLEANUP_PUSH(local_fulladdr.contents, free); - plocal_fulladdr = &local_fulladdr; - } else { - goto error; - } - } else { - plocal_fulladdr = auth_context->local_addr; - } - - if (auth_context->remote_addr) { - if (auth_context->remote_port) { - if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, - auth_context->remote_port, - &remote_fulladdr))){ - CLEANUP_PUSH(remote_fulladdr.contents, free); - premote_fulladdr = &remote_fulladdr; - } else { - CLEANUP_DONE(); - goto error; - } - } else { - premote_fulladdr = auth_context->remote_addr; - } - } - - sumtype = safe_cksumtype(context, auth_context, key->keyblock.enctype); - if ((retval = krb5_mk_safe_basic(context, userdata, key, &replaydata, - plocal_fulladdr, premote_fulladdr, - sumtype, &buf))) { - CLEANUP_DONE(); - goto error; - } - - CLEANUP_DONE(); - } - - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { - krb5_donot_replay replay; - - if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, - "_safe", &replay.client))) - goto error; - - replay.server = ""; /* XXX */ - replay.msghash = NULL; - replay.cusec = replaydata.usec; - replay.ctime = replaydata.timestamp; - /* should we really error out here? XXX */ - if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) - goto error; - free(replay.client); - } - - *outbuf = buf; - return 0; - -error: - krb5_free_data_contents(context, &buf); - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) - auth_context->local_seq_number--; - - return retval; + ret = k5_privsafe_gen_rdata(context, authcon, &rdata, rdata_out); + if (ret) + goto cleanup; + + ret = k5_privsafe_gen_addrs(context, authcon, &lstorage, &rstorage, + &local_addr, &remote_addr); + if (ret) + goto cleanup; + + key = (authcon->send_subkey != NULL) ? authcon->send_subkey : authcon->key; + sumtype = safe_cksumtype(context, authcon, key->keyblock.enctype); + ret = create_krbsafe(context, userdata, key, &rdata, local_addr, + remote_addr, sumtype, &der_krbsafe); + if (ret) + goto cleanup; + + ret = k5_privsafe_check_replay(context, authcon, authcon->local_addr, + "_safe", &rdata, FALSE); + if (ret) + goto cleanup; + + *der_out = der_krbsafe; + der_krbsafe = empty_data(); + if ((authcon->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || + (authcon->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) + authcon->local_seq_number++; + +cleanup: + krb5_free_data_contents(context, &der_krbsafe); + free(lstorage.contents); + free(rstorage.contents); + return ret; } diff --git a/src/lib/krb5/krb/privsafe.c b/src/lib/krb5/krb/privsafe.c index 264b07684e..a1e5230c0c 100644 --- a/src/lib/krb5/krb/privsafe.c +++ b/src/lib/krb5/krb/privsafe.c @@ -1,33 +1,145 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* lib/krb5/krb/privsafe.c - Shared logic for KRB-SAFE and KRB-PRIV messages */ /* - * Copyright (C) 2011 by the Massachusetts Institute of Technology. + * Copyright (C) 2011,2019 by the Massachusetts Institute of Technology. * All rights reserved. * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" #include "int-proto.h" #include "auth_con.h" +krb5_error_code +k5_privsafe_gen_rdata(krb5_context context, krb5_auth_context authcon, + krb5_replay_data *rdata, krb5_replay_data *caller_rdata) +{ + krb5_error_code ret; + krb5_int32 flags = authcon->auth_context_flags; + krb5_boolean do_time = !!(flags & KRB5_AUTH_CONTEXT_DO_TIME); + krb5_boolean do_sequence = !!(flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE); + krb5_boolean ret_time = !!(flags & KRB5_AUTH_CONTEXT_RET_TIME); + krb5_boolean ret_sequence = !!(flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE); + + memset(rdata, 0, sizeof(*rdata)); + if ((ret_time || ret_sequence) && caller_rdata == NULL) + return KRB5_RC_REQUIRED; + + if (do_time || ret_time) { + ret = krb5_us_timeofday(context, &rdata->timestamp, &rdata->usec); + if (ret) + return ret; + if (ret_time) { + caller_rdata->timestamp = rdata->timestamp; + caller_rdata->usec = rdata->usec; + } + } + if (do_sequence || ret_sequence) { + rdata->seq = authcon->local_seq_number; + if (ret_sequence) + caller_rdata->seq = rdata->seq; + } + + return 0; +} + +krb5_error_code +k5_privsafe_gen_addrs(krb5_context context, krb5_auth_context authcon, + krb5_address *lstorage, krb5_address *rstorage, + krb5_address **local_out, krb5_address **remote_out) +{ + krb5_error_code ret; + + *local_out = NULL; + *remote_out = NULL; + + if (authcon->local_addr != NULL) { + if (authcon->local_port != NULL) { + ret = krb5_make_fulladdr(context, authcon->local_addr, + authcon->local_port, lstorage); + if (ret) + return ret; + *local_out = lstorage; + } else { + *local_out = authcon->local_addr; + } + } + + if (authcon->remote_addr != NULL) { + if (authcon->remote_port != NULL) { + ret = krb5_make_fulladdr(context, authcon->remote_addr, + authcon->remote_port, rstorage); + if (ret) + return ret; + *remote_out = rstorage; + } else { + *remote_out = authcon->remote_addr; + } + } + + return 0; +} + +krb5_error_code +k5_privsafe_check_replay(krb5_context context, krb5_auth_context authcon, + krb5_address *addr, const char *uniq, + const krb5_replay_data *rdata, + krb5_boolean check_time) +{ + krb5_error_code ret; + krb5_donot_replay replay; + char *client = NULL; + + if (!(authcon->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME)) + return 0; + + if (authcon->rcache == NULL) + return KRB5_RC_REQUIRED; + + if (check_time) { + ret = krb5_check_clockskew(context, rdata->timestamp); + if (ret) + return ret; + } + + ret = krb5_gen_replay_name(context, addr, uniq, &client); + if (ret) + return ret; + + replay.client = client; + replay.server = ""; + replay.msghash = NULL; + replay.cusec = rdata->usec; + replay.ctime = rdata->timestamp; + ret = krb5_rc_store(context, authcon->rcache, &replay); + free(replay.client); + return ret; +} + /* * k5_privsafe_check_seqnum * diff --git a/src/lib/krb5/krb/rd_cred.c b/src/lib/krb5/krb/rd_cred.c index b08108bee2..7fdd10354a 100644 --- a/src/lib/krb5/krb/rd_cred.c +++ b/src/lib/krb5/krb/rd_cred.c @@ -4,37 +4,40 @@ * Copyright 1994-2009,2014 by the Massachusetts Institute of Technology. * All Rights Reserved. * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" -#include "cleanup.h" +#include "int-proto.h" #include "auth_con.h" -#include -#include - /* * Decrypt and decode the enc_part of a krb5_cred using the receiving subkey or * the session key of authcon. If neither key is present, ctext->ciphertext is - * assumed to be unencrypted plain text. + * assumed to be unencrypted plain text (RFC 6448). */ static krb5_error_code decrypt_encpart(krb5_context context, krb5_enc_data *ctext, @@ -145,7 +148,7 @@ krb5_rd_cred(krb5_context context, krb5_auth_context authcon, krb5_creds **credlist = NULL; krb5_cred *krbcred = NULL; krb5_cred_enc_part *encpart = NULL; - krb5_donot_replay replay; + krb5_replay_data rdata; const krb5_int32 flags = authcon->auth_context_flags; *creds_out = NULL; @@ -170,25 +173,13 @@ krb5_rd_cred(krb5_context context, krb5_auth_context authcon, if (ret) goto cleanup; - if (flags & KRB5_AUTH_CONTEXT_DO_TIME) { - ret = krb5_check_clockskew(context, encpart->timestamp); - if (ret) - goto cleanup; - - ret = krb5_gen_replay_name(context, authcon->remote_addr, "_forw", - &replay.client); - if (ret) - goto cleanup; - - replay.server = ""; - replay.msghash = NULL; - replay.cusec = encpart->usec; - replay.ctime = encpart->timestamp; - ret = krb5_rc_store(context, authcon->rcache, &replay); - free(replay.client); - if (ret) - goto cleanup; - } + rdata.timestamp = encpart->timestamp; + rdata.usec = encpart->usec; + rdata.seq = encpart->nonce; + ret = k5_privsafe_check_replay(context, authcon, authcon->remote_addr, + "_forw", &rdata, TRUE); + if (ret) + goto cleanup; if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if (authcon->remote_seq_number != (uint32_t)encpart->nonce) { diff --git a/src/lib/krb5/krb/rd_priv.c b/src/lib/krb5/krb/rd_priv.c index 2912ab1b5b..34eb656e32 100644 --- a/src/lib/krb5/krb/rd_priv.c +++ b/src/lib/krb5/krb/rd_priv.c @@ -1,27 +1,33 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* lib/krb5/krb/rd_priv.c */ +/* lib/krb5/krb/rd_priv.c - krb5_rd_priv() */ /* - * Copyright 1990,1991,2007 by the Massachusetts Institute of Technology. + * Copyright 1990,1991,2007,2019 by the Massachusetts Institute of Technology. * All Rights Reserved. * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" @@ -29,160 +35,112 @@ #include "auth_con.h" /* - - Parses a KRB_PRIV message from inbuf, placing the confidential user - data in *outbuf. - - key specifies the key to be used for decryption of the message. - - outbuf points to allocated storage which the caller should - free when finished. - - Returns system errors, integrity errors. - -*/ - + * Unmarshal a KRB-PRIV message from der_krbpriv, placing the confidential user + * data in *userdata_out and replay data in *rdata_out. The caller should free + * *userdata_out when finished. + */ static krb5_error_code -rd_priv_basic(krb5_context context, krb5_auth_context ac, - const krb5_data *inbuf, const krb5_key key, - krb5_replay_data *replaydata, krb5_data *outbuf) +read_krbpriv(krb5_context context, krb5_auth_context authcon, + const krb5_data *der_krbpriv, const krb5_key key, + krb5_replay_data *rdata_out, krb5_data *userdata_out) { - krb5_error_code retval; - krb5_priv * privmsg; - krb5_data scratch; - krb5_priv_enc_part * privmsg_enc_part; - krb5_data *iv = NULL; + krb5_error_code ret; + krb5_priv *privmsg = NULL; + krb5_data plaintext = empty_data(); + krb5_priv_enc_part *encpart = NULL; + krb5_data *cstate; - if (!krb5_is_krb_priv(inbuf)) + if (!krb5_is_krb_priv(der_krbpriv)) return KRB5KRB_AP_ERR_MSG_TYPE; /* decode private message */ - if ((retval = decode_krb5_priv(inbuf, &privmsg))) - return retval; - - if (ac->cstate.length > 0) - iv = &ac->cstate; - - scratch.length = privmsg->enc_part.ciphertext.length; - if (!(scratch.data = malloc(scratch.length))) { - retval = ENOMEM; - goto cleanup_privmsg; - } - - if ((retval = krb5_k_decrypt(context, key, - KRB5_KEYUSAGE_KRB_PRIV_ENCPART, iv, - &privmsg->enc_part, &scratch))) - goto cleanup_scratch; - - /* now decode the decrypted stuff */ - if ((retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part))) - goto cleanup_scratch; - - retval = k5_privsafe_check_addrs(context, ac, privmsg_enc_part->s_address, - privmsg_enc_part->r_address); - if (retval) - goto cleanup_data; - - replaydata->timestamp = privmsg_enc_part->timestamp; - replaydata->usec = privmsg_enc_part->usec; - replaydata->seq = privmsg_enc_part->seq_number; - - /* everything is ok - return data to the user */ - *outbuf = privmsg_enc_part->user_data; - retval = 0; - -cleanup_data:; - if (retval == 0) - privmsg_enc_part->user_data.data = 0; - krb5_free_priv_enc_part(context, privmsg_enc_part); - -cleanup_scratch:; - memset(scratch.data, 0, scratch.length); - free(scratch.data); - -cleanup_privmsg:; - free(privmsg->enc_part.ciphertext.data); - free(privmsg); - - return retval; + ret = decode_krb5_priv(der_krbpriv, &privmsg); + if (ret) + return ret; + + ret = alloc_data(&plaintext, privmsg->enc_part.ciphertext.length); + if (ret) + goto cleanup; + + cstate = (authcon->cstate.length > 0) ? &authcon->cstate : NULL; + ret = krb5_k_decrypt(context, key, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, cstate, + &privmsg->enc_part, &plaintext); + if (ret) + goto cleanup; + + ret = decode_krb5_enc_priv_part(&plaintext, &encpart); + if (ret) + goto cleanup; + + ret = k5_privsafe_check_addrs(context, authcon, encpart->s_address, + encpart->r_address); + if (ret) + goto cleanup; + + rdata_out->timestamp = encpart->timestamp; + rdata_out->usec = encpart->usec; + rdata_out->seq = encpart->seq_number; + + *userdata_out = encpart->user_data; + encpart->user_data.data = NULL; + +cleanup: + krb5_free_priv_enc_part(context, encpart); + krb5_free_priv(context, privmsg); + zapfree(plaintext.data, plaintext.length); + return ret; } krb5_error_code KRB5_CALLCONV -krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, - const krb5_data *inbuf, krb5_data *outbuf, - krb5_replay_data *outdata) +krb5_rd_priv(krb5_context context, krb5_auth_context authcon, + const krb5_data *inbuf, krb5_data *userdata_out, + krb5_replay_data *rdata_out) { - krb5_error_code retval; - krb5_key key; - krb5_replay_data replaydata; - - /* Get key */ - if ((key = auth_context->recv_subkey) == NULL) - key = auth_context->key; - - if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && - (outdata == NULL)) - /* Need a better error */ - return KRB5_RC_REQUIRED; + krb5_error_code ret; + krb5_key key; + krb5_replay_data rdata; + krb5_data userdata = empty_data(); + const krb5_int32 flags = authcon->auth_context_flags; - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->remote_addr == NULL)) - return KRB5_REMOTE_ADDR_REQUIRED; + *userdata_out = empty_data(); - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->rcache == NULL)) + if (((flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && rdata_out == NULL) return KRB5_RC_REQUIRED; - memset(&replaydata, 0, sizeof(replaydata)); - retval = rd_priv_basic(context, auth_context, inbuf, key, &replaydata, - outbuf); - if (retval) - return retval; - - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { - krb5_donot_replay replay; - - if ((retval = krb5_check_clockskew(context, replaydata.timestamp))) - goto error; - - if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, - "_priv", &replay.client))) - goto error; - - replay.server = ""; /* XXX */ - replay.msghash = NULL; - replay.cusec = replaydata.usec; - replay.ctime = replaydata.timestamp; - if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { - free(replay.client); - goto error; - } - free(replay.client); - } + if ((flags & KRB5_AUTH_CONTEXT_DO_TIME) && authcon->remote_addr == NULL) + return KRB5_REMOTE_ADDR_REQUIRED; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { - if (!k5_privsafe_check_seqnum(context, auth_context, replaydata.seq)) { - retval = KRB5KRB_AP_ERR_BADORDER; - goto error; + key = (authcon->recv_subkey != NULL) ? authcon->recv_subkey : authcon->key; + memset(&rdata, 0, sizeof(rdata)); + ret = read_krbpriv(context, authcon, inbuf, key, &rdata, &userdata); + if (ret) + goto cleanup; + + ret = k5_privsafe_check_replay(context, authcon, authcon->remote_addr, + "_priv", &rdata, TRUE); + if (ret) + goto cleanup; + + if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { + if (!k5_privsafe_check_seqnum(context, authcon, rdata.seq)) { + ret = KRB5KRB_AP_ERR_BADORDER; + goto cleanup; } - auth_context->remote_seq_number++; + authcon->remote_seq_number++; } - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { - outdata->timestamp = replaydata.timestamp; - outdata->usec = replaydata.usec; - outdata->seq = replaydata.seq; + if ((flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { + rdata_out->timestamp = rdata.timestamp; + rdata_out->usec = rdata.usec; + rdata_out->seq = rdata.seq; } - /* everything is ok - return data to the user */ - return 0; - -error:; - free(outbuf->data); - outbuf->length = 0; - outbuf->data = NULL; + *userdata_out = userdata; + userdata = empty_data(); - return retval; +cleanup: + krb5_free_data_contents(context, &userdata); + return ret; } diff --git a/src/lib/krb5/krb/rd_safe.c b/src/lib/krb5/krb/rd_safe.c index 5d2cee232b..eab7f6d746 100644 --- a/src/lib/krb5/krb/rd_safe.c +++ b/src/lib/krb5/krb/rd_safe.c @@ -1,210 +1,174 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* lib/krb5/krb/rd_safe.c - definition of krb5_rd_safe() */ +/* lib/krb5/krb/rd_safe.c - krb5_rd_safe() */ /* - * Copyright 1990,1991,2007,2008 by the Massachusetts Institute of Technology. - * All Rights Reserved. + * Copyright 1990,1991,2007,2008,2019 by the Massachusetts Institute of + * Technology. All Rights Reserved. * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "k5-int.h" #include "int-proto.h" -#include "cleanup.h" #include "auth_con.h" /* - parses a KRB_SAFE message from inbuf, placing the integrity-protected user - data in *outbuf. - - key specifies the key to be used for decryption of the message. - - outbuf points to allocated storage which the caller should free when finished. - - returns system errors, integrity errors -*/ + * Unmarshal a KRB-SAFE message from der_krbsafe, placing the + * integrity-protected user data in *userdata_out and replay data in + * *rdata_out. The caller should free *userdata_out when finished. + */ static krb5_error_code -rd_safe_basic(krb5_context context, krb5_auth_context ac, - const krb5_data *inbuf, krb5_key key, - krb5_replay_data *replaydata, krb5_data *outbuf) +read_krbsafe(krb5_context context, krb5_auth_context ac, + const krb5_data *der_krbsafe, krb5_key key, + krb5_replay_data *rdata_out, krb5_data *userdata_out) { - krb5_error_code retval; - krb5_safe * message; - krb5_data *safe_body = NULL; - krb5_checksum our_cksum, *his_cksum; + krb5_error_code ret; + krb5_safe *krbsafe; + krb5_data *safe_body = NULL, *der_zerosafe = NULL; + krb5_checksum zero_cksum, *safe_cksum; krb5_octet zero_octet = 0; - krb5_data *scratch; krb5_boolean valid; struct krb5_safe_with_body swb; - if (!krb5_is_krb_safe(inbuf)) + *userdata_out = empty_data(); + if (!krb5_is_krb_safe(der_krbsafe)) return KRB5KRB_AP_ERR_MSG_TYPE; - if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body))) - return retval; + ret = decode_krb5_safe_with_body(der_krbsafe, &krbsafe, &safe_body); + if (ret) + return ret; - if (!krb5_c_valid_cksumtype(message->checksum->checksum_type)) { - retval = KRB5_PROG_SUMTYPE_NOSUPP; + if (!krb5_c_valid_cksumtype(krbsafe->checksum->checksum_type)) { + ret = KRB5_PROG_SUMTYPE_NOSUPP; goto cleanup; } - if (!krb5_c_is_coll_proof_cksum(message->checksum->checksum_type) || - !krb5_c_is_keyed_cksum(message->checksum->checksum_type)) { - retval = KRB5KRB_AP_ERR_INAPP_CKSUM; + if (!krb5_c_is_coll_proof_cksum(krbsafe->checksum->checksum_type) || + !krb5_c_is_keyed_cksum(krbsafe->checksum->checksum_type)) { + ret = KRB5KRB_AP_ERR_INAPP_CKSUM; goto cleanup; } - retval = k5_privsafe_check_addrs(context, ac, message->s_address, - message->r_address); - if (retval) + ret = k5_privsafe_check_addrs(context, ac, krbsafe->s_address, + krbsafe->r_address); + if (ret) goto cleanup; - /* verify the checksum */ - /* - * In order to recreate what was checksummed, we regenerate the message - * without checksum and then have the cryptographic subsystem verify - * the checksum for us. This is because some checksum methods have - * a confounder encrypted as part of the checksum. - */ - his_cksum = message->checksum; - - our_cksum.length = 0; - our_cksum.checksum_type = 0; - our_cksum.contents = &zero_octet; - - message->checksum = &our_cksum; - + /* Regenerate the KRB-SAFE message without the checksum. */ + safe_cksum = krbsafe->checksum; + zero_cksum.length = 0; + zero_cksum.checksum_type = 0; + zero_cksum.contents = &zero_octet; + krbsafe->checksum = &zero_cksum; swb.body = safe_body; - swb.safe = message; - retval = encode_krb5_safe_with_body(&swb, &scratch); - message->checksum = his_cksum; - if (retval) + swb.safe = krbsafe; + ret = encode_krb5_safe_with_body(&swb, &der_zerosafe); + krbsafe->checksum = safe_cksum; + if (ret) goto cleanup; - retval = krb5_k_verify_checksum(context, key, - KRB5_KEYUSAGE_KRB_SAFE_CKSUM, - scratch, his_cksum, &valid); - - (void) memset(scratch->data, 0, scratch->length); - krb5_free_data(context, scratch); - + /* Verify the checkum over the re-encoded message. */ + ret = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_KRB_SAFE_CKSUM, + der_zerosafe, safe_cksum, &valid); if (!valid) { - /* - * Checksum over only the KRB-SAFE-BODY, like RFC 1510 says, in - * case someone actually implements it correctly. - */ - retval = krb5_k_verify_checksum(context, key, - KRB5_KEYUSAGE_KRB_SAFE_CKSUM, - safe_body, his_cksum, &valid); + /* Checksum over only the KRB-SAFE-BODY as specified in RFC 1510. */ + ret = krb5_k_verify_checksum(context, key, + KRB5_KEYUSAGE_KRB_SAFE_CKSUM, + safe_body, safe_cksum, &valid); if (!valid) { - retval = KRB5KRB_AP_ERR_MODIFIED; + ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } } - replaydata->timestamp = message->timestamp; - replaydata->usec = message->usec; - replaydata->seq = message->seq_number; + rdata_out->timestamp = krbsafe->timestamp; + rdata_out->usec = krbsafe->usec; + rdata_out->seq = krbsafe->seq_number; - *outbuf = message->user_data; - message->user_data.data = NULL; - retval = 0; + *userdata_out = krbsafe->user_data; + krbsafe->user_data.data = NULL; cleanup: - krb5_free_safe(context, message); + if (der_zerosafe != NULL) { + zap(der_zerosafe->data, der_zerosafe->length); + krb5_free_data(context, der_zerosafe); + } krb5_free_data(context, safe_body); - return retval; + krb5_free_safe(context, krbsafe); + return ret; } krb5_error_code KRB5_CALLCONV -krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, - const krb5_data *inbuf, krb5_data *outbuf, - krb5_replay_data *outdata) +krb5_rd_safe(krb5_context context, krb5_auth_context authcon, + const krb5_data *inbuf, krb5_data *userdata_out, + krb5_replay_data *rdata_out) { - krb5_error_code retval; - krb5_key key; - krb5_replay_data replaydata; - - if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && - (outdata == NULL)) - /* Need a better error */ + krb5_error_code ret; + krb5_key key; + krb5_replay_data rdata; + krb5_data userdata = empty_data(); + const krb5_int32 flags = authcon->auth_context_flags; + + *userdata_out = empty_data(); + + if (((flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && rdata_out == NULL) return KRB5_RC_REQUIRED; - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->remote_addr == NULL)) + if ((flags & KRB5_AUTH_CONTEXT_DO_TIME) && authcon->remote_addr == NULL) return KRB5_REMOTE_ADDR_REQUIRED; - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && - (auth_context->rcache == NULL)) - return KRB5_RC_REQUIRED; + key = (authcon->recv_subkey != NULL) ? authcon->recv_subkey : authcon->key; + memset(&rdata, 0, sizeof(rdata)); + ret = read_krbsafe(context, authcon, inbuf, key, &rdata, &userdata); + if (ret) + goto cleanup; - /* Get key */ - if ((key = auth_context->recv_subkey) == NULL) - key = auth_context->key; - - memset(&replaydata, 0, sizeof(replaydata)); - retval = rd_safe_basic(context, auth_context, inbuf, key, &replaydata, - outbuf); - if (retval) - return retval; - - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { - krb5_donot_replay replay; - - if ((retval = krb5_check_clockskew(context, replaydata.timestamp))) - goto error; - - if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, - "_safe", &replay.client))) - goto error; - - replay.server = ""; /* XXX */ - replay.msghash = NULL; - replay.cusec = replaydata.usec; - replay.ctime = replaydata.timestamp; - if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { - free(replay.client); - goto error; - } - free(replay.client); - } + ret = k5_privsafe_check_replay(context, authcon, authcon->remote_addr, + "_safe", &rdata, TRUE); + if (ret) + goto cleanup; - if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { - if (!k5_privsafe_check_seqnum(context, auth_context, replaydata.seq)) { - retval = KRB5KRB_AP_ERR_BADORDER; - goto error; + if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { + if (!k5_privsafe_check_seqnum(context, authcon, rdata.seq)) { + ret = KRB5KRB_AP_ERR_BADORDER; + goto cleanup; } - auth_context->remote_seq_number++; + authcon->remote_seq_number++; } - if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || - (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { - outdata->timestamp = replaydata.timestamp; - outdata->usec = replaydata.usec; - outdata->seq = replaydata.seq; + if ((flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { + rdata_out->timestamp = rdata.timestamp; + rdata_out->usec = rdata.usec; + rdata_out->seq = rdata.seq; } - /* everything is ok - return data to the user */ - return 0; - -error: - free(outbuf->data); - return retval; + *userdata_out = userdata; + userdata = empty_data(); +cleanup: + krb5_free_data_contents(context, &userdata); + return ret; }