Skip to content

Commit fffdaef

Browse files
Kevin CoffmanTrond Myklebust
authored andcommitted
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 <[email protected]> Signed-off-by: Steve Dickson <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent 5af4654 commit fffdaef

File tree

7 files changed

+492
-13
lines changed

7 files changed

+492
-13
lines changed

include/linux/sunrpc/gss_krb5.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,5 +317,14 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset,
317317
struct xdr_buf *buf, u32 *plainoffset,
318318
u32 *plainlen);
319319

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);
320329
void
321330
gss_krb5_make_confounder(char *p, u32 conflen);

net/sunrpc/auth_gss/gss_krb5_crypto.c

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,114 @@ checksummer(struct scatterlist *sg, void *data)
124124
return crypto_hash_update(desc, sg, sg->length);
125125
}
126126

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+
127235
/*
128236
* checksum the plaintext data and hdrlen bytes of the token header
129237
* 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,
140248
u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
141249
unsigned int checksumlen;
142250

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+
143256
if (cksumout->len < kctx->gk5e->cksumlength) {
144257
dprintk("%s: checksum buffer length, %u, too small for %s\n",
145258
__func__, cksumout->len, kctx->gk5e->name);
@@ -733,3 +846,145 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
733846
ret = GSS_S_FAILURE;
734847
return ret;
735848
}
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+

0 commit comments

Comments
 (0)