diff options
author | Kevin Coffman <kwc@citi.umich.edu> | 2010-03-17 13:02:59 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-05-14 15:09:18 -0400 |
commit | de9c17eb4a912c9028f7b470eb80815144883b26 (patch) | |
tree | 3e681897cff2db43f91c1e5e2f7dcad9598165c9 | |
parent | c43abaedaff92a7bcbfe04b593164bb5faba3078 (diff) |
gss_krb5: add support for new token formats in rfc4121
This is a step toward support for AES encryption types which are
required to use the new token formats defined in rfc4121.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
[SteveD: Fixed a typo in gss_verify_mic_v2()]
Signed-off-by: Steve Dickson <steved@redhat.com>
[Trond: Got rid of the TEST_ROTATE/TEST_EXTRA_COUNT crap]
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | include/linux/sunrpc/gss_krb5.h | 28 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_crypto.c | 74 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_seal.c | 69 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_unseal.c | 61 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_wrap.c | 174 |
5 files changed, 406 insertions, 0 deletions
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index db0522b4c4c9..0085a30fd204 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h | |||
@@ -53,6 +53,8 @@ | |||
53 | /* Maximum blocksize for the supported crypto algorithms */ | 53 | /* Maximum blocksize for the supported crypto algorithms */ |
54 | #define GSS_KRB5_MAX_BLOCKSIZE (16) | 54 | #define GSS_KRB5_MAX_BLOCKSIZE (16) |
55 | 55 | ||
56 | struct krb5_ctx; | ||
57 | |||
56 | struct gss_krb5_enctype { | 58 | struct gss_krb5_enctype { |
57 | const u32 etype; /* encryption (key) type */ | 59 | const u32 etype; /* encryption (key) type */ |
58 | const u32 ctype; /* checksum type */ | 60 | const u32 ctype; /* checksum type */ |
@@ -75,6 +77,12 @@ struct gss_krb5_enctype { | |||
75 | u32 (*mk_key) (const struct gss_krb5_enctype *gk5e, | 77 | u32 (*mk_key) (const struct gss_krb5_enctype *gk5e, |
76 | struct xdr_netobj *in, | 78 | struct xdr_netobj *in, |
77 | struct xdr_netobj *out); /* complete key generation */ | 79 | struct xdr_netobj *out); /* complete key generation */ |
80 | u32 (*encrypt_v2) (struct krb5_ctx *kctx, u32 offset, | ||
81 | struct xdr_buf *buf, int ec, | ||
82 | struct page **pages); /* v2 encryption function */ | ||
83 | u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset, | ||
84 | struct xdr_buf *buf, u32 *headskip, | ||
85 | u32 *tailskip); /* v2 decryption function */ | ||
78 | }; | 86 | }; |
79 | 87 | ||
80 | /* krb5_ctx flags definitions */ | 88 | /* krb5_ctx flags definitions */ |
@@ -112,6 +120,18 @@ extern spinlock_t krb5_seq_lock; | |||
112 | #define KG_TOK_MIC_MSG 0x0101 | 120 | #define KG_TOK_MIC_MSG 0x0101 |
113 | #define KG_TOK_WRAP_MSG 0x0201 | 121 | #define KG_TOK_WRAP_MSG 0x0201 |
114 | 122 | ||
123 | #define KG2_TOK_INITIAL 0x0101 | ||
124 | #define KG2_TOK_RESPONSE 0x0202 | ||
125 | #define KG2_TOK_MIC 0x0404 | ||
126 | #define KG2_TOK_WRAP 0x0504 | ||
127 | |||
128 | #define KG2_TOKEN_FLAG_SENTBYACCEPTOR 0x01 | ||
129 | #define KG2_TOKEN_FLAG_SEALED 0x02 | ||
130 | #define KG2_TOKEN_FLAG_ACCEPTORSUBKEY 0x04 | ||
131 | |||
132 | #define KG2_RESP_FLAG_ERROR 0x0001 | ||
133 | #define KG2_RESP_FLAG_DELEG_OK 0x0002 | ||
134 | |||
115 | enum sgn_alg { | 135 | enum sgn_alg { |
116 | SGN_ALG_DES_MAC_MD5 = 0x0000, | 136 | SGN_ALG_DES_MAC_MD5 = 0x0000, |
117 | SGN_ALG_MD2_5 = 0x0001, | 137 | SGN_ALG_MD2_5 = 0x0001, |
@@ -136,6 +156,9 @@ enum seal_alg { | |||
136 | #define CKSUMTYPE_RSA_MD5_DES 0x0008 | 156 | #define CKSUMTYPE_RSA_MD5_DES 0x0008 |
137 | #define CKSUMTYPE_NIST_SHA 0x0009 | 157 | #define CKSUMTYPE_NIST_SHA 0x0009 |
138 | #define CKSUMTYPE_HMAC_SHA1_DES3 0x000c | 158 | #define CKSUMTYPE_HMAC_SHA1_DES3 0x000c |
159 | #define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f | ||
160 | #define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010 | ||
161 | #define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */ | ||
139 | 162 | ||
140 | /* from gssapi_err_krb5.h */ | 163 | /* from gssapi_err_krb5.h */ |
141 | #define KG_CCACHE_NOMATCH (39756032L) | 164 | #define KG_CCACHE_NOMATCH (39756032L) |
@@ -212,6 +235,11 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, | |||
212 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | 235 | struct xdr_buf *body, int body_offset, u8 *cksumkey, |
213 | struct xdr_netobj *cksumout); | 236 | struct xdr_netobj *cksumout); |
214 | 237 | ||
238 | u32 | ||
239 | make_checksum_v2(struct krb5_ctx *, char *header, int hdrlen, | ||
240 | struct xdr_buf *body, int body_offset, u8 *key, | ||
241 | struct xdr_netobj *cksum); | ||
242 | |||
215 | u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, | 243 | u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, |
216 | struct xdr_netobj *); | 244 | struct xdr_netobj *); |
217 | 245 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index bb76873aa019..ca52ac28a537 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
@@ -197,6 +197,80 @@ out: | |||
197 | return err ? GSS_S_FAILURE : 0; | 197 | return err ? GSS_S_FAILURE : 0; |
198 | } | 198 | } |
199 | 199 | ||
200 | /* | ||
201 | * checksum the plaintext data and hdrlen bytes of the token header | ||
202 | * Per rfc4121, sec. 4.2.4, the checksum is performed over the data | ||
203 | * body then over the first 16 octets of the MIC token | ||
204 | * Inclusion of the header data in the calculation of the | ||
205 | * checksum is optional. | ||
206 | */ | ||
207 | u32 | ||
208 | make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen, | ||
209 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | ||
210 | struct xdr_netobj *cksumout) | ||
211 | { | ||
212 | struct hash_desc desc; | ||
213 | struct scatterlist sg[1]; | ||
214 | int err; | ||
215 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
216 | unsigned int checksumlen; | ||
217 | |||
218 | if (kctx->gk5e->keyed_cksum == 0) { | ||
219 | dprintk("%s: expected keyed hash for %s\n", | ||
220 | __func__, kctx->gk5e->name); | ||
221 | return GSS_S_FAILURE; | ||
222 | } | ||
223 | if (cksumkey == NULL) { | ||
224 | dprintk("%s: no key supplied for %s\n", | ||
225 | __func__, kctx->gk5e->name); | ||
226 | return GSS_S_FAILURE; | ||
227 | } | ||
228 | |||
229 | desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, | ||
230 | CRYPTO_ALG_ASYNC); | ||
231 | if (IS_ERR(desc.tfm)) | ||
232 | return GSS_S_FAILURE; | ||
233 | checksumlen = crypto_hash_digestsize(desc.tfm); | ||
234 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
235 | |||
236 | err = crypto_hash_setkey(desc.tfm, cksumkey, kctx->gk5e->keylength); | ||
237 | if (err) | ||
238 | goto out; | ||
239 | |||
240 | err = crypto_hash_init(&desc); | ||
241 | if (err) | ||
242 | goto out; | ||
243 | err = xdr_process_buf(body, body_offset, body->len - body_offset, | ||
244 | checksummer, &desc); | ||
245 | if (err) | ||
246 | goto out; | ||
247 | if (header != NULL) { | ||
248 | sg_init_one(sg, header, hdrlen); | ||
249 | err = crypto_hash_update(&desc, sg, hdrlen); | ||
250 | if (err) | ||
251 | goto out; | ||
252 | } | ||
253 | err = crypto_hash_final(&desc, checksumdata); | ||
254 | if (err) | ||
255 | goto out; | ||
256 | |||
257 | cksumout->len = kctx->gk5e->cksumlength; | ||
258 | |||
259 | switch (kctx->gk5e->ctype) { | ||
260 | case CKSUMTYPE_HMAC_SHA1_96_AES128: | ||
261 | case CKSUMTYPE_HMAC_SHA1_96_AES256: | ||
262 | /* note that this truncates the hash */ | ||
263 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | ||
264 | break; | ||
265 | default: | ||
266 | BUG(); | ||
267 | break; | ||
268 | } | ||
269 | out: | ||
270 | crypto_free_hash(desc.tfm); | ||
271 | return err ? GSS_S_FAILURE : 0; | ||
272 | } | ||
273 | |||
200 | struct encryptor_desc { | 274 | struct encryptor_desc { |
201 | u8 iv[GSS_KRB5_MAX_BLOCKSIZE]; | 275 | u8 iv[GSS_KRB5_MAX_BLOCKSIZE]; |
202 | struct blkcipher_desc desc; | 276 | struct blkcipher_desc desc; |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 7ede900049a7..477a546d19bb 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
@@ -91,6 +91,33 @@ setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) | |||
91 | return (char *)krb5_hdr; | 91 | return (char *)krb5_hdr; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void * | ||
95 | setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) | ||
96 | { | ||
97 | __be16 *ptr, *krb5_hdr; | ||
98 | u8 *p, flags = 0x00; | ||
99 | |||
100 | if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) | ||
101 | flags |= 0x01; | ||
102 | if (ctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) | ||
103 | flags |= 0x04; | ||
104 | |||
105 | /* Per rfc 4121, sec 4.2.6.1, there is no header, | ||
106 | * just start the token */ | ||
107 | krb5_hdr = ptr = (__be16 *)token->data; | ||
108 | |||
109 | *ptr++ = KG2_TOK_MIC; | ||
110 | p = (u8 *)ptr; | ||
111 | *p++ = flags; | ||
112 | *p++ = 0xff; | ||
113 | ptr = (__be16 *)p; | ||
114 | *ptr++ = 0xffff; | ||
115 | *ptr++ = 0xffff; | ||
116 | |||
117 | token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | ||
118 | return krb5_hdr; | ||
119 | } | ||
120 | |||
94 | static u32 | 121 | static u32 |
95 | gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, | 122 | gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, |
96 | struct xdr_netobj *token) | 123 | struct xdr_netobj *token) |
@@ -133,6 +160,45 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, | |||
133 | } | 160 | } |
134 | 161 | ||
135 | u32 | 162 | u32 |
163 | gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, | ||
164 | struct xdr_netobj *token) | ||
165 | { | ||
166 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
167 | struct xdr_netobj cksumobj = { .len = sizeof(cksumdata), | ||
168 | .data = cksumdata}; | ||
169 | void *krb5_hdr; | ||
170 | s32 now; | ||
171 | u64 seq_send; | ||
172 | u8 *cksumkey; | ||
173 | |||
174 | dprintk("RPC: %s\n", __func__); | ||
175 | |||
176 | krb5_hdr = setup_token_v2(ctx, token); | ||
177 | |||
178 | /* Set up the sequence number. Now 64-bits in clear | ||
179 | * text and w/o direction indicator */ | ||
180 | spin_lock(&krb5_seq_lock); | ||
181 | seq_send = ctx->seq_send64++; | ||
182 | spin_unlock(&krb5_seq_lock); | ||
183 | *((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send); | ||
184 | |||
185 | if (ctx->initiate) | ||
186 | cksumkey = ctx->initiator_sign; | ||
187 | else | ||
188 | cksumkey = ctx->acceptor_sign; | ||
189 | |||
190 | if (make_checksum_v2(ctx, krb5_hdr, GSS_KRB5_TOK_HDR_LEN, | ||
191 | text, 0, cksumkey, &cksumobj)) | ||
192 | return GSS_S_FAILURE; | ||
193 | |||
194 | memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, cksumobj.data, cksumobj.len); | ||
195 | |||
196 | now = get_seconds(); | ||
197 | |||
198 | return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | ||
199 | } | ||
200 | |||
201 | u32 | ||
136 | gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | 202 | gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, |
137 | struct xdr_netobj *token) | 203 | struct xdr_netobj *token) |
138 | { | 204 | { |
@@ -144,6 +210,9 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | |||
144 | case ENCTYPE_DES_CBC_RAW: | 210 | case ENCTYPE_DES_CBC_RAW: |
145 | case ENCTYPE_DES3_CBC_RAW: | 211 | case ENCTYPE_DES3_CBC_RAW: |
146 | return gss_get_mic_v1(ctx, text, token); | 212 | return gss_get_mic_v1(ctx, text, token); |
213 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
214 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
215 | return gss_get_mic_v2(ctx, text, token); | ||
147 | } | 216 | } |
148 | } | 217 | } |
149 | 218 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 3e15bdb5a9eb..4ede4cc4391f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c | |||
@@ -141,6 +141,64 @@ gss_verify_mic_v1(struct krb5_ctx *ctx, | |||
141 | return GSS_S_COMPLETE; | 141 | return GSS_S_COMPLETE; |
142 | } | 142 | } |
143 | 143 | ||
144 | static u32 | ||
145 | gss_verify_mic_v2(struct krb5_ctx *ctx, | ||
146 | struct xdr_buf *message_buffer, struct xdr_netobj *read_token) | ||
147 | { | ||
148 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
149 | struct xdr_netobj cksumobj = {.len = sizeof(cksumdata), | ||
150 | .data = cksumdata}; | ||
151 | s32 now; | ||
152 | u64 seqnum; | ||
153 | u8 *ptr = read_token->data; | ||
154 | u8 *cksumkey; | ||
155 | u8 flags; | ||
156 | int i; | ||
157 | |||
158 | dprintk("RPC: %s\n", __func__); | ||
159 | |||
160 | if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_MIC) | ||
161 | return GSS_S_DEFECTIVE_TOKEN; | ||
162 | |||
163 | flags = ptr[2]; | ||
164 | if ((!ctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) || | ||
165 | (ctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR))) | ||
166 | return GSS_S_BAD_SIG; | ||
167 | |||
168 | if (flags & KG2_TOKEN_FLAG_SEALED) { | ||
169 | dprintk("%s: token has unexpected sealed flag\n", __func__); | ||
170 | return GSS_S_FAILURE; | ||
171 | } | ||
172 | |||
173 | for (i = 3; i < 8; i++) | ||
174 | if (ptr[i] != 0xff) | ||
175 | return GSS_S_DEFECTIVE_TOKEN; | ||
176 | |||
177 | if (ctx->initiate) | ||
178 | cksumkey = ctx->acceptor_sign; | ||
179 | else | ||
180 | cksumkey = ctx->initiator_sign; | ||
181 | |||
182 | if (make_checksum_v2(ctx, ptr, GSS_KRB5_TOK_HDR_LEN, message_buffer, 0, | ||
183 | cksumkey, &cksumobj)) | ||
184 | return GSS_S_FAILURE; | ||
185 | |||
186 | if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN, | ||
187 | ctx->gk5e->cksumlength)) | ||
188 | return GSS_S_BAD_SIG; | ||
189 | |||
190 | /* it got through unscathed. Make sure the context is unexpired */ | ||
191 | now = get_seconds(); | ||
192 | if (now > ctx->endtime) | ||
193 | return GSS_S_CONTEXT_EXPIRED; | ||
194 | |||
195 | /* do sequencing checks */ | ||
196 | |||
197 | seqnum = be64_to_cpup((__be64 *)ptr + 8); | ||
198 | |||
199 | return GSS_S_COMPLETE; | ||
200 | } | ||
201 | |||
144 | u32 | 202 | u32 |
145 | gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | 203 | gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, |
146 | struct xdr_buf *message_buffer, | 204 | struct xdr_buf *message_buffer, |
@@ -154,6 +212,9 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
154 | case ENCTYPE_DES_CBC_RAW: | 212 | case ENCTYPE_DES_CBC_RAW: |
155 | case ENCTYPE_DES3_CBC_RAW: | 213 | case ENCTYPE_DES3_CBC_RAW: |
156 | return gss_verify_mic_v1(ctx, message_buffer, read_token); | 214 | return gss_verify_mic_v1(ctx, message_buffer, read_token); |
215 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
216 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
217 | return gss_verify_mic_v2(ctx, message_buffer, read_token); | ||
157 | } | 218 | } |
158 | } | 219 | } |
159 | 220 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 1c8ebd3dbd3c..4aa46b28298c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
@@ -340,6 +340,174 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
340 | return GSS_S_COMPLETE; | 340 | return GSS_S_COMPLETE; |
341 | } | 341 | } |
342 | 342 | ||
343 | /* | ||
344 | * We cannot currently handle tokens with rotated data. We need a | ||
345 | * generalized routine to rotate the data in place. It is anticipated | ||
346 | * that we won't encounter rotated data in the general case. | ||
347 | */ | ||
348 | static u32 | ||
349 | rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc) | ||
350 | { | ||
351 | unsigned int realrrc = rrc % (buf->len - offset - GSS_KRB5_TOK_HDR_LEN); | ||
352 | |||
353 | if (realrrc == 0) | ||
354 | return 0; | ||
355 | |||
356 | dprintk("%s: cannot process token with rotated data: " | ||
357 | "rrc %u, realrrc %u\n", __func__, rrc, realrrc); | ||
358 | return 1; | ||
359 | } | ||
360 | |||
361 | static u32 | ||
362 | gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, | ||
363 | struct xdr_buf *buf, struct page **pages) | ||
364 | { | ||
365 | int blocksize; | ||
366 | u8 *ptr, *plainhdr; | ||
367 | s32 now; | ||
368 | u8 flags = 0x00; | ||
369 | __be16 *be16ptr, ec = 0; | ||
370 | __be64 *be64ptr; | ||
371 | u32 err; | ||
372 | |||
373 | dprintk("RPC: %s\n", __func__); | ||
374 | |||
375 | if (kctx->gk5e->encrypt_v2 == NULL) | ||
376 | return GSS_S_FAILURE; | ||
377 | |||
378 | /* make room for gss token header */ | ||
379 | if (xdr_extend_head(buf, offset, GSS_KRB5_TOK_HDR_LEN)) | ||
380 | return GSS_S_FAILURE; | ||
381 | |||
382 | /* construct gss token header */ | ||
383 | ptr = plainhdr = buf->head[0].iov_base + offset; | ||
384 | *ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff); | ||
385 | *ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff); | ||
386 | |||
387 | if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) | ||
388 | flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR; | ||
389 | if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0) | ||
390 | flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY; | ||
391 | /* We always do confidentiality in wrap tokens */ | ||
392 | flags |= KG2_TOKEN_FLAG_SEALED; | ||
393 | |||
394 | *ptr++ = flags; | ||
395 | *ptr++ = 0xff; | ||
396 | be16ptr = (__be16 *)ptr; | ||
397 | |||
398 | blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc); | ||
399 | *be16ptr++ = cpu_to_be16(ec); | ||
400 | /* "inner" token header always uses 0 for RRC */ | ||
401 | *be16ptr++ = cpu_to_be16(0); | ||
402 | |||
403 | be64ptr = (__be64 *)be16ptr; | ||
404 | spin_lock(&krb5_seq_lock); | ||
405 | *be64ptr = cpu_to_be64(kctx->seq_send64++); | ||
406 | spin_unlock(&krb5_seq_lock); | ||
407 | |||
408 | err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages); | ||
409 | if (err) | ||
410 | return err; | ||
411 | |||
412 | now = get_seconds(); | ||
413 | return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | ||
414 | } | ||
415 | |||
416 | static u32 | ||
417 | gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | ||
418 | { | ||
419 | s32 now; | ||
420 | u64 seqnum; | ||
421 | u8 *ptr; | ||
422 | u8 flags = 0x00; | ||
423 | u16 ec, rrc; | ||
424 | int err; | ||
425 | u32 headskip, tailskip; | ||
426 | u8 decrypted_hdr[GSS_KRB5_TOK_HDR_LEN]; | ||
427 | unsigned int movelen; | ||
428 | |||
429 | |||
430 | dprintk("RPC: %s\n", __func__); | ||
431 | |||
432 | if (kctx->gk5e->decrypt_v2 == NULL) | ||
433 | return GSS_S_FAILURE; | ||
434 | |||
435 | ptr = buf->head[0].iov_base + offset; | ||
436 | |||
437 | if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_WRAP) | ||
438 | return GSS_S_DEFECTIVE_TOKEN; | ||
439 | |||
440 | flags = ptr[2]; | ||
441 | if ((!kctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) || | ||
442 | (kctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR))) | ||
443 | return GSS_S_BAD_SIG; | ||
444 | |||
445 | if ((flags & KG2_TOKEN_FLAG_SEALED) == 0) { | ||
446 | dprintk("%s: token missing expected sealed flag\n", __func__); | ||
447 | return GSS_S_DEFECTIVE_TOKEN; | ||
448 | } | ||
449 | |||
450 | if (ptr[3] != 0xff) | ||
451 | return GSS_S_DEFECTIVE_TOKEN; | ||
452 | |||
453 | ec = be16_to_cpup((__be16 *)(ptr + 4)); | ||
454 | rrc = be16_to_cpup((__be16 *)(ptr + 6)); | ||
455 | |||
456 | seqnum = be64_to_cpup((__be64 *)(ptr + 8)); | ||
457 | |||
458 | if (rrc != 0) { | ||
459 | err = rotate_left(kctx, offset, buf, rrc); | ||
460 | if (err) | ||
461 | return GSS_S_FAILURE; | ||
462 | } | ||
463 | |||
464 | err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf, | ||
465 | &headskip, &tailskip); | ||
466 | if (err) | ||
467 | return GSS_S_FAILURE; | ||
468 | |||
469 | /* | ||
470 | * Retrieve the decrypted gss token header and verify | ||
471 | * it against the original | ||
472 | */ | ||
473 | err = read_bytes_from_xdr_buf(buf, | ||
474 | buf->len - GSS_KRB5_TOK_HDR_LEN - tailskip, | ||
475 | decrypted_hdr, GSS_KRB5_TOK_HDR_LEN); | ||
476 | if (err) { | ||
477 | dprintk("%s: error %u getting decrypted_hdr\n", __func__, err); | ||
478 | return GSS_S_FAILURE; | ||
479 | } | ||
480 | if (memcmp(ptr, decrypted_hdr, 6) | ||
481 | || memcmp(ptr + 8, decrypted_hdr + 8, 8)) { | ||
482 | dprintk("%s: token hdr, plaintext hdr mismatch!\n", __func__); | ||
483 | return GSS_S_FAILURE; | ||
484 | } | ||
485 | |||
486 | /* do sequencing checks */ | ||
487 | |||
488 | /* it got through unscathed. Make sure the context is unexpired */ | ||
489 | now = get_seconds(); | ||
490 | if (now > kctx->endtime) | ||
491 | return GSS_S_CONTEXT_EXPIRED; | ||
492 | |||
493 | /* | ||
494 | * Move the head data back to the right position in xdr_buf. | ||
495 | * We ignore any "ec" data since it might be in the head or | ||
496 | * the tail, and we really don't need to deal with it. | ||
497 | * Note that buf->head[0].iov_len may indicate the available | ||
498 | * head buffer space rather than that actually occupied. | ||
499 | */ | ||
500 | movelen = min_t(unsigned int, buf->head[0].iov_len, buf->len); | ||
501 | movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip; | ||
502 | BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen > | ||
503 | buf->head[0].iov_len); | ||
504 | memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen); | ||
505 | buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip; | ||
506 | buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip; | ||
507 | |||
508 | return GSS_S_COMPLETE; | ||
509 | } | ||
510 | |||
343 | u32 | 511 | u32 |
344 | gss_wrap_kerberos(struct gss_ctx *gctx, int offset, | 512 | gss_wrap_kerberos(struct gss_ctx *gctx, int offset, |
345 | struct xdr_buf *buf, struct page **pages) | 513 | struct xdr_buf *buf, struct page **pages) |
@@ -352,6 +520,9 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset, | |||
352 | case ENCTYPE_DES_CBC_RAW: | 520 | case ENCTYPE_DES_CBC_RAW: |
353 | case ENCTYPE_DES3_CBC_RAW: | 521 | case ENCTYPE_DES3_CBC_RAW: |
354 | return gss_wrap_kerberos_v1(kctx, offset, buf, pages); | 522 | return gss_wrap_kerberos_v1(kctx, offset, buf, pages); |
523 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
524 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
525 | return gss_wrap_kerberos_v2(kctx, offset, buf, pages); | ||
355 | } | 526 | } |
356 | } | 527 | } |
357 | 528 | ||
@@ -366,6 +537,9 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf) | |||
366 | case ENCTYPE_DES_CBC_RAW: | 537 | case ENCTYPE_DES_CBC_RAW: |
367 | case ENCTYPE_DES3_CBC_RAW: | 538 | case ENCTYPE_DES3_CBC_RAW: |
368 | return gss_unwrap_kerberos_v1(kctx, offset, buf); | 539 | return gss_unwrap_kerberos_v1(kctx, offset, buf); |
540 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
541 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
542 | return gss_unwrap_kerberos_v2(kctx, offset, buf); | ||
369 | } | 543 | } |
370 | } | 544 | } |
371 | 545 | ||