asn1.c (5610B)
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 26static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01, 27 0x82, 0x37, 0x02, 0x02, 0x0a }; 28 29int 30ksmbd_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 37int 38ksmbd_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 45static 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 59static 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 93int 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, GFP_KERNEL); 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 134int 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, GFP_KERNEL); 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 162int 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 179int 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 211int ksmbd_neg_token_init_mech_token(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 conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); 218 if (!conn->mechToken) 219 return -ENOMEM; 220 221 memcpy(conn->mechToken, value, vlen); 222 conn->mechToken[vlen] = '\0'; 223 return 0; 224} 225 226int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen, 227 unsigned char tag, const void *value, 228 size_t vlen) 229{ 230 struct ksmbd_conn *conn = context; 231 232 conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); 233 if (!conn->mechToken) 234 return -ENOMEM; 235 236 memcpy(conn->mechToken, value, vlen); 237 conn->mechToken[vlen] = '\0'; 238 return 0; 239}