1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in 4 * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich 5 * 6 * Copyright (c) 2000 RP Internet (www.rpi.net.au). 7 */ 8 9 #include <linux/module.h> 10 #include <linux/types.h> 11 #include <linux/kernel.h> 12 #include <linux/mm.h> 13 #include <linux/slab.h> 14 #include <linux/oid_registry.h> 15 16 #include "glob.h" 17 18 #include "asn1.h" 19 #include "connection.h" 20 #include "auth.h" 21 #include "ksmbd_spnego_negtokeninit.asn1.h" 22 #include "ksmbd_spnego_negtokentarg.asn1.h" 23 24 #define NTLMSSP_OID_LEN 10 25 26 static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01, 27 0x82, 0x37, 0x02, 0x02, 0x0a }; 28 29 int 30 ksmbd_decode_negTokenInit(unsigned char *security_blob, int length, 31 struct ksmbd_conn *conn) 32 { 33 return asn1_ber_decoder(&ksmbd_spnego_negtokeninit_decoder, conn, 34 security_blob, length); 35 } 36 37 int 38 ksmbd_decode_negTokenTarg(unsigned char *security_blob, int length, 39 struct ksmbd_conn *conn) 40 { 41 return asn1_ber_decoder(&ksmbd_spnego_negtokentarg_decoder, conn, 42 security_blob, length); 43 } 44 45 static int compute_asn_hdr_len_bytes(int len) 46 { 47 if (len > 0xFFFFFF) 48 return 4; 49 else if (len > 0xFFFF) 50 return 3; 51 else if (len > 0xFF) 52 return 2; 53 else if (len > 0x7F) 54 return 1; 55 else 56 return 0; 57 } 58 59 static void encode_asn_tag(char *buf, unsigned int *ofs, char tag, char seq, 60 int length) 61 { 62 int i; 63 int index = *ofs; 64 char hdr_len = compute_asn_hdr_len_bytes(length); 65 int len = length + 2 + hdr_len; 66 67 /* insert tag */ 68 buf[index++] = tag; 69 70 if (!hdr_len) { 71 buf[index++] = len; 72 } else { 73 buf[index++] = 0x80 | hdr_len; 74 for (i = hdr_len - 1; i >= 0; i--) 75 buf[index++] = (len >> (i * 8)) & 0xFF; 76 } 77 78 /* insert seq */ 79 len = len - (index - *ofs); 80 buf[index++] = seq; 81 82 if (!hdr_len) { 83 buf[index++] = len; 84 } else { 85 buf[index++] = 0x80 | hdr_len; 86 for (i = hdr_len - 1; i >= 0; i--) 87 buf[index++] = (len >> (i * 8)) & 0xFF; 88 } 89 90 *ofs += (index - *ofs); 91 } 92 93 int build_spnego_ntlmssp_neg_blob(unsigned char **pbuffer, u16 *buflen, 94 char *ntlm_blob, int ntlm_blob_len) 95 { 96 char *buf; 97 unsigned int ofs = 0; 98 int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1; 99 int oid_len = 4 + compute_asn_hdr_len_bytes(NTLMSSP_OID_LEN) * 2 + 100 NTLMSSP_OID_LEN; 101 int ntlmssp_len = 4 + compute_asn_hdr_len_bytes(ntlm_blob_len) * 2 + 102 ntlm_blob_len; 103 int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len + 104 oid_len + ntlmssp_len) * 2 + 105 neg_result_len + oid_len + ntlmssp_len; 106 107 buf = kmalloc(total_len, KSMBD_DEFAULT_GFP); 108 if (!buf) 109 return -ENOMEM; 110 111 /* insert main gss header */ 112 encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len + oid_len + 113 ntlmssp_len); 114 115 /* insert neg result */ 116 encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1); 117 buf[ofs++] = 1; 118 119 /* insert oid */ 120 encode_asn_tag(buf, &ofs, 0xa1, 0x06, NTLMSSP_OID_LEN); 121 memcpy(buf + ofs, NTLMSSP_OID_STR, NTLMSSP_OID_LEN); 122 ofs += NTLMSSP_OID_LEN; 123 124 /* insert response token - ntlmssp blob */ 125 encode_asn_tag(buf, &ofs, 0xa2, 0x04, ntlm_blob_len); 126 memcpy(buf + ofs, ntlm_blob, ntlm_blob_len); 127 ofs += ntlm_blob_len; 128 129 *pbuffer = buf; 130 *buflen = total_len; 131 return 0; 132 } 133 134 int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, 135 int neg_result) 136 { 137 char *buf; 138 unsigned int ofs = 0; 139 int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1; 140 int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len) * 2 + 141 neg_result_len; 142 143 buf = kmalloc(total_len, KSMBD_DEFAULT_GFP); 144 if (!buf) 145 return -ENOMEM; 146 147 /* insert main gss header */ 148 encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len); 149 150 /* insert neg result */ 151 encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1); 152 if (neg_result) 153 buf[ofs++] = 2; 154 else 155 buf[ofs++] = 0; 156 157 *pbuffer = buf; 158 *buflen = total_len; 159 return 0; 160 } 161 162 int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag, 163 const void *value, size_t vlen) 164 { 165 enum OID oid; 166 167 oid = look_up_OID(value, vlen); 168 if (oid != OID_spnego) { 169 char buf[50]; 170 171 sprint_oid(value, vlen, buf, sizeof(buf)); 172 ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); 173 return -EBADMSG; 174 } 175 176 return 0; 177 } 178 179 int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen, 180 unsigned char tag, const void *value, 181 size_t vlen) 182 { 183 struct ksmbd_conn *conn = context; 184 enum OID oid; 185 int mech_type; 186 187 oid = look_up_OID(value, vlen); 188 if (oid == OID_ntlmssp) { 189 mech_type = KSMBD_AUTH_NTLMSSP; 190 } else if (oid == OID_mskrb5) { 191 mech_type = KSMBD_AUTH_MSKRB5; 192 } else if (oid == OID_krb5) { 193 mech_type = KSMBD_AUTH_KRB5; 194 } else if (oid == OID_krb5u2u) { 195 mech_type = KSMBD_AUTH_KRB5U2U; 196 } else { 197 char buf[50]; 198 199 sprint_oid(value, vlen, buf, sizeof(buf)); 200 ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); 201 return -EBADMSG; 202 } 203 204 conn->auth_mechs |= mech_type; 205 if (conn->preferred_auth_mech == 0) 206 conn->preferred_auth_mech = mech_type; 207 208 return 0; 209 } 210 211 static int ksmbd_neg_token_alloc(void *context, size_t hdrlen, 212 unsigned char tag, const void *value, 213 size_t vlen) 214 { 215 struct ksmbd_conn *conn = context; 216 217 if (!vlen) 218 return -EINVAL; 219 220 conn->mechToken = kmemdup_nul(value, vlen, KSMBD_DEFAULT_GFP); 221 if (!conn->mechToken) 222 return -ENOMEM; 223 224 conn->mechTokenLen = (unsigned int)vlen; 225 226 return 0; 227 } 228 229 int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, 230 unsigned char tag, const void *value, 231 size_t vlen) 232 { 233 return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen); 234 } 235 236 int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen, 237 unsigned char tag, const void *value, 238 size_t vlen) 239 { 240 return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen); 241 } 242