Commit e01b2c79 authored by Chuck Lever's avatar Chuck Lever
Browse files

SUNRPC: Refactor the GSS-API Per Message calls in the Kerberos mechanism



Replace a number of switches on encryption type so that all of them don't
have to be modified when adding or removing support for an enctype.

Tested-by: default avatarScott Mayhew <smayhew@redhat.com>
Reviewed-by: default avatarSimo Sorce <simo@redhat.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 8270dbfc
Loading
Loading
Loading
Loading
+9 −14
Original line number Original line Diff line number Diff line
@@ -84,6 +84,15 @@ struct gss_krb5_enctype {
	u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset, u32 len,
	u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset, u32 len,
			   struct xdr_buf *buf, u32 *headskip,
			   struct xdr_buf *buf, u32 *headskip,
			   u32 *tailskip);	/* v2 decryption function */
			   u32 *tailskip);	/* v2 decryption function */
	u32 (*get_mic)(struct krb5_ctx *kctx, struct xdr_buf *text,
		       struct xdr_netobj *token);
	u32 (*verify_mic)(struct krb5_ctx *kctx, struct xdr_buf *message_buffer,
			  struct xdr_netobj *read_token);
	u32 (*wrap)(struct krb5_ctx *kctx, int offset,
		    struct xdr_buf *buf, struct page **pages);
	u32 (*unwrap)(struct krb5_ctx *kctx, int offset, int len,
		      struct xdr_buf *buf, unsigned int *slack,
		      unsigned int *align);
};
};


/* krb5_ctx flags definitions */
/* krb5_ctx flags definitions */
@@ -233,20 +242,6 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
		struct xdr_buf *body, int body_offset, u8 *cksumkey,
		struct xdr_buf *body, int body_offset, u8 *cksumkey,
		unsigned int usage, struct xdr_netobj *cksumout);
		unsigned int usage, struct xdr_netobj *cksumout);


u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
		struct xdr_netobj *);

u32 gss_verify_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
		struct xdr_netobj *);

u32
gss_wrap_kerberos(struct gss_ctx *ctx_id, int offset,
		struct xdr_buf *outbuf, struct page **pages);

u32
gss_unwrap_kerberos(struct gss_ctx *ctx_id, int offset, int len,
		struct xdr_buf *buf);

u32
u32
krb5_encrypt(struct crypto_sync_skcipher *key,
krb5_encrypt(struct crypto_sync_skcipher *key,
	     void *iv, void *in, void *out, int length);
	     void *iv, void *in, void *out, int length);
+30 −0
Original line number Original line Diff line number Diff line
@@ -8,6 +8,36 @@
#ifndef _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H
#ifndef _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H
#define _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H
#define _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H


/*
 * GSS Kerberos 5 mechanism Per-Message calls.
 */

u32 gss_krb5_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
			struct xdr_netobj *token);
u32 gss_krb5_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
			struct xdr_netobj *token);

u32 gss_krb5_verify_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
			   struct xdr_netobj *read_token);
u32 gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
			   struct xdr_netobj *read_token);

u32 gss_krb5_wrap_v1(struct krb5_ctx *kctx, int offset,
		     struct xdr_buf *buf, struct page **pages);
u32 gss_krb5_wrap_v2(struct krb5_ctx *kctx, int offset,
		     struct xdr_buf *buf, struct page **pages);

u32 gss_krb5_unwrap_v1(struct krb5_ctx *kctx, int offset, int len,
		       struct xdr_buf *buf, unsigned int *slack,
		       unsigned int *align);
u32 gss_krb5_unwrap_v2(struct krb5_ctx *kctx, int offset, int len,
		       struct xdr_buf *buf, unsigned int *slack,
		       unsigned int *align);

/*
 * Implementation internal functions
 */

void krb5_make_confounder(u8 *p, int conflen);
void krb5_make_confounder(u8 *p, int conflen);


u32 gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
u32 gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
+115 −11
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/sunrpc/gss_krb5_enctypes.h>
#include <linux/sunrpc/gss_krb5_enctypes.h>


#include "auth_gss_internal.h"
#include "auth_gss_internal.h"
#include "gss_krb5_internal.h"


#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY	RPCDBG_AUTH
# define RPCDBG_FACILITY	RPCDBG_AUTH
@@ -43,6 +44,10 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
	  .encrypt = krb5_encrypt,
	  .encrypt = krb5_encrypt,
	  .decrypt = krb5_decrypt,
	  .decrypt = krb5_decrypt,
	  .mk_key = NULL,
	  .mk_key = NULL,
	  .get_mic = gss_krb5_get_mic_v1,
	  .verify_mic = gss_krb5_verify_mic_v1,
	  .wrap = gss_krb5_wrap_v1,
	  .unwrap = gss_krb5_unwrap_v1,
	  .signalg = SGN_ALG_DES_MAC_MD5,
	  .signalg = SGN_ALG_DES_MAC_MD5,
	  .sealalg = SEAL_ALG_DES,
	  .sealalg = SEAL_ALG_DES,
	  .keybytes = 7,
	  .keybytes = 7,
@@ -63,6 +68,10 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
	  .encrypt = krb5_encrypt,
	  .encrypt = krb5_encrypt,
	  .decrypt = krb5_decrypt,
	  .decrypt = krb5_decrypt,
	  .mk_key = gss_krb5_des3_make_key,
	  .mk_key = gss_krb5_des3_make_key,
	  .get_mic = gss_krb5_get_mic_v1,
	  .verify_mic = gss_krb5_verify_mic_v1,
	  .wrap = gss_krb5_wrap_v1,
	  .unwrap = gss_krb5_unwrap_v1,
	  .signalg = SGN_ALG_HMAC_SHA1_DES3_KD,
	  .signalg = SGN_ALG_HMAC_SHA1_DES3_KD,
	  .sealalg = SEAL_ALG_DES3KD,
	  .sealalg = SEAL_ALG_DES3KD,
	  .keybytes = 21,
	  .keybytes = 21,
@@ -85,6 +94,12 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
	  .mk_key = gss_krb5_aes_make_key,
	  .mk_key = gss_krb5_aes_make_key,
	  .encrypt_v2 = gss_krb5_aes_encrypt,
	  .encrypt_v2 = gss_krb5_aes_encrypt,
	  .decrypt_v2 = gss_krb5_aes_decrypt,
	  .decrypt_v2 = gss_krb5_aes_decrypt,

	  .get_mic = gss_krb5_get_mic_v2,
	  .verify_mic = gss_krb5_verify_mic_v2,
	  .wrap = gss_krb5_wrap_v2,
	  .unwrap = gss_krb5_unwrap_v2,

	  .signalg = -1,
	  .signalg = -1,
	  .sealalg = -1,
	  .sealalg = -1,
	  .keybytes = 16,
	  .keybytes = 16,
@@ -107,6 +122,12 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
	  .mk_key = gss_krb5_aes_make_key,
	  .mk_key = gss_krb5_aes_make_key,
	  .encrypt_v2 = gss_krb5_aes_encrypt,
	  .encrypt_v2 = gss_krb5_aes_encrypt,
	  .decrypt_v2 = gss_krb5_aes_decrypt,
	  .decrypt_v2 = gss_krb5_aes_decrypt,

	  .get_mic = gss_krb5_get_mic_v2,
	  .verify_mic = gss_krb5_verify_mic_v2,
	  .wrap = gss_krb5_wrap_v2,
	  .unwrap = gss_krb5_unwrap_v2,

	  .signalg = -1,
	  .signalg = -1,
	  .sealalg = -1,
	  .sealalg = -1,
	  .keybytes = 32,
	  .keybytes = 32,
@@ -557,10 +578,8 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
}
}


static int
static int
gss_import_sec_context_kerberos(const void *p, size_t len,
gss_krb5_import_sec_context(const void *p, size_t len, struct gss_ctx *ctx_id,
				struct gss_ctx *ctx_id,
			    time64_t *endtime, gfp_t gfp_mask)
				time64_t *endtime,
				gfp_t gfp_mask)
{
{
	const void *end = (const void *)((const char *)p + len);
	const void *end = (const void *)((const char *)p + len);
	struct  krb5_ctx *ctx;
	struct  krb5_ctx *ctx;
@@ -587,7 +606,8 @@ gss_import_sec_context_kerberos(const void *p, size_t len,
}
}


static void
static void
gss_delete_sec_context_kerberos(void *internal_ctx) {
gss_krb5_delete_sec_context(void *internal_ctx)
{
	struct krb5_ctx *kctx = internal_ctx;
	struct krb5_ctx *kctx = internal_ctx;


	crypto_free_sync_skcipher(kctx->seq);
	crypto_free_sync_skcipher(kctx->seq);
@@ -604,13 +624,97 @@ gss_delete_sec_context_kerberos(void *internal_ctx) {
	kfree(kctx);
	kfree(kctx);
}
}


/**
 * gss_krb5_get_mic - get_mic for the Kerberos GSS mechanism
 * @gctx: GSS context
 * @text: plaintext to checksum
 * @token: buffer into which to write the computed checksum
 *
 * Return values:
 *    %GSS_S_COMPLETE - success, and @token is filled in
 *    %GSS_S_FAILURE - checksum could not be generated
 *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
 */
static u32 gss_krb5_get_mic(struct gss_ctx *gctx, struct xdr_buf *text,
			    struct xdr_netobj *token)
{
	struct krb5_ctx *kctx = gctx->internal_ctx_id;

	return kctx->gk5e->get_mic(kctx, text, token);
}

/**
 * gss_krb5_verify_mic - verify_mic for the Kerberos GSS mechanism
 * @gctx: GSS context
 * @message_buffer: plaintext to check
 * @read_token: received checksum to check
 *
 * Return values:
 *    %GSS_S_COMPLETE - computed and received checksums match
 *    %GSS_S_DEFECTIVE_TOKEN - received checksum is not valid
 *    %GSS_S_BAD_SIG - computed and received checksums do not match
 *    %GSS_S_FAILURE - received checksum could not be checked
 *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
 */
static u32 gss_krb5_verify_mic(struct gss_ctx *gctx,
			       struct xdr_buf *message_buffer,
			       struct xdr_netobj *read_token)
{
	struct krb5_ctx *kctx = gctx->internal_ctx_id;

	return kctx->gk5e->verify_mic(kctx, message_buffer, read_token);
}

/**
 * gss_krb5_wrap - gss_wrap for the Kerberos GSS mechanism
 * @gctx: initialized GSS context
 * @offset: byte offset in @buf to start writing the cipher text
 * @buf: OUT: send buffer
 * @pages: plaintext to wrap
 *
 * Return values:
 *    %GSS_S_COMPLETE - success, @buf has been updated
 *    %GSS_S_FAILURE - @buf could not be wrapped
 *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
 */
static u32 gss_krb5_wrap(struct gss_ctx *gctx, int offset,
			 struct xdr_buf *buf, struct page **pages)
{
	struct krb5_ctx	*kctx = gctx->internal_ctx_id;

	return kctx->gk5e->wrap(kctx, offset, buf, pages);
}

/**
 * gss_krb5_unwrap - gss_unwrap for the Kerberos GSS mechanism
 * @gctx: initialized GSS context
 * @offset: starting byte offset into @buf
 * @len: size of ciphertext to unwrap
 * @buf: ciphertext to unwrap
 *
 * Return values:
 *    %GSS_S_COMPLETE - success, @buf has been updated
 *    %GSS_S_DEFECTIVE_TOKEN - received blob is not valid
 *    %GSS_S_BAD_SIG - computed and received checksums do not match
 *    %GSS_S_FAILURE - @buf could not be unwrapped
 *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
 */
static u32 gss_krb5_unwrap(struct gss_ctx *gctx, int offset,
			   int len, struct xdr_buf *buf)
{
	struct krb5_ctx	*kctx = gctx->internal_ctx_id;

	return kctx->gk5e->unwrap(kctx, offset, len, buf,
				  &gctx->slack, &gctx->align);
}

static const struct gss_api_ops gss_kerberos_ops = {
static const struct gss_api_ops gss_kerberos_ops = {
	.gss_import_sec_context	= gss_import_sec_context_kerberos,
	.gss_import_sec_context	= gss_krb5_import_sec_context,
	.gss_get_mic		= gss_get_mic_kerberos,
	.gss_get_mic		= gss_krb5_get_mic,
	.gss_verify_mic		= gss_verify_mic_kerberos,
	.gss_verify_mic		= gss_krb5_verify_mic,
	.gss_wrap		= gss_wrap_kerberos,
	.gss_wrap		= gss_krb5_wrap,
	.gss_unwrap		= gss_unwrap_kerberos,
	.gss_unwrap		= gss_krb5_unwrap,
	.gss_delete_sec_context	= gss_delete_sec_context_kerberos,
	.gss_delete_sec_context	= gss_krb5_delete_sec_context,
};
};


static struct pf_desc gss_kerberos_pfs[] = {
static struct pf_desc gss_kerberos_pfs[] = {
+6 −24
Original line number Original line Diff line number Diff line
@@ -125,8 +125,8 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
	return krb5_hdr;
	return krb5_hdr;
}
}


static u32
u32
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
gss_krb5_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
		    struct xdr_netobj *token)
		    struct xdr_netobj *token)
{
{
	char			cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
	char			cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
@@ -164,8 +164,8 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
}
}


static u32
u32
gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
gss_krb5_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
		    struct xdr_netobj *token)
		    struct xdr_netobj *token)
{
{
	struct crypto_ahash *tfm = ctx->initiate ?
	struct crypto_ahash *tfm = ctx->initiate ?
@@ -194,21 +194,3 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
	now = ktime_get_real_seconds();
	now = ktime_get_real_seconds();
	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
}
}

u32
gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
		     struct xdr_netobj *token)
{
	struct krb5_ctx		*ctx = gss_ctx->internal_ctx_id;

	switch (ctx->enctype) {
	default:
		BUG();
	case ENCTYPE_DES_CBC_RAW:
	case ENCTYPE_DES3_CBC_RAW:
		return gss_get_mic_v1(ctx, text, token);
	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
		return gss_get_mic_v2(ctx, text, token);
	}
}
+6 −25
Original line number Original line Diff line number Diff line
@@ -73,9 +73,9 @@
/* read_token is a mic token, and message_buffer is the data that the mic was
/* read_token is a mic token, and message_buffer is the data that the mic was
 * supposedly taken over. */
 * supposedly taken over. */


static u32
u32
gss_verify_mic_v1(struct krb5_ctx *ctx,
gss_krb5_verify_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
		struct xdr_buf *message_buffer, struct xdr_netobj *read_token)
		       struct xdr_netobj *read_token)
{
{
	int			signalg;
	int			signalg;
	int			sealalg;
	int			sealalg;
@@ -145,9 +145,9 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
	return GSS_S_COMPLETE;
	return GSS_S_COMPLETE;
}
}


static u32
u32
gss_verify_mic_v2(struct krb5_ctx *ctx,
gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
		struct xdr_buf *message_buffer, struct xdr_netobj *read_token)
		       struct xdr_netobj *read_token)
{
{
	struct crypto_ahash *tfm = ctx->initiate ?
	struct crypto_ahash *tfm = ctx->initiate ?
				   ctx->acceptor_sign : ctx->initiator_sign;
				   ctx->acceptor_sign : ctx->initiator_sign;
@@ -202,22 +202,3 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,


	return GSS_S_COMPLETE;
	return GSS_S_COMPLETE;
}
}

u32
gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
			struct xdr_buf *message_buffer,
			struct xdr_netobj *read_token)
{
	struct krb5_ctx *ctx = gss_ctx->internal_ctx_id;

	switch (ctx->enctype) {
	default:
		BUG();
	case ENCTYPE_DES_CBC_RAW:
	case ENCTYPE_DES3_CBC_RAW:
		return gss_verify_mic_v1(ctx, message_buffer, read_token);
	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
		return gss_verify_mic_v2(ctx, message_buffer, read_token);
	}
}
Loading