Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rpc: spkm3 update

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>

authored by

Olga Kornievskaia and committed by
Trond Myklebust
adeb8133 37a4e6cb

+180 -182
+14 -20
include/linux/sunrpc/gss_spkm3.h
··· 12 12 #include <linux/sunrpc/gss_asn1.h> 13 13 14 14 struct spkm3_ctx { 15 - struct xdr_netobj ctx_id; /* per message context id */ 16 - int qop; /* negotiated qop */ 15 + struct xdr_netobj ctx_id; /* per message context id */ 16 + int endtime; /* endtime of the context */ 17 17 struct xdr_netobj mech_used; 18 18 unsigned int ret_flags ; 19 - unsigned int req_flags ; 20 - struct xdr_netobj share_key; 21 - int conf_alg; 22 - struct crypto_blkcipher *derived_conf_key; 23 - int intg_alg; 24 - struct crypto_blkcipher *derived_integ_key; 25 - int keyestb_alg; /* alg used to get share_key */ 26 - int owf_alg; /* one way function */ 19 + struct xdr_netobj conf_alg; 20 + struct xdr_netobj derived_conf_key; 21 + struct xdr_netobj intg_alg; 22 + struct xdr_netobj derived_integ_key; 27 23 }; 28 24 29 - /* from openssl/objects.h */ 30 - /* XXX need SEAL_ALG_NONE */ 31 - #define NID_md5 4 32 - #define NID_dhKeyAgreement 28 33 - #define NID_des_cbc 31 34 - #define NID_sha1 64 35 - #define NID_cast5_cbc 108 25 + /* OIDs declarations for K-ALG, I-ALG, C-ALG, and OWF-ALG */ 26 + extern const struct xdr_netobj hmac_md5_oid; 27 + extern const struct xdr_netobj cast5_cbc_oid; 36 28 37 29 /* SPKM InnerContext Token types */ 38 30 ··· 38 46 u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int toktype); 39 47 40 48 #define CKSUMTYPE_RSA_MD5 0x0007 49 + #define CKSUMTYPE_HMAC_MD5 0x0008 41 50 42 - s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, 43 - int body_offset, struct xdr_netobj *cksum); 51 + s32 make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header, 52 + unsigned int hdrlen, struct xdr_buf *body, 53 + unsigned int body_offset, struct xdr_netobj *cksum); 44 54 void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits); 45 - int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, 55 + int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, 46 56 int explen); 47 57 void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, 48 58 unsigned char *ctxhdr, int elen, int zbit);
+1 -1
net/sunrpc/auth_gss/auth_gss.c
··· 68 68 #define GSS_CRED_SLACK 1024 /* XXX: unused */ 69 69 /* length of a krb5 verifier (48), plus data added before arguments when 70 70 * using integrity (two 4-byte integers): */ 71 - #define GSS_VERF_SLACK 56 71 + #define GSS_VERF_SLACK 100 72 72 73 73 /* XXX this define must match the gssd define 74 74 * as it is passed to gssd to signal the use of
+36 -95
net/sunrpc/auth_gss/gss_spkm3_mech.c
··· 82 82 return q; 83 83 } 84 84 85 - static inline const void * 86 - get_key(const void *p, const void *end, struct crypto_blkcipher **res, 87 - int *resalg) 88 - { 89 - struct xdr_netobj key = { 0 }; 90 - int setkey = 0; 91 - char *alg_name; 92 - 93 - p = simple_get_bytes(p, end, resalg, sizeof(*resalg)); 94 - if (IS_ERR(p)) 95 - goto out_err; 96 - p = simple_get_netobj(p, end, &key); 97 - if (IS_ERR(p)) 98 - goto out_err; 99 - 100 - switch (*resalg) { 101 - case NID_des_cbc: 102 - alg_name = "cbc(des)"; 103 - setkey = 1; 104 - break; 105 - case NID_cast5_cbc: 106 - /* XXXX here in name only, not used */ 107 - alg_name = "cbc(cast5)"; 108 - setkey = 0; /* XXX will need to set to 1 */ 109 - break; 110 - case NID_md5: 111 - if (key.len == 0) { 112 - dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n"); 113 - } 114 - alg_name = "md5"; 115 - setkey = 0; 116 - break; 117 - default: 118 - dprintk("gss_spkm3_mech: unsupported algorithm %d\n", *resalg); 119 - goto out_err_free_key; 120 - } 121 - *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC); 122 - if (IS_ERR(*res)) { 123 - printk("gss_spkm3_mech: unable to initialize crypto algorthm %s\n", alg_name); 124 - *res = NULL; 125 - goto out_err_free_key; 126 - } 127 - if (setkey) { 128 - if (crypto_blkcipher_setkey(*res, key.data, key.len)) { 129 - printk("gss_spkm3_mech: error setting key for crypto algorthm %s\n", alg_name); 130 - goto out_err_free_tfm; 131 - } 132 - } 133 - 134 - if(key.len > 0) 135 - kfree(key.data); 136 - return p; 137 - 138 - out_err_free_tfm: 139 - crypto_free_blkcipher(*res); 140 - out_err_free_key: 141 - if(key.len > 0) 142 - kfree(key.data); 143 - p = ERR_PTR(-EINVAL); 144 - out_err: 145 - return p; 146 - } 147 - 148 85 static int 149 86 gss_import_sec_context_spkm3(const void *p, size_t len, 150 87 struct gss_ctx *ctx_id) 151 88 { 152 89 const void *end = (const void *)((const char *)p + len); 153 90 struct spkm3_ctx *ctx; 91 + int version; 154 92 155 93 if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL))) 156 94 goto out_err; 95 + 96 + p = simple_get_bytes(p, end, &version, sizeof(version)); 97 + if (IS_ERR(p)) 98 + goto out_err_free_ctx; 99 + if (version != 1) { 100 + dprintk("RPC: unknown spkm3 token format: obsolete nfs-utils?\n"); 101 + goto out_err_free_ctx; 102 + } 157 103 158 104 p = simple_get_netobj(p, end, &ctx->ctx_id); 159 105 if (IS_ERR(p)) 160 106 goto out_err_free_ctx; 161 107 162 - p = simple_get_bytes(p, end, &ctx->qop, sizeof(ctx->qop)); 108 + p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); 163 109 if (IS_ERR(p)) 164 110 goto out_err_free_ctx_id; 165 111 166 112 p = simple_get_netobj(p, end, &ctx->mech_used); 167 113 if (IS_ERR(p)) 168 - goto out_err_free_mech; 114 + goto out_err_free_ctx_id; 169 115 170 116 p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)); 171 117 if (IS_ERR(p)) 172 118 goto out_err_free_mech; 173 119 174 - p = simple_get_bytes(p, end, &ctx->req_flags, sizeof(ctx->req_flags)); 120 + p = simple_get_netobj(p, end, &ctx->conf_alg); 175 121 if (IS_ERR(p)) 176 122 goto out_err_free_mech; 177 123 178 - p = simple_get_netobj(p, end, &ctx->share_key); 124 + p = simple_get_netobj(p, end, &ctx->derived_conf_key); 179 125 if (IS_ERR(p)) 180 - goto out_err_free_s_key; 126 + goto out_err_free_conf_alg; 181 127 182 - p = get_key(p, end, &ctx->derived_conf_key, &ctx->conf_alg); 128 + p = simple_get_netobj(p, end, &ctx->intg_alg); 183 129 if (IS_ERR(p)) 184 - goto out_err_free_s_key; 130 + goto out_err_free_conf_key; 185 131 186 - p = get_key(p, end, &ctx->derived_integ_key, &ctx->intg_alg); 132 + p = simple_get_netobj(p, end, &ctx->derived_integ_key); 187 133 if (IS_ERR(p)) 188 - goto out_err_free_key1; 189 - 190 - p = simple_get_bytes(p, end, &ctx->keyestb_alg, sizeof(ctx->keyestb_alg)); 191 - if (IS_ERR(p)) 192 - goto out_err_free_key2; 193 - 194 - p = simple_get_bytes(p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)); 195 - if (IS_ERR(p)) 196 - goto out_err_free_key2; 134 + goto out_err_free_intg_alg; 197 135 198 136 if (p != end) 199 - goto out_err_free_key2; 137 + goto out_err_free_intg_key; 200 138 201 139 ctx_id->internal_ctx_id = ctx; 202 140 203 141 dprintk("Successfully imported new spkm context.\n"); 204 142 return 0; 205 143 206 - out_err_free_key2: 207 - crypto_free_blkcipher(ctx->derived_integ_key); 208 - out_err_free_key1: 209 - crypto_free_blkcipher(ctx->derived_conf_key); 210 - out_err_free_s_key: 211 - kfree(ctx->share_key.data); 144 + out_err_free_intg_key: 145 + kfree(ctx->derived_integ_key.data); 146 + out_err_free_intg_alg: 147 + kfree(ctx->intg_alg.data); 148 + out_err_free_conf_key: 149 + kfree(ctx->derived_conf_key.data); 150 + out_err_free_conf_alg: 151 + kfree(ctx->conf_alg.data); 212 152 out_err_free_mech: 213 153 kfree(ctx->mech_used.data); 214 154 out_err_free_ctx_id: ··· 160 220 } 161 221 162 222 static void 163 - gss_delete_sec_context_spkm3(void *internal_ctx) { 223 + gss_delete_sec_context_spkm3(void *internal_ctx) 224 + { 164 225 struct spkm3_ctx *sctx = internal_ctx; 165 226 166 - crypto_free_blkcipher(sctx->derived_integ_key); 167 - crypto_free_blkcipher(sctx->derived_conf_key); 168 - kfree(sctx->share_key.data); 227 + kfree(sctx->derived_integ_key.data); 228 + kfree(sctx->intg_alg.data); 229 + kfree(sctx->derived_conf_key.data); 230 + kfree(sctx->conf_alg.data); 169 231 kfree(sctx->mech_used.data); 232 + kfree(sctx->ctx_id.data); 170 233 kfree(sctx); 171 234 } 172 235 ··· 181 238 u32 maj_stat = 0; 182 239 struct spkm3_ctx *sctx = ctx->internal_ctx_id; 183 240 184 - dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n"); 185 241 maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK); 186 242 187 243 dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat); ··· 195 253 u32 err = 0; 196 254 struct spkm3_ctx *sctx = ctx->internal_ctx_id; 197 255 198 - dprintk("RPC: gss_get_mic_spkm3\n"); 199 - 200 256 err = spkm3_make_token(sctx, message_buffer, 201 - message_token, SPKM_MIC_TOK); 257 + message_token, SPKM_MIC_TOK); 258 + dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err); 202 259 return err; 203 260 } 204 261
+80 -21
net/sunrpc/auth_gss/gss_spkm3_seal.c
··· 39 39 #include <linux/sunrpc/gss_spkm3.h> 40 40 #include <linux/random.h> 41 41 #include <linux/crypto.h> 42 + #include <linux/pagemap.h> 43 + #include <linux/scatterlist.h> 44 + #include <linux/sunrpc/xdr.h> 42 45 43 46 #ifdef RPC_DEBUG 44 47 # define RPCDBG_FACILITY RPCDBG_AUTH 45 48 #endif 49 + 50 + const struct xdr_netobj hmac_md5_oid = { 8, "\x2B\x06\x01\x05\x05\x08\x01\x01"}; 51 + const struct xdr_netobj cast5_cbc_oid = {9, "\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A"}; 46 52 47 53 /* 48 54 * spkm3_make_token() ··· 72 66 int ctxelen = 0, ctxzbit = 0; 73 67 int md5elen = 0, md5zbit = 0; 74 68 75 - dprintk("RPC: spkm3_make_token\n"); 76 - 77 69 now = jiffies; 78 70 79 71 if (ctx->ctx_id.len != 16) { 80 72 dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n", 81 - ctx->ctx_id.len); 73 + ctx->ctx_id.len); 82 74 goto out_err; 83 75 } 84 - 85 - switch (ctx->intg_alg) { 86 - case NID_md5: 87 - checksum_type = CKSUMTYPE_RSA_MD5; 88 - break; 89 - default: 90 - dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not" 91 - " supported\n", ctx->intg_alg); 92 - goto out_err; 93 - } 94 - /* XXX since we don't support WRAP, perhaps we don't care... */ 95 - if (ctx->conf_alg != NID_cast5_cbc) { 96 - dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n", 97 - ctx->conf_alg); 76 + 77 + if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { 78 + dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm." 79 + "only support hmac-md5 I-ALG.\n"); 80 + goto out_err; 81 + } else 82 + checksum_type = CKSUMTYPE_HMAC_MD5; 83 + 84 + if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) { 85 + dprintk("RPC: gss_spkm3_seal: unsupported C-ALG algorithm\n"); 98 86 goto out_err; 99 87 } 100 88 ··· 96 96 /* Calculate checksum over the mic-header */ 97 97 asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit); 98 98 spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data, 99 - ctxelen, ctxzbit); 100 - 101 - if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len, 102 - text, 0, &md5cksum)) 99 + ctxelen, ctxzbit); 100 + if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key, 101 + (char *)mic_hdr.data, mic_hdr.len, 102 + text, 0, &md5cksum)) 103 103 goto out_err; 104 104 105 105 asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit); ··· 121 121 122 122 return GSS_S_COMPLETE; 123 123 out_err: 124 + if (md5cksum.data) 125 + kfree(md5cksum.data); 126 + 124 127 token->data = NULL; 125 128 token->len = 0; 126 129 return GSS_S_FAILURE; 127 130 } 131 + 132 + static int 133 + spkm3_checksummer(struct scatterlist *sg, void *data) 134 + { 135 + struct hash_desc *desc = data; 136 + 137 + return crypto_hash_update(desc, sg, sg->length); 138 + } 139 + 140 + /* checksum the plaintext data and hdrlen bytes of the token header */ 141 + s32 142 + make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header, 143 + unsigned int hdrlen, struct xdr_buf *body, 144 + unsigned int body_offset, struct xdr_netobj *cksum) 145 + { 146 + char *cksumname; 147 + struct hash_desc desc; /* XXX add to ctx? */ 148 + struct scatterlist sg[1]; 149 + int err; 150 + 151 + switch (cksumtype) { 152 + case CKSUMTYPE_HMAC_MD5: 153 + cksumname = "md5"; 154 + break; 155 + default: 156 + dprintk("RPC: spkm3_make_checksum:" 157 + " unsupported checksum %d", cksumtype); 158 + return GSS_S_FAILURE; 159 + } 160 + 161 + if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE; 162 + 163 + desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); 164 + if (IS_ERR(desc.tfm)) 165 + return GSS_S_FAILURE; 166 + cksum->len = crypto_hash_digestsize(desc.tfm); 167 + desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; 168 + 169 + err = crypto_hash_setkey(desc.tfm, key->data, key->len); 170 + if (err) 171 + goto out; 172 + 173 + sg_set_buf(sg, header, hdrlen); 174 + crypto_hash_update(&desc, sg, 1); 175 + 176 + xdr_process_buf(body, body_offset, body->len - body_offset, 177 + spkm3_checksummer, &desc); 178 + crypto_hash_final(&desc, cksum->data); 179 + 180 + out: 181 + crypto_free_hash(desc.tfm); 182 + 183 + return err ? GSS_S_FAILURE : 0; 184 + } 185 + 186 + EXPORT_SYMBOL(make_spkm3_checksum);
+3 -3
net/sunrpc/auth_gss/gss_spkm3_token.c
··· 172 172 *(u8 *)hptr++ = zbit; 173 173 memcpy(hptr, ctxdata, elen); 174 174 hptr += elen; 175 - *hdrlen = hptr - top; 175 + *hdrlen = hptr - top; 176 176 } 177 - 178 - /* 177 + 178 + /* 179 179 * spkm3_mic_innercontext_token() 180 180 * 181 181 * *tokp points to the beginning of the SPKM_MIC token described
+46 -42
net/sunrpc/auth_gss/gss_spkm3_unseal.c
··· 54 54 struct xdr_buf *message_buffer, /* signbuf */ 55 55 int toktype) 56 56 { 57 + s32 checksum_type; 57 58 s32 code; 58 59 struct xdr_netobj wire_cksum = {.len =0, .data = NULL}; 59 60 char cksumdata[16]; 60 61 struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; 61 62 unsigned char *ptr = (unsigned char *)read_token->data; 62 - unsigned char *cksum; 63 + unsigned char *cksum; 63 64 int bodysize, md5elen; 64 65 int mic_hdrlen; 65 66 u32 ret = GSS_S_DEFECTIVE_TOKEN; 66 - 67 - dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len); 68 67 69 68 if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used, 70 69 &bodysize, &ptr, read_token->len)) ··· 71 72 72 73 /* decode the token */ 73 74 74 - if (toktype == SPKM_MIC_TOK) { 75 - 76 - if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) 77 - goto out; 78 - 79 - if (*cksum++ != 0x03) { 80 - dprintk("RPC: spkm3_read_token BAD checksum type\n"); 81 - goto out; 82 - } 83 - md5elen = *cksum++; 84 - cksum++; /* move past the zbit */ 85 - 86 - if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16)) 87 - goto out; 88 - 89 - /* HARD CODED FOR MD5 */ 90 - 91 - /* compute the checksum of the message. 92 - * ptr + 2 = start of header piece of checksum 93 - * mic_hdrlen + 2 = length of header piece of checksum 94 - */ 95 - ret = GSS_S_DEFECTIVE_TOKEN; 96 - code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2, 97 - mic_hdrlen + 2, 98 - message_buffer, 0, &md5cksum); 99 - 100 - if (code) 101 - goto out; 102 - 103 - dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n", 104 - wire_cksum.len); 105 - 106 - ret = GSS_S_BAD_SIG; 107 - code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); 108 - if (code) 109 - goto out; 110 - 111 - } else { 112 - dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype); 75 + if (toktype != SPKM_MIC_TOK) { 76 + dprintk("RPC: BAD SPKM3 token type: %d\n", toktype); 113 77 goto out; 114 78 } 79 + 80 + if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) 81 + goto out; 82 + 83 + if (*cksum++ != 0x03) { 84 + dprintk("RPC: spkm3_read_token BAD checksum type\n"); 85 + goto out; 86 + } 87 + md5elen = *cksum++; 88 + cksum++; /* move past the zbit */ 89 + 90 + if (!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16)) 91 + goto out; 92 + 93 + /* HARD CODED FOR MD5 */ 94 + 95 + /* compute the checksum of the message. 96 + * ptr + 2 = start of header piece of checksum 97 + * mic_hdrlen + 2 = length of header piece of checksum 98 + */ 99 + ret = GSS_S_DEFECTIVE_TOKEN; 100 + if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { 101 + dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm\n"); 102 + goto out; 103 + } 104 + 105 + checksum_type = CKSUMTYPE_HMAC_MD5; 106 + 107 + code = make_spkm3_checksum(checksum_type, 108 + &ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2, 109 + message_buffer, 0, &md5cksum); 110 + 111 + if (code) 112 + goto out; 113 + 114 + ret = GSS_S_BAD_SIG; 115 + code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); 116 + if (code) { 117 + dprintk("RPC: bad MIC checksum\n"); 118 + goto out; 119 + } 120 + 115 121 116 122 /* XXX: need to add expiration and sequencing */ 117 123 ret = GSS_S_COMPLETE;