Commit 395f639e authored by Trond Myklebust's avatar Trond Myklebust

RPCSEC_GSS: Add the spkm3 common and client-side code.

Signed-off-by: default avatarAndy Adamson <andros@citi.umich.edu>
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
parent 1a7549b7
......@@ -1560,6 +1560,22 @@ config RPCSEC_GSS_KRB5
If unsure, say N.
config RPCSEC_GSS_SPKM3
tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
select SUNRPC_GSS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_DES
help
Provides for secure RPC calls by means of a gss-api
mechanism based on the SPKM3 public-key mechanism.
Note: Requires an auxiliary userspace daemon which may be found on
http://www.citi.umich.edu/projects/nfsv4/
If unsure, say N.
config SMB_FS
tristate "SMB file system support (to mount Windows shares etc.)"
depends on INET
......
/*
* linux/include/linux/sunrpc/gss_spkm3.h
*
* Copyright (c) 2000 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*/
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
struct spkm3_ctx {
struct xdr_netobj ctx_id; /* per message context id */
int qop; /* negotiated qop */
struct xdr_netobj mech_used;
unsigned int ret_flags ;
unsigned int req_flags ;
struct xdr_netobj share_key;
int conf_alg;
struct crypto_tfm* derived_conf_key;
int intg_alg;
struct crypto_tfm* derived_integ_key;
int keyestb_alg; /* alg used to get share_key */
int owf_alg; /* one way function */
};
/* from openssl/objects.h */
/* XXX need SEAL_ALG_NONE */
#define NID_md5 4
#define NID_dhKeyAgreement 28
#define NID_des_cbc 31
#define NID_sha1 64
#define NID_cast5_cbc 108
/* SPKM InnerContext Token types */
#define SPKM_ERROR_TOK 3
#define SPKM_MIC_TOK 4
#define SPKM_WRAP_TOK 5
#define SPKM_DEL_TOK 6
u32 spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, struct xdr_buf * text, struct xdr_netobj * token, int toktype);
u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int *qop_state, int toktype);
#define CKSUMTYPE_RSA_MD5 0x0007
s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
struct xdr_netobj *cksum);
void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen,
int explen);
void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen,
unsigned char *ctxhdr, int elen, int zbit);
void spkm3_make_mic_token(unsigned char **tokp, int toklen,
struct xdr_netobj *mic_hdr,
struct xdr_netobj *md5cksum, int md5elen, int md5zbit);
u32 spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen,
unsigned char **cksum);
......@@ -12,3 +12,7 @@ obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
gss_krb5_seqnum.o
obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
rpcsec_gss_spkm3-objs := gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o \
gss_spkm3_token.o
/*
* linux/net/sunrpc/gss_spkm3_mech.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
* J. Bruce Fields <bfields@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``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 REGENTS 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 <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sunrpc/auth.h>
#include <linux/in.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/sunrpc/xdr.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
struct xdr_netobj gss_mech_spkm3_oid =
{7, "\053\006\001\005\005\001\003"};
static inline int
get_bytes(char **ptr, const char *end, void *res, int len)
{
char *p, *q;
p = *ptr;
q = p + len;
if (q > end || q < p)
return -1;
memcpy(res, p, len);
*ptr = q;
return 0;
}
static inline int
get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
{
char *p, *q;
p = *ptr;
if (get_bytes(&p, end, &res->len, sizeof(res->len)))
return -1;
q = p + res->len;
if(res->len == 0)
goto out_nocopy;
if (q > end || q < p)
return -1;
if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
return -1;
memcpy(res->data, p, res->len);
out_nocopy:
*ptr = q;
return 0;
}
static inline int
get_key(char **p, char *end, struct crypto_tfm **res, int *resalg)
{
struct xdr_netobj key = {
.len = 0,
.data = NULL,
};
int alg_mode,setkey = 0;
char *alg_name;
if (get_bytes(p, end, resalg, sizeof(int)))
goto out_err;
if ((get_netobj(p, end, &key)))
goto out_err;
switch (*resalg) {
case NID_des_cbc:
alg_name = "des";
alg_mode = CRYPTO_TFM_MODE_CBC;
setkey = 1;
break;
case NID_md5:
if (key.len == 0) {
dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
}
alg_name = "md5";
alg_mode = 0;
setkey = 0;
break;
case NID_cast5_cbc:
dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n");
goto out_err;
break;
default:
dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
goto out_err_free_key;
}
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
goto out_err_free_key;
if (setkey) {
if (crypto_cipher_setkey(*res, key.data, key.len))
goto out_err_free_tfm;
}
if(key.len > 0)
kfree(key.data);
return 0;
out_err_free_tfm:
crypto_free_tfm(*res);
out_err_free_key:
if(key.len > 0)
kfree(key.data);
out_err:
return -1;
}
static u32
gss_import_sec_context_spkm3(struct xdr_netobj *inbuf,
struct gss_ctx *ctx_id)
{
char *p = inbuf->data;
char *end = inbuf->data + inbuf->len;
struct spkm3_ctx *ctx;
if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
goto out_err;
memset(ctx, 0, sizeof(*ctx));
if (get_netobj(&p, end, &ctx->ctx_id))
goto out_err_free_ctx;
if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop)))
goto out_err_free_ctx_id;
if (get_netobj(&p, end, &ctx->mech_used))
goto out_err_free_mech;
if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)))
goto out_err_free_mech;
if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags)))
goto out_err_free_mech;
if (get_netobj(&p, end, &ctx->share_key))
goto out_err_free_s_key;
if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) {
dprintk("RPC: SPKM3 confidentiality key will be NULL\n");
}
if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) {
dprintk("RPC: SPKM3 integrity key will be NULL\n");
}
if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
goto out_err_free_s_key;
if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
goto out_err_free_s_key;
if (p != end)
goto out_err_free_s_key;
ctx_id->internal_ctx_id = ctx;
dprintk("Succesfully imported new spkm context.\n");
return 0;
out_err_free_s_key:
kfree(ctx->share_key.data);
out_err_free_mech:
kfree(ctx->mech_used.data);
out_err_free_ctx_id:
kfree(ctx->ctx_id.data);
out_err_free_ctx:
kfree(ctx);
out_err:
return GSS_S_FAILURE;
}
void
gss_delete_sec_context_spkm3(void *internal_ctx) {
struct spkm3_ctx *sctx = internal_ctx;
if(sctx->derived_integ_key)
crypto_free_tfm(sctx->derived_integ_key);
if(sctx->derived_conf_key)
crypto_free_tfm(sctx->derived_conf_key);
if(sctx->share_key.data)
kfree(sctx->share_key.data);
if(sctx->mech_used.data)
kfree(sctx->mech_used.data);
kfree(sctx);
}
u32
gss_verify_mic_spkm3(struct gss_ctx *ctx,
struct xdr_buf *signbuf,
struct xdr_netobj *checksum,
u32 *qstate) {
u32 maj_stat = 0;
int qop_state = 0;
struct spkm3_ctx *sctx = ctx->internal_ctx_id;
dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n");
maj_stat = spkm3_read_token(sctx, checksum, signbuf, &qop_state,
SPKM_MIC_TOK);
if (!maj_stat && qop_state)
*qstate = qop_state;
dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
return maj_stat;
}
u32
gss_get_mic_spkm3(struct gss_ctx *ctx,
u32 qop,
struct xdr_buf *message_buffer,
struct xdr_netobj *message_token) {
u32 err = 0;
struct spkm3_ctx *sctx = ctx->internal_ctx_id;
dprintk("RPC: gss_get_mic_spkm3\n");
err = spkm3_make_token(sctx, qop, message_buffer,
message_token, SPKM_MIC_TOK);
return err;
}
static struct gss_api_ops gss_spkm3_ops = {
.gss_import_sec_context = gss_import_sec_context_spkm3,
.gss_get_mic = gss_get_mic_spkm3,
.gss_verify_mic = gss_verify_mic_spkm3,
.gss_delete_sec_context = gss_delete_sec_context_spkm3,
};
static struct pf_desc gss_spkm3_pfs[] = {
{RPC_AUTH_GSS_SPKM, 0, RPC_GSS_SVC_NONE, "spkm3"},
{RPC_AUTH_GSS_SPKMI, 0, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
};
static struct gss_api_mech gss_spkm3_mech = {
.gm_name = "spkm3",
.gm_owner = THIS_MODULE,
.gm_ops = &gss_spkm3_ops,
.gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
.gm_pfs = gss_spkm3_pfs,
};
static int __init init_spkm3_module(void)
{
int status;
status = gss_mech_register(&gss_spkm3_mech);
if (status)
printk("Failed to register spkm3 gss mechanism!\n");
return 0;
}
static void __exit cleanup_spkm3_module(void)
{
gss_mech_unregister(&gss_spkm3_mech);
}
MODULE_LICENSE("GPL");
module_init(init_spkm3_module);
module_exit(cleanup_spkm3_module);
/*
* linux/net/sunrpc/gss_spkm3_seal.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``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 REGENTS 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 <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/random.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
/*
* spkm3_make_token()
*
* Only SPKM_MIC_TOK with md5 intg-alg is supported
*/
u32
spkm3_make_token(struct spkm3_ctx *ctx, int qop_req,
struct xdr_buf * text, struct xdr_netobj * token,
int toktype)
{
s32 checksum_type;
char tokhdrbuf[25];
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf};
int tmsglen, tokenlen = 0;
unsigned char *ptr;
s32 now;
int ctxelen = 0, ctxzbit = 0;
int md5elen = 0, md5zbit = 0;
dprintk("RPC: spkm3_make_token\n");
now = jiffies;
if (qop_req != 0)
goto out_err;
if (ctx->ctx_id.len != 16) {
dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
ctx->ctx_id.len);
goto out_err;
}
switch (ctx->intg_alg) {
case NID_md5:
checksum_type = CKSUMTYPE_RSA_MD5;
break;
default:
dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not"
" supported\n", ctx->intg_alg);
goto out_err;
}
/* XXX since we don't support WRAP, perhaps we don't care... */
if (ctx->conf_alg != NID_cast5_cbc) {
dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n",
ctx->conf_alg);
goto out_err;
}
if (toktype == SPKM_MIC_TOK) {
tmsglen = 0;
/* Calculate checksum over the mic-header */
asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
ctxelen, ctxzbit);
if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len,
text, &md5cksum))
goto out_err;
asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
tokenlen = 10 + ctxelen + 1 + 2 + md5elen + 1;
/* Create token header using generic routines */
token->len = g_token_size(&ctx->mech_used, tokenlen + tmsglen);
ptr = token->data;
g_make_token_header(&ctx->mech_used, tokenlen + tmsglen, &ptr);
spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n");
goto out_err;
}
kfree(md5cksum.data);
/* XXX need to implement sequence numbers, and ctx->expired */
return GSS_S_COMPLETE;
out_err:
if (md5cksum.data)
kfree(md5cksum.data);
token->data = 0;
token->len = 0;
return GSS_S_FAILURE;
}
/*
* linux/net/sunrpc/gss_spkm3_token.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``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 REGENTS 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 <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/random.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
/*
* asn1_bitstring_len()
*
* calculate the asn1 bitstring length of the xdr_netobject
*/
void
asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
{
int i, zbit = 0,elen = in->len;
char *ptr;
ptr = &in->data[in->len -1];
/* count trailing 0's */
for(i = in->len; i > 0; i--) {
if (*ptr == 0) {
ptr--;
elen--;
} else
break;
}
/* count number of 0 bits in final octet */
ptr = &in->data[elen - 1];
for(i = 0; i < 8; i++) {
short mask = 0x01;
if (!((mask << i) & *ptr))
zbit++;
else
break;
}
*enclen = elen;
*zerobits = zbit;
}
/*
* decode_asn1_bitstring()
*
* decode a bitstring into a buffer of the expected length.
* enclen = bit string length
* explen = expected length (define in rfc)
*/
int
decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
{
if (!(out->data = kmalloc(explen,GFP_KERNEL)))
return 0;
out->len = explen;
memset(out->data, 0, explen);
memcpy(out->data, in, enclen);
return 1;
}
/*
* SPKMInnerContextToken choice SPKM_MIC asn1 token layout
*
* contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
*
* tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
*
* pos value
* ----------
* [0] a4 SPKM-MIC tag
* [1] ?? innertoken length (max 44)
*
*
* tok_hdr piece of checksum data starts here
*
* the maximum mic-header len = 9 + 17 = 26
* mic-header
* ----------
* [2] 30 SEQUENCE tag
* [3] ?? mic-header length: (max 23) = TokenID + ContextID
*
* TokenID - all fields constant and can be hardcoded
* -------
* [4] 02 Type 2
* [5] 02 Length 2
* [6][7] 01 01 TokenID (SPKM_MIC_TOK)
*
* ContextID - encoded length not constant, calculated
* ---------
* [8] 03 Type 3
* [9] ?? encoded length
* [10] ?? ctxzbit
* [11] contextid
*
* mic_header piece of checksum data ends here.
*
* int-cksum - encoded length not constant, calculated
* ---------
* [??] 03 Type 3
* [??] ?? encoded length
* [??] ?? md5zbit
* [??] int-cksum (NID_md5 = 16)
*
* maximum SPKM-MIC innercontext token length =
* 10 + encoded contextid_size(17 max) + 2 + encoded
* cksum_size (17 maxfor NID_md5) = 46
*/
/*
* spkm3_mic_header()
*
* Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
* elen: 16 byte context id asn1 bitstring encoded length
*/
void
spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
{
char *hptr = *hdrbuf;
char *top = *hdrbuf;
*(u8 *)hptr++ = 0x30;
*(u8 *)hptr++ = elen + 7; /* on the wire header length */
/* tokenid */
*(u8 *)hptr++ = 0x02;
*(u8 *)hptr++ = 0x02;
*(u8 *)hptr++ = 0x01;
*(u8 *)hptr++ = 0x01;
/* coniextid */
*(u8 *)hptr++ = 0x03;
*(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
*(u8 *)hptr++ = zbit;
memcpy(hptr, ctxdata, elen);
hptr += elen;
*hdrlen = hptr - top;
}
/*
* spkm3_mic_innercontext_token()
*
* *tokp points to the beginning of the SPKM_MIC token described
* in rfc 2025, section 3.2.1:
*
*/
void
spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
{
unsigned char *ict = *tokp;
*(u8 *)ict++ = 0xa4;
*(u8 *)ict++ = toklen - 2;
memcpy(ict, mic_hdr->data, mic_hdr->len);
ict += mic_hdr->len;
*(u8 *)ict++ = 0x03;
*(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
*(u8 *)ict++ = md5zbit;
memcpy(ict, md5cksum->data, md5elen);
}
u32
spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
{
struct xdr_netobj spkm3_ctx_id = {.len =0, .data = NULL};
unsigned char *ptr = *tokp;
int ctxelen;
u32 ret = GSS_S_DEFECTIVE_TOKEN;
/* spkm3 innercontext token preamble */
if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
dprintk("RPC: BAD SPKM ictoken preamble\n");
goto out;
}
*mic_hdrlen = ptr[3];
/* token type */
if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
dprintk("RPC: BAD asn1 SPKM3 token type\n");
goto out;
}
/* only support SPKM_MIC_TOK */
if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
dprintk("RPC: ERROR unsupported SPKM3 token \n");
goto out;
}
/* contextid */
if (ptr[8] != 0x03) {
dprintk("RPC: BAD SPKM3 asn1 context-id type\n");
goto out;
}
ctxelen = ptr[9];
if (ctxelen > 17) { /* length includes asn1 zbit octet */
dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen);
goto out;
}
/* ignore ptr[10] */
if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
goto out;
/*
* in the current implementation: the optional int-alg is not present
* so the default int-alg (md5) is used the optional snd-seq field is
* also not present
*/
if (*mic_hdrlen != 6 + ctxelen) {
dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq\n", *mic_hdrlen);
goto out;
}
/* checksum */
*cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
ret = GSS_S_COMPLETE;
out:
if (spkm3_ctx_id.data)
kfree(spkm3_ctx_id.data);
return ret;
}
/*
* linux/net/sunrpc/gss_spkm3_unseal.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``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 REGENTS 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 <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
/*
* spkm3_read_token()
*
* only SPKM_MIC_TOK with md5 intg-alg is supported
*/
u32
spkm3_read_token(struct spkm3_ctx *ctx,
struct xdr_netobj *read_token, /* checksum */
struct xdr_buf *message_buffer, /* signbuf */
int *qop_state, int toktype)
{
s32 code;
struct xdr_netobj wire_cksum = {.len =0, .data = NULL};
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
unsigned char *ptr = (unsigned char *)read_token->data;
unsigned char *cksum;
int bodysize, md5elen;
int mic_hdrlen;
u32 ret = GSS_S_DEFECTIVE_TOKEN;
dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len);
if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
&bodysize, &ptr, read_token->len))
goto out;
/* decode the token */
if (toktype == SPKM_MIC_TOK) {
if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
goto out;
if (*cksum++ != 0x03) {
dprintk("RPC: spkm3_read_token BAD checksum type\n");
goto out;
}
md5elen = *cksum++;
cksum++; /* move past the zbit */
if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
goto out;
/* HARD CODED FOR MD5 */
/* compute the checksum of the message.
* ptr + 2 = start of header piece of checksum
* mic_hdrlen + 2 = length of header piece of checksum
*/
ret = GSS_S_DEFECTIVE_TOKEN;
code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2,
mic_hdrlen + 2,
message_buffer, &md5cksum);
if (code)
goto out;
dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n",
wire_cksum.len);
dprintk(" md5cksum.data\n");
print_hexl((u32 *) md5cksum.data, 16, 0);
dprintk(" cksum.data:\n");
print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0);
ret = GSS_S_BAD_SIG;
code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
if (code)
goto out;
} else {
dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype);
goto out;
}
/* XXX: need to add expiration and sequencing */
ret = GSS_S_COMPLETE;
out:
if (md5cksum.data)
kfree(md5cksum.data);
if (wire_cksum.data)
kfree(wire_cksum.data);
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment