#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 ctx_id; /* per message context id */
+ int endtime; /* endtime of the context */
struct xdr_netobj mech_used;
unsigned int ret_flags ;
- unsigned int req_flags ;
- struct xdr_netobj share_key;
- int conf_alg;
- struct crypto_blkcipher *derived_conf_key;
- int intg_alg;
- struct crypto_blkcipher *derived_integ_key;
- int keyestb_alg; /* alg used to get share_key */
- int owf_alg; /* one way function */
+ struct xdr_netobj conf_alg;
+ struct xdr_netobj derived_conf_key;
+ struct xdr_netobj intg_alg;
+ struct xdr_netobj derived_integ_key;
};
-/* 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
+/* OIDs declarations for K-ALG, I-ALG, C-ALG, and OWF-ALG */
+extern const struct xdr_netobj hmac_md5_oid;
+extern const struct xdr_netobj cast5_cbc_oid;
/* SPKM InnerContext Token types */
u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int toktype);
#define CKSUMTYPE_RSA_MD5 0x0007
+#define CKSUMTYPE_HMAC_MD5 0x0008
-s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
- int body_offset, struct xdr_netobj *cksum);
+s32 make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
+ unsigned int hdrlen, struct xdr_buf *body,
+ unsigned int body_offset, 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 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);
#define GSS_CRED_SLACK 1024 /* XXX: unused */
/* length of a krb5 verifier (48), plus data added before arguments when
* using integrity (two 4-byte integers): */
-#define GSS_VERF_SLACK 56
+#define GSS_VERF_SLACK 100
/* XXX this define must match the gssd define
* as it is passed to gssd to signal the use of
return q;
}
-static inline const void *
-get_key(const void *p, const void *end, struct crypto_blkcipher **res,
- int *resalg)
-{
- struct xdr_netobj key = { 0 };
- int setkey = 0;
- char *alg_name;
-
- p = simple_get_bytes(p, end, resalg, sizeof(*resalg));
- if (IS_ERR(p))
- goto out_err;
- p = simple_get_netobj(p, end, &key);
- if (IS_ERR(p))
- goto out_err;
-
- switch (*resalg) {
- case NID_des_cbc:
- alg_name = "cbc(des)";
- setkey = 1;
- break;
- case NID_cast5_cbc:
- /* XXXX here in name only, not used */
- alg_name = "cbc(cast5)";
- setkey = 0; /* XXX will need to set to 1 */
- break;
- case NID_md5:
- if (key.len == 0) {
- dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
- }
- alg_name = "md5";
- setkey = 0;
- break;
- default:
- dprintk("gss_spkm3_mech: unsupported algorithm %d\n", *resalg);
- goto out_err_free_key;
- }
- *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(*res)) {
- printk("gss_spkm3_mech: unable to initialize crypto algorthm %s\n", alg_name);
- *res = NULL;
- goto out_err_free_key;
- }
- if (setkey) {
- if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
- printk("gss_spkm3_mech: error setting key for crypto algorthm %s\n", alg_name);
- goto out_err_free_tfm;
- }
- }
-
- if(key.len > 0)
- kfree(key.data);
- return p;
-
-out_err_free_tfm:
- crypto_free_blkcipher(*res);
-out_err_free_key:
- if(key.len > 0)
- kfree(key.data);
- p = ERR_PTR(-EINVAL);
-out_err:
- return p;
-}
-
static int
gss_import_sec_context_spkm3(const void *p, size_t len,
struct gss_ctx *ctx_id)
{
const void *end = (const void *)((const char *)p + len);
struct spkm3_ctx *ctx;
+ int version;
if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
goto out_err;
+ p = simple_get_bytes(p, end, &version, sizeof(version));
+ if (IS_ERR(p))
+ goto out_err_free_ctx;
+ if (version != 1) {
+ dprintk("RPC: unknown spkm3 token format: obsolete nfs-utils?\n");
+ goto out_err_free_ctx;
+ }
+
p = simple_get_netobj(p, end, &ctx->ctx_id);
if (IS_ERR(p))
goto out_err_free_ctx;
- p = simple_get_bytes(p, end, &ctx->qop, sizeof(ctx->qop));
+ p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
if (IS_ERR(p))
goto out_err_free_ctx_id;
p = simple_get_netobj(p, end, &ctx->mech_used);
if (IS_ERR(p))
- goto out_err_free_mech;
+ goto out_err_free_ctx_id;
p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags));
if (IS_ERR(p))
goto out_err_free_mech;
- p = simple_get_bytes(p, end, &ctx->req_flags, sizeof(ctx->req_flags));
+ p = simple_get_netobj(p, end, &ctx->conf_alg);
if (IS_ERR(p))
goto out_err_free_mech;
- p = simple_get_netobj(p, end, &ctx->share_key);
- if (IS_ERR(p))
- goto out_err_free_s_key;
-
- p = get_key(p, end, &ctx->derived_conf_key, &ctx->conf_alg);
+ p = simple_get_netobj(p, end, &ctx->derived_conf_key);
if (IS_ERR(p))
- goto out_err_free_s_key;
+ goto out_err_free_conf_alg;
- p = get_key(p, end, &ctx->derived_integ_key, &ctx->intg_alg);
+ p = simple_get_netobj(p, end, &ctx->intg_alg);
if (IS_ERR(p))
- goto out_err_free_key1;
+ goto out_err_free_conf_key;
- p = simple_get_bytes(p, end, &ctx->keyestb_alg, sizeof(ctx->keyestb_alg));
+ p = simple_get_netobj(p, end, &ctx->derived_integ_key);
if (IS_ERR(p))
- goto out_err_free_key2;
-
- p = simple_get_bytes(p, end, &ctx->owf_alg, sizeof(ctx->owf_alg));
- if (IS_ERR(p))
- goto out_err_free_key2;
+ goto out_err_free_intg_alg;
if (p != end)
- goto out_err_free_key2;
+ goto out_err_free_intg_key;
ctx_id->internal_ctx_id = ctx;
dprintk("Successfully imported new spkm context.\n");
return 0;
-out_err_free_key2:
- crypto_free_blkcipher(ctx->derived_integ_key);
-out_err_free_key1:
- crypto_free_blkcipher(ctx->derived_conf_key);
-out_err_free_s_key:
- kfree(ctx->share_key.data);
+out_err_free_intg_key:
+ kfree(ctx->derived_integ_key.data);
+out_err_free_intg_alg:
+ kfree(ctx->intg_alg.data);
+out_err_free_conf_key:
+ kfree(ctx->derived_conf_key.data);
+out_err_free_conf_alg:
+ kfree(ctx->conf_alg.data);
out_err_free_mech:
kfree(ctx->mech_used.data);
out_err_free_ctx_id:
}
static void
-gss_delete_sec_context_spkm3(void *internal_ctx) {
+gss_delete_sec_context_spkm3(void *internal_ctx)
+{
struct spkm3_ctx *sctx = internal_ctx;
- crypto_free_blkcipher(sctx->derived_integ_key);
- crypto_free_blkcipher(sctx->derived_conf_key);
- kfree(sctx->share_key.data);
+ kfree(sctx->derived_integ_key.data);
+ kfree(sctx->intg_alg.data);
+ kfree(sctx->derived_conf_key.data);
+ kfree(sctx->conf_alg.data);
kfree(sctx->mech_used.data);
+ kfree(sctx->ctx_id.data);
kfree(sctx);
}
u32 maj_stat = 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, SPKM_MIC_TOK);
dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
u32 err = 0;
struct spkm3_ctx *sctx = ctx->internal_ctx_id;
- dprintk("RPC: gss_get_mic_spkm3\n");
-
err = spkm3_make_token(sctx, message_buffer,
- message_token, SPKM_MIC_TOK);
+ message_token, SPKM_MIC_TOK);
+ dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err);
return err;
}
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/random.h>
#include <linux/crypto.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <linux/sunrpc/xdr.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
+const struct xdr_netobj hmac_md5_oid = { 8, "\x2B\x06\x01\x05\x05\x08\x01\x01"};
+const struct xdr_netobj cast5_cbc_oid = {9, "\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A"};
+
/*
* spkm3_make_token()
*
int ctxelen = 0, ctxzbit = 0;
int md5elen = 0, md5zbit = 0;
- dprintk("RPC: spkm3_make_token\n");
-
now = jiffies;
if (ctx->ctx_id.len != 16) {
dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
- ctx->ctx_id.len);
+ 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);
+
+ if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
+ dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm."
+ "only support hmac-md5 I-ALG.\n");
+ goto out_err;
+ } else
+ checksum_type = CKSUMTYPE_HMAC_MD5;
+
+ if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) {
+ dprintk("RPC: gss_spkm3_seal: unsupported C-ALG algorithm\n");
goto out_err;
}
/* 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, 0, &md5cksum))
+ ctxelen, ctxzbit);
+ if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key,
+ (char *)mic_hdr.data, mic_hdr.len,
+ text, 0, &md5cksum))
goto out_err;
asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
return GSS_S_COMPLETE;
out_err:
+ if (md5cksum.data)
+ kfree(md5cksum.data);
+
token->data = NULL;
token->len = 0;
return GSS_S_FAILURE;
}
+
+static int
+spkm3_checksummer(struct scatterlist *sg, void *data)
+{
+ struct hash_desc *desc = data;
+
+ return crypto_hash_update(desc, sg, sg->length);
+}
+
+/* checksum the plaintext data and hdrlen bytes of the token header */
+s32
+make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
+ unsigned int hdrlen, struct xdr_buf *body,
+ unsigned int body_offset, struct xdr_netobj *cksum)
+{
+ char *cksumname;
+ struct hash_desc desc; /* XXX add to ctx? */
+ struct scatterlist sg[1];
+ int err;
+
+ switch (cksumtype) {
+ case CKSUMTYPE_HMAC_MD5:
+ cksumname = "md5";
+ break;
+ default:
+ dprintk("RPC: spkm3_make_checksum:"
+ " unsupported checksum %d", cksumtype);
+ return GSS_S_FAILURE;
+ }
+
+ if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE;
+
+ desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(desc.tfm))
+ return GSS_S_FAILURE;
+ cksum->len = crypto_hash_digestsize(desc.tfm);
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ err = crypto_hash_setkey(desc.tfm, key->data, key->len);
+ if (err)
+ goto out;
+
+ sg_set_buf(sg, header, hdrlen);
+ crypto_hash_update(&desc, sg, 1);
+
+ xdr_process_buf(body, body_offset, body->len - body_offset,
+ spkm3_checksummer, &desc);
+ crypto_hash_final(&desc, cksum->data);
+
+out:
+ crypto_free_hash(desc.tfm);
+
+ return err ? GSS_S_FAILURE : 0;
+}
+
+EXPORT_SYMBOL(make_spkm3_checksum);
*(u8 *)hptr++ = zbit;
memcpy(hptr, ctxdata, elen);
hptr += elen;
- *hdrlen = hptr - top;
+ *hdrlen = hptr - top;
}
-
-/*
+
+/*
* spkm3_mic_innercontext_token()
*
* *tokp points to the beginning of the SPKM_MIC token described
struct xdr_buf *message_buffer, /* signbuf */
int toktype)
{
+ s32 checksum_type;
s32 code;
struct xdr_netobj wire_cksum = {.len =0, .data = NULL};
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
unsigned char *ptr = (unsigned char *)read_token->data;
- unsigned char *cksum;
+ 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, 0, &md5cksum);
-
- if (code)
- goto out;
-
- dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n",
- wire_cksum.len);
-
- 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);
+ if (toktype != SPKM_MIC_TOK) {
+ dprintk("RPC: BAD SPKM3 token type: %d\n", toktype);
+ goto out;
+ }
+
+ 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;
+ if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
+ dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm\n");
+ goto out;
+ }
+
+ checksum_type = CKSUMTYPE_HMAC_MD5;
+
+ code = make_spkm3_checksum(checksum_type,
+ &ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2,
+ message_buffer, 0, &md5cksum);
+
+ if (code)
+ goto out;
+
+ ret = GSS_S_BAD_SIG;
+ code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
+ if (code) {
+ dprintk("RPC: bad MIC checksum\n");
goto out;
}
+
/* XXX: need to add expiration and sequencing */
ret = GSS_S_COMPLETE;
out: