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 | ||
