adeb8133dd
This updates the spkm3 code to bring it up to date with our current understanding of the spkm3 spec. In doing so, we're changing the downcall format used by gssd in the spkm3 case, which will cause an incompatilibity with old userland spkm3 support. Since the old code a) didn't implement the protocol correctly, and b) was never distributed except in the form of some experimental patches from the citi web site, we're assuming this is OK. We do detect the old downcall format and print warning (and fail). We also include a version number in the new downcall format, to be used in the future in case any further change is required. In some more detail: - fix integrity support - removed dependency on NIDs. instead OIDs are used - known OID values for algorithms added. - fixed some context fields and types Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
266 lines
6.8 KiB
C
266 lines
6.8 KiB
C
/*
|
|
* 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 = kzalloc(explen,GFP_KERNEL)))
|
|
return 0;
|
|
out->len = 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:
|
|
*
|
|
* toklen is the inner token length
|
|
*/
|
|
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;
|
|
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:
|
|
kfree(spkm3_ctx_id.data);
|
|
return ret;
|
|
}
|
|
|