diff options
author | Kevin Coffman <kwc@citi.umich.edu> | 2010-03-17 13:03:06 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-05-14 15:09:20 -0400 |
commit | fffdaef2eb4a7333952e55cf97f1fc0fcc35f981 (patch) | |
tree | bd4e4b39ec901feb27b91d33d4f52e723f3584d7 | |
parent | 5af46547ec451918f3ba51efe59b317d33adf701 (diff) |
gss_krb5: Add support for rc4-hmac encryption
Add necessary changes to add kernel support for the rc4-hmac Kerberos
encryption type used by Microsoft and described in rfc4757.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Steve Dickson <steved@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | include/linux/sunrpc/gss_krb5.h | 9 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_crypto.c | 255 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 96 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_seal.c | 1 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_seqnum.c | 77 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_unseal.c | 1 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_wrap.c | 66 |
7 files changed, 492 insertions, 13 deletions
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index 79f6ac2492f5..5e774a5abf2c 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h | |||
@@ -317,5 +317,14 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, | |||
317 | struct xdr_buf *buf, u32 *plainoffset, | 317 | struct xdr_buf *buf, u32 *plainoffset, |
318 | u32 *plainlen); | 318 | u32 *plainlen); |
319 | 319 | ||
320 | int | ||
321 | krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, | ||
322 | struct crypto_blkcipher *cipher, | ||
323 | unsigned char *cksum); | ||
324 | |||
325 | int | ||
326 | krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, | ||
327 | struct crypto_blkcipher *cipher, | ||
328 | s32 seqnum); | ||
320 | void | 329 | void |
321 | gss_krb5_make_confounder(char *p, u32 conflen); | 330 | gss_krb5_make_confounder(char *p, u32 conflen); |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index ed4106a3daf2..75ee993ea057 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
@@ -124,6 +124,114 @@ checksummer(struct scatterlist *sg, void *data) | |||
124 | return crypto_hash_update(desc, sg, sg->length); | 124 | return crypto_hash_update(desc, sg, sg->length); |
125 | } | 125 | } |
126 | 126 | ||
127 | static int | ||
128 | arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4]) | ||
129 | { | ||
130 | unsigned int ms_usage; | ||
131 | |||
132 | switch (usage) { | ||
133 | case KG_USAGE_SIGN: | ||
134 | ms_usage = 15; | ||
135 | break; | ||
136 | case KG_USAGE_SEAL: | ||
137 | ms_usage = 13; | ||
138 | break; | ||
139 | default: | ||
140 | return EINVAL;; | ||
141 | } | ||
142 | salt[0] = (ms_usage >> 0) & 0xff; | ||
143 | salt[1] = (ms_usage >> 8) & 0xff; | ||
144 | salt[2] = (ms_usage >> 16) & 0xff; | ||
145 | salt[3] = (ms_usage >> 24) & 0xff; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static u32 | ||
151 | make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen, | ||
152 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | ||
153 | unsigned int usage, struct xdr_netobj *cksumout) | ||
154 | { | ||
155 | struct hash_desc desc; | ||
156 | struct scatterlist sg[1]; | ||
157 | int err; | ||
158 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
159 | u8 rc4salt[4]; | ||
160 | struct crypto_hash *md5; | ||
161 | struct crypto_hash *hmac_md5; | ||
162 | |||
163 | if (cksumkey == NULL) | ||
164 | return GSS_S_FAILURE; | ||
165 | |||
166 | if (cksumout->len < kctx->gk5e->cksumlength) { | ||
167 | dprintk("%s: checksum buffer length, %u, too small for %s\n", | ||
168 | __func__, cksumout->len, kctx->gk5e->name); | ||
169 | return GSS_S_FAILURE; | ||
170 | } | ||
171 | |||
172 | if (arcfour_hmac_md5_usage_to_salt(usage, rc4salt)) { | ||
173 | dprintk("%s: invalid usage value %u\n", __func__, usage); | ||
174 | return GSS_S_FAILURE; | ||
175 | } | ||
176 | |||
177 | md5 = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | ||
178 | if (IS_ERR(md5)) | ||
179 | return GSS_S_FAILURE; | ||
180 | |||
181 | hmac_md5 = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, | ||
182 | CRYPTO_ALG_ASYNC); | ||
183 | if (IS_ERR(hmac_md5)) { | ||
184 | crypto_free_hash(md5); | ||
185 | return GSS_S_FAILURE; | ||
186 | } | ||
187 | |||
188 | desc.tfm = md5; | ||
189 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
190 | |||
191 | err = crypto_hash_init(&desc); | ||
192 | if (err) | ||
193 | goto out; | ||
194 | sg_init_one(sg, rc4salt, 4); | ||
195 | err = crypto_hash_update(&desc, sg, 4); | ||
196 | if (err) | ||
197 | goto out; | ||
198 | |||
199 | sg_init_one(sg, header, hdrlen); | ||
200 | err = crypto_hash_update(&desc, sg, hdrlen); | ||
201 | if (err) | ||
202 | goto out; | ||
203 | err = xdr_process_buf(body, body_offset, body->len - body_offset, | ||
204 | checksummer, &desc); | ||
205 | if (err) | ||
206 | goto out; | ||
207 | err = crypto_hash_final(&desc, checksumdata); | ||
208 | if (err) | ||
209 | goto out; | ||
210 | |||
211 | desc.tfm = hmac_md5; | ||
212 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
213 | |||
214 | err = crypto_hash_init(&desc); | ||
215 | if (err) | ||
216 | goto out; | ||
217 | err = crypto_hash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength); | ||
218 | if (err) | ||
219 | goto out; | ||
220 | |||
221 | sg_init_one(sg, checksumdata, crypto_hash_digestsize(md5)); | ||
222 | err = crypto_hash_digest(&desc, sg, crypto_hash_digestsize(md5), | ||
223 | checksumdata); | ||
224 | if (err) | ||
225 | goto out; | ||
226 | |||
227 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | ||
228 | cksumout->len = kctx->gk5e->cksumlength; | ||
229 | out: | ||
230 | crypto_free_hash(md5); | ||
231 | crypto_free_hash(hmac_md5); | ||
232 | return err ? GSS_S_FAILURE : 0; | ||
233 | } | ||
234 | |||
127 | /* | 235 | /* |
128 | * checksum the plaintext data and hdrlen bytes of the token header | 236 | * checksum the plaintext data and hdrlen bytes of the token header |
129 | * The checksum is performed over the first 8 bytes of the | 237 | * The checksum is performed over the first 8 bytes of the |
@@ -140,6 +248,11 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, | |||
140 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | 248 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; |
141 | unsigned int checksumlen; | 249 | unsigned int checksumlen; |
142 | 250 | ||
251 | if (kctx->gk5e->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR) | ||
252 | return make_checksum_hmac_md5(kctx, header, hdrlen, | ||
253 | body, body_offset, | ||
254 | cksumkey, usage, cksumout); | ||
255 | |||
143 | if (cksumout->len < kctx->gk5e->cksumlength) { | 256 | if (cksumout->len < kctx->gk5e->cksumlength) { |
144 | dprintk("%s: checksum buffer length, %u, too small for %s\n", | 257 | dprintk("%s: checksum buffer length, %u, too small for %s\n", |
145 | __func__, cksumout->len, kctx->gk5e->name); | 258 | __func__, cksumout->len, kctx->gk5e->name); |
@@ -733,3 +846,145 @@ out_err: | |||
733 | ret = GSS_S_FAILURE; | 846 | ret = GSS_S_FAILURE; |
734 | return ret; | 847 | return ret; |
735 | } | 848 | } |
849 | |||
850 | /* | ||
851 | * Compute Kseq given the initial session key and the checksum. | ||
852 | * Set the key of the given cipher. | ||
853 | */ | ||
854 | int | ||
855 | krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, struct crypto_blkcipher *cipher, | ||
856 | unsigned char *cksum) | ||
857 | { | ||
858 | struct crypto_hash *hmac; | ||
859 | struct hash_desc desc; | ||
860 | struct scatterlist sg[1]; | ||
861 | u8 Kseq[GSS_KRB5_MAX_KEYLEN]; | ||
862 | u32 zeroconstant = 0; | ||
863 | int err; | ||
864 | |||
865 | dprintk("%s: entered\n", __func__); | ||
866 | |||
867 | hmac = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | ||
868 | if (IS_ERR(hmac)) { | ||
869 | dprintk("%s: error %ld, allocating hash '%s'\n", | ||
870 | __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name); | ||
871 | return PTR_ERR(hmac); | ||
872 | } | ||
873 | |||
874 | desc.tfm = hmac; | ||
875 | desc.flags = 0; | ||
876 | |||
877 | err = crypto_hash_init(&desc); | ||
878 | if (err) | ||
879 | goto out_err; | ||
880 | |||
881 | /* Compute intermediate Kseq from session key */ | ||
882 | err = crypto_hash_setkey(hmac, kctx->Ksess, kctx->gk5e->keylength); | ||
883 | if (err) | ||
884 | goto out_err; | ||
885 | |||
886 | sg_init_table(sg, 1); | ||
887 | sg_set_buf(sg, &zeroconstant, 4); | ||
888 | |||
889 | err = crypto_hash_digest(&desc, sg, 4, Kseq); | ||
890 | if (err) | ||
891 | goto out_err; | ||
892 | |||
893 | /* Compute final Kseq from the checksum and intermediate Kseq */ | ||
894 | err = crypto_hash_setkey(hmac, Kseq, kctx->gk5e->keylength); | ||
895 | if (err) | ||
896 | goto out_err; | ||
897 | |||
898 | sg_set_buf(sg, cksum, 8); | ||
899 | |||
900 | err = crypto_hash_digest(&desc, sg, 8, Kseq); | ||
901 | if (err) | ||
902 | goto out_err; | ||
903 | |||
904 | err = crypto_blkcipher_setkey(cipher, Kseq, kctx->gk5e->keylength); | ||
905 | if (err) | ||
906 | goto out_err; | ||
907 | |||
908 | err = 0; | ||
909 | |||
910 | out_err: | ||
911 | crypto_free_hash(hmac); | ||
912 | dprintk("%s: returning %d\n", __func__, err); | ||
913 | return err; | ||
914 | } | ||
915 | |||
916 | /* | ||
917 | * Compute Kcrypt given the initial session key and the plaintext seqnum. | ||
918 | * Set the key of cipher kctx->enc. | ||
919 | */ | ||
920 | int | ||
921 | krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, struct crypto_blkcipher *cipher, | ||
922 | s32 seqnum) | ||
923 | { | ||
924 | struct crypto_hash *hmac; | ||
925 | struct hash_desc desc; | ||
926 | struct scatterlist sg[1]; | ||
927 | u8 Kcrypt[GSS_KRB5_MAX_KEYLEN]; | ||
928 | u8 zeroconstant[4] = {0}; | ||
929 | u8 seqnumarray[4]; | ||
930 | int err, i; | ||
931 | |||
932 | dprintk("%s: entered, seqnum %u\n", __func__, seqnum); | ||
933 | |||
934 | hmac = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | ||
935 | if (IS_ERR(hmac)) { | ||
936 | dprintk("%s: error %ld, allocating hash '%s'\n", | ||
937 | __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name); | ||
938 | return PTR_ERR(hmac); | ||
939 | } | ||
940 | |||
941 | desc.tfm = hmac; | ||
942 | desc.flags = 0; | ||
943 | |||
944 | err = crypto_hash_init(&desc); | ||
945 | if (err) | ||
946 | goto out_err; | ||
947 | |||
948 | /* Compute intermediate Kcrypt from session key */ | ||
949 | for (i = 0; i < kctx->gk5e->keylength; i++) | ||
950 | Kcrypt[i] = kctx->Ksess[i] ^ 0xf0; | ||
951 | |||
952 | err = crypto_hash_setkey(hmac, Kcrypt, kctx->gk5e->keylength); | ||
953 | if (err) | ||
954 | goto out_err; | ||
955 | |||
956 | sg_init_table(sg, 1); | ||
957 | sg_set_buf(sg, zeroconstant, 4); | ||
958 | |||
959 | err = crypto_hash_digest(&desc, sg, 4, Kcrypt); | ||
960 | if (err) | ||
961 | goto out_err; | ||
962 | |||
963 | /* Compute final Kcrypt from the seqnum and intermediate Kcrypt */ | ||
964 | err = crypto_hash_setkey(hmac, Kcrypt, kctx->gk5e->keylength); | ||
965 | if (err) | ||
966 | goto out_err; | ||
967 | |||
968 | seqnumarray[0] = (unsigned char) ((seqnum >> 24) & 0xff); | ||
969 | seqnumarray[1] = (unsigned char) ((seqnum >> 16) & 0xff); | ||
970 | seqnumarray[2] = (unsigned char) ((seqnum >> 8) & 0xff); | ||
971 | seqnumarray[3] = (unsigned char) ((seqnum >> 0) & 0xff); | ||
972 | |||
973 | sg_set_buf(sg, seqnumarray, 4); | ||
974 | |||
975 | err = crypto_hash_digest(&desc, sg, 4, Kcrypt); | ||
976 | if (err) | ||
977 | goto out_err; | ||
978 | |||
979 | err = crypto_blkcipher_setkey(cipher, Kcrypt, kctx->gk5e->keylength); | ||
980 | if (err) | ||
981 | goto out_err; | ||
982 | |||
983 | err = 0; | ||
984 | |||
985 | out_err: | ||
986 | crypto_free_hash(hmac); | ||
987 | dprintk("%s: returning %d\n", __func__, err); | ||
988 | return err; | ||
989 | } | ||
990 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index ef6b31349046..54eda5f0c58b 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
@@ -73,6 +73,27 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { | |||
73 | .keyed_cksum = 0, | 73 | .keyed_cksum = 0, |
74 | }, | 74 | }, |
75 | /* | 75 | /* |
76 | * RC4-HMAC | ||
77 | */ | ||
78 | { | ||
79 | .etype = ENCTYPE_ARCFOUR_HMAC, | ||
80 | .ctype = CKSUMTYPE_HMAC_MD5_ARCFOUR, | ||
81 | .name = "rc4-hmac", | ||
82 | .encrypt_name = "ecb(arc4)", | ||
83 | .cksum_name = "hmac(md5)", | ||
84 | .encrypt = krb5_encrypt, | ||
85 | .decrypt = krb5_decrypt, | ||
86 | .mk_key = NULL, | ||
87 | .signalg = SGN_ALG_HMAC_MD5, | ||
88 | .sealalg = SEAL_ALG_MICROSOFT_RC4, | ||
89 | .keybytes = 16, | ||
90 | .keylength = 16, | ||
91 | .blocksize = 1, | ||
92 | .conflen = 8, | ||
93 | .cksumlength = 8, | ||
94 | .keyed_cksum = 1, | ||
95 | }, | ||
96 | /* | ||
76 | * 3DES | 97 | * 3DES |
77 | */ | 98 | */ |
78 | { | 99 | { |
@@ -392,6 +413,79 @@ out_err: | |||
392 | return -EINVAL; | 413 | return -EINVAL; |
393 | } | 414 | } |
394 | 415 | ||
416 | /* | ||
417 | * Note that RC4 depends on deriving keys using the sequence | ||
418 | * number or the checksum of a token. Therefore, the final keys | ||
419 | * cannot be calculated until the token is being constructed! | ||
420 | */ | ||
421 | static int | ||
422 | context_derive_keys_rc4(struct krb5_ctx *ctx) | ||
423 | { | ||
424 | struct crypto_hash *hmac; | ||
425 | char sigkeyconstant[] = "signaturekey"; | ||
426 | int slen = strlen(sigkeyconstant) + 1; /* include null terminator */ | ||
427 | struct hash_desc desc; | ||
428 | struct scatterlist sg[1]; | ||
429 | int err; | ||
430 | |||
431 | dprintk("RPC: %s: entered\n", __func__); | ||
432 | /* | ||
433 | * derive cksum (aka Ksign) key | ||
434 | */ | ||
435 | hmac = crypto_alloc_hash(ctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | ||
436 | if (IS_ERR(hmac)) { | ||
437 | dprintk("%s: error %ld allocating hash '%s'\n", | ||
438 | __func__, PTR_ERR(hmac), ctx->gk5e->cksum_name); | ||
439 | err = PTR_ERR(hmac); | ||
440 | goto out_err; | ||
441 | } | ||
442 | |||
443 | err = crypto_hash_setkey(hmac, ctx->Ksess, ctx->gk5e->keylength); | ||
444 | if (err) | ||
445 | goto out_err_free_hmac; | ||
446 | |||
447 | sg_init_table(sg, 1); | ||
448 | sg_set_buf(sg, sigkeyconstant, slen); | ||
449 | |||
450 | desc.tfm = hmac; | ||
451 | desc.flags = 0; | ||
452 | |||
453 | err = crypto_hash_init(&desc); | ||
454 | if (err) | ||
455 | goto out_err_free_hmac; | ||
456 | |||
457 | err = crypto_hash_digest(&desc, sg, slen, ctx->cksum); | ||
458 | if (err) | ||
459 | goto out_err_free_hmac; | ||
460 | /* | ||
461 | * allocate hash, and blkciphers for data and seqnum encryption | ||
462 | */ | ||
463 | ctx->enc = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, | ||
464 | CRYPTO_ALG_ASYNC); | ||
465 | if (IS_ERR(ctx->enc)) { | ||
466 | err = PTR_ERR(ctx->enc); | ||
467 | goto out_err_free_hmac; | ||
468 | } | ||
469 | |||
470 | ctx->seq = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, | ||
471 | CRYPTO_ALG_ASYNC); | ||
472 | if (IS_ERR(ctx->seq)) { | ||
473 | crypto_free_blkcipher(ctx->enc); | ||
474 | err = PTR_ERR(ctx->seq); | ||
475 | goto out_err_free_hmac; | ||
476 | } | ||
477 | |||
478 | dprintk("RPC: %s: returning success\n", __func__); | ||
479 | |||
480 | err = 0; | ||
481 | |||
482 | out_err_free_hmac: | ||
483 | crypto_free_hash(hmac); | ||
484 | out_err: | ||
485 | dprintk("RPC: %s: returning %d\n", __func__, err); | ||
486 | return err; | ||
487 | } | ||
488 | |||
395 | static int | 489 | static int |
396 | context_derive_keys_new(struct krb5_ctx *ctx) | 490 | context_derive_keys_new(struct krb5_ctx *ctx) |
397 | { | 491 | { |
@@ -561,6 +655,8 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx) | |||
561 | switch (ctx->enctype) { | 655 | switch (ctx->enctype) { |
562 | case ENCTYPE_DES3_CBC_RAW: | 656 | case ENCTYPE_DES3_CBC_RAW: |
563 | return context_derive_keys_des3(ctx); | 657 | return context_derive_keys_des3(ctx); |
658 | case ENCTYPE_ARCFOUR_HMAC: | ||
659 | return context_derive_keys_rc4(ctx); | ||
564 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | 660 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
565 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | 661 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: |
566 | return context_derive_keys_new(ctx); | 662 | return context_derive_keys_new(ctx); |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 36fe487d93d2..d7941eab7796 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
@@ -213,6 +213,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | |||
213 | BUG(); | 213 | BUG(); |
214 | case ENCTYPE_DES_CBC_RAW: | 214 | case ENCTYPE_DES_CBC_RAW: |
215 | case ENCTYPE_DES3_CBC_RAW: | 215 | case ENCTYPE_DES3_CBC_RAW: |
216 | case ENCTYPE_ARCFOUR_HMAC: | ||
216 | return gss_get_mic_v1(ctx, text, token); | 217 | return gss_get_mic_v1(ctx, text, token); |
217 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | 218 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
218 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | 219 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c index 83b593084976..415c013ba382 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c +++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c | |||
@@ -39,6 +39,38 @@ | |||
39 | # define RPCDBG_FACILITY RPCDBG_AUTH | 39 | # define RPCDBG_FACILITY RPCDBG_AUTH |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | static s32 | ||
43 | krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, | ||
44 | unsigned char *cksum, unsigned char *buf) | ||
45 | { | ||
46 | struct crypto_blkcipher *cipher; | ||
47 | unsigned char plain[8]; | ||
48 | s32 code; | ||
49 | |||
50 | dprintk("RPC: %s:\n", __func__); | ||
51 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
52 | CRYPTO_ALG_ASYNC); | ||
53 | if (IS_ERR(cipher)) | ||
54 | return PTR_ERR(cipher); | ||
55 | |||
56 | plain[0] = (unsigned char) ((seqnum >> 24) & 0xff); | ||
57 | plain[1] = (unsigned char) ((seqnum >> 16) & 0xff); | ||
58 | plain[2] = (unsigned char) ((seqnum >> 8) & 0xff); | ||
59 | plain[3] = (unsigned char) ((seqnum >> 0) & 0xff); | ||
60 | plain[4] = direction; | ||
61 | plain[5] = direction; | ||
62 | plain[6] = direction; | ||
63 | plain[7] = direction; | ||
64 | |||
65 | code = krb5_rc4_setup_seq_key(kctx, cipher, cksum); | ||
66 | if (code) | ||
67 | goto out; | ||
68 | |||
69 | code = krb5_encrypt(cipher, cksum, plain, buf, 8); | ||
70 | out: | ||
71 | crypto_free_blkcipher(cipher); | ||
72 | return code; | ||
73 | } | ||
42 | s32 | 74 | s32 |
43 | krb5_make_seq_num(struct krb5_ctx *kctx, | 75 | krb5_make_seq_num(struct krb5_ctx *kctx, |
44 | struct crypto_blkcipher *key, | 76 | struct crypto_blkcipher *key, |
@@ -48,6 +80,10 @@ krb5_make_seq_num(struct krb5_ctx *kctx, | |||
48 | { | 80 | { |
49 | unsigned char plain[8]; | 81 | unsigned char plain[8]; |
50 | 82 | ||
83 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) | ||
84 | return krb5_make_rc4_seq_num(kctx, direction, seqnum, | ||
85 | cksum, buf); | ||
86 | |||
51 | plain[0] = (unsigned char) (seqnum & 0xff); | 87 | plain[0] = (unsigned char) (seqnum & 0xff); |
52 | plain[1] = (unsigned char) ((seqnum >> 8) & 0xff); | 88 | plain[1] = (unsigned char) ((seqnum >> 8) & 0xff); |
53 | plain[2] = (unsigned char) ((seqnum >> 16) & 0xff); | 89 | plain[2] = (unsigned char) ((seqnum >> 16) & 0xff); |
@@ -61,6 +97,43 @@ krb5_make_seq_num(struct krb5_ctx *kctx, | |||
61 | return krb5_encrypt(key, cksum, plain, buf, 8); | 97 | return krb5_encrypt(key, cksum, plain, buf, 8); |
62 | } | 98 | } |
63 | 99 | ||
100 | static s32 | ||
101 | krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum, | ||
102 | unsigned char *buf, int *direction, s32 *seqnum) | ||
103 | { | ||
104 | struct crypto_blkcipher *cipher; | ||
105 | unsigned char plain[8]; | ||
106 | s32 code; | ||
107 | |||
108 | dprintk("RPC: %s:\n", __func__); | ||
109 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
110 | CRYPTO_ALG_ASYNC); | ||
111 | if (IS_ERR(cipher)) | ||
112 | return PTR_ERR(cipher); | ||
113 | |||
114 | code = krb5_rc4_setup_seq_key(kctx, cipher, cksum); | ||
115 | if (code) | ||
116 | goto out; | ||
117 | |||
118 | code = krb5_decrypt(cipher, cksum, buf, plain, 8); | ||
119 | if (code) | ||
120 | goto out; | ||
121 | |||
122 | if ((plain[4] != plain[5]) || (plain[4] != plain[6]) | ||
123 | || (plain[4] != plain[7])) { | ||
124 | code = (s32)KG_BAD_SEQ; | ||
125 | goto out; | ||
126 | } | ||
127 | |||
128 | *direction = plain[4]; | ||
129 | |||
130 | *seqnum = ((plain[0] << 24) | (plain[1] << 16) | | ||
131 | (plain[2] << 8) | (plain[3])); | ||
132 | out: | ||
133 | crypto_free_blkcipher(cipher); | ||
134 | return code; | ||
135 | } | ||
136 | |||
64 | s32 | 137 | s32 |
65 | krb5_get_seq_num(struct krb5_ctx *kctx, | 138 | krb5_get_seq_num(struct krb5_ctx *kctx, |
66 | unsigned char *cksum, | 139 | unsigned char *cksum, |
@@ -73,6 +146,10 @@ krb5_get_seq_num(struct krb5_ctx *kctx, | |||
73 | 146 | ||
74 | dprintk("RPC: krb5_get_seq_num:\n"); | 147 | dprintk("RPC: krb5_get_seq_num:\n"); |
75 | 148 | ||
149 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) | ||
150 | return krb5_get_rc4_seq_num(kctx, cksum, buf, | ||
151 | direction, seqnum); | ||
152 | |||
76 | if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) | 153 | if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) |
77 | return code; | 154 | return code; |
78 | 155 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 97eb91b8c70c..6cd930f3678f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c | |||
@@ -216,6 +216,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
216 | BUG(); | 216 | BUG(); |
217 | case ENCTYPE_DES_CBC_RAW: | 217 | case ENCTYPE_DES_CBC_RAW: |
218 | case ENCTYPE_DES3_CBC_RAW: | 218 | case ENCTYPE_DES3_CBC_RAW: |
219 | case ENCTYPE_ARCFOUR_HMAC: | ||
219 | return gss_verify_mic_v1(ctx, message_buffer, read_token); | 220 | return gss_verify_mic_v1(ctx, message_buffer, read_token); |
220 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | 221 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
221 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | 222 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: |
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 383db891c835..2763e3e48db4 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
@@ -232,9 +232,26 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, | |||
232 | seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))) | 232 | seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))) |
233 | return GSS_S_FAILURE; | 233 | return GSS_S_FAILURE; |
234 | 234 | ||
235 | if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - conflen, | 235 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) { |
236 | pages)) | 236 | struct crypto_blkcipher *cipher; |
237 | return GSS_S_FAILURE; | 237 | int err; |
238 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
239 | CRYPTO_ALG_ASYNC); | ||
240 | if (IS_ERR(cipher)) | ||
241 | return GSS_S_FAILURE; | ||
242 | |||
243 | krb5_rc4_setup_enc_key(kctx, cipher, seq_send); | ||
244 | |||
245 | err = gss_encrypt_xdr_buf(cipher, buf, | ||
246 | offset + headlen - conflen, pages); | ||
247 | crypto_free_blkcipher(cipher); | ||
248 | if (err) | ||
249 | return GSS_S_FAILURE; | ||
250 | } else { | ||
251 | if (gss_encrypt_xdr_buf(kctx->enc, buf, | ||
252 | offset + headlen - conflen, pages)) | ||
253 | return GSS_S_FAILURE; | ||
254 | } | ||
238 | 255 | ||
239 | return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | 256 | return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; |
240 | } | 257 | } |
@@ -291,8 +308,37 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
291 | */ | 308 | */ |
292 | crypt_offset = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) - | 309 | crypt_offset = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) - |
293 | (unsigned char *)buf->head[0].iov_base; | 310 | (unsigned char *)buf->head[0].iov_base; |
294 | if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset)) | 311 | |
295 | return GSS_S_DEFECTIVE_TOKEN; | 312 | /* |
313 | * Need plaintext seqnum to derive encryption key for arcfour-hmac | ||
314 | */ | ||
315 | if (krb5_get_seq_num(kctx, ptr + GSS_KRB5_TOK_HDR_LEN, | ||
316 | ptr + 8, &direction, &seqnum)) | ||
317 | return GSS_S_BAD_SIG; | ||
318 | |||
319 | if ((kctx->initiate && direction != 0xff) || | ||
320 | (!kctx->initiate && direction != 0)) | ||
321 | return GSS_S_BAD_SIG; | ||
322 | |||
323 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) { | ||
324 | struct crypto_blkcipher *cipher; | ||
325 | int err; | ||
326 | |||
327 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
328 | CRYPTO_ALG_ASYNC); | ||
329 | if (IS_ERR(cipher)) | ||
330 | return GSS_S_FAILURE; | ||
331 | |||
332 | krb5_rc4_setup_enc_key(kctx, cipher, seqnum); | ||
333 | |||
334 | err = gss_decrypt_xdr_buf(cipher, buf, crypt_offset); | ||
335 | crypto_free_blkcipher(cipher); | ||
336 | if (err) | ||
337 | return GSS_S_DEFECTIVE_TOKEN; | ||
338 | } else { | ||
339 | if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset)) | ||
340 | return GSS_S_DEFECTIVE_TOKEN; | ||
341 | } | ||
296 | 342 | ||
297 | if (kctx->gk5e->keyed_cksum) | 343 | if (kctx->gk5e->keyed_cksum) |
298 | cksumkey = kctx->cksum; | 344 | cksumkey = kctx->cksum; |
@@ -316,14 +362,6 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
316 | 362 | ||
317 | /* do sequencing checks */ | 363 | /* do sequencing checks */ |
318 | 364 | ||
319 | if (krb5_get_seq_num(kctx, ptr + GSS_KRB5_TOK_HDR_LEN, | ||
320 | ptr + 8, &direction, &seqnum)) | ||
321 | return GSS_S_BAD_SIG; | ||
322 | |||
323 | if ((kctx->initiate && direction != 0xff) || | ||
324 | (!kctx->initiate && direction != 0)) | ||
325 | return GSS_S_BAD_SIG; | ||
326 | |||
327 | /* Copy the data back to the right position. XXX: Would probably be | 365 | /* Copy the data back to the right position. XXX: Would probably be |
328 | * better to copy and encrypt at the same time. */ | 366 | * better to copy and encrypt at the same time. */ |
329 | 367 | ||
@@ -521,6 +559,7 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset, | |||
521 | BUG(); | 559 | BUG(); |
522 | case ENCTYPE_DES_CBC_RAW: | 560 | case ENCTYPE_DES_CBC_RAW: |
523 | case ENCTYPE_DES3_CBC_RAW: | 561 | case ENCTYPE_DES3_CBC_RAW: |
562 | case ENCTYPE_ARCFOUR_HMAC: | ||
524 | return gss_wrap_kerberos_v1(kctx, offset, buf, pages); | 563 | return gss_wrap_kerberos_v1(kctx, offset, buf, pages); |
525 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | 564 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
526 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | 565 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: |
@@ -538,6 +577,7 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf) | |||
538 | BUG(); | 577 | BUG(); |
539 | case ENCTYPE_DES_CBC_RAW: | 578 | case ENCTYPE_DES_CBC_RAW: |
540 | case ENCTYPE_DES3_CBC_RAW: | 579 | case ENCTYPE_DES3_CBC_RAW: |
580 | case ENCTYPE_ARCFOUR_HMAC: | ||
541 | return gss_unwrap_kerberos_v1(kctx, offset, buf); | 581 | return gss_unwrap_kerberos_v1(kctx, offset, buf); |
542 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | 582 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
543 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | 583 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: |