17static const uint8_t SPNEGO_OID[] = {0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02};
18static const uint8_t NTLM_OID[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
19 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a};
21static size_t der_len_size(
size_t n)
23 return n < 0x80 ? 1 : n < 0x100 ? 2 : n < 0x10000 ? 3 : 4;
25static size_t tlv_size(
size_t clen)
27 return 1 + der_len_size(clen) + clen;
30static void wr_tag_len(uint8_t *out,
size_t *p, uint8_t tag,
size_t clen)
35 out[(*p)++] = (uint8_t)clen;
37 else if (clen < 0x100)
40 out[(*p)++] = (uint8_t)clen;
42 else if (clen < 0x10000)
45 out[(*p)++] = (uint8_t)(clen >> 8);
46 out[(*p)++] = (uint8_t)clen;
51 out[(*p)++] = (uint8_t)(clen >> 16);
52 out[(*p)++] = (uint8_t)(clen >> 8);
53 out[(*p)++] = (uint8_t)clen;
59static bool der_read(
const uint8_t *buf,
size_t len,
size_t *pos, uint8_t *tag,
size_t *clen,
size_t *cstart)
71 if (nb == 0 || nb > 4 || p + nb > len)
76 for (
size_t i = 0; i < nb; i++)
78 l = (l << 8) | buf[p++];
91size_t pc_spnego_wrap_negotiate(
const uint8_t *ntlm,
size_t pc_ntlm_len, uint8_t *out,
size_t cap)
97 size_t octet = tlv_size(pc_ntlm_len);
98 size_t mt = tlv_size(octet);
99 size_t seqof = tlv_size(
sizeof(NTLM_OID));
100 size_t mtypes = tlv_size(seqof);
101 size_t seq = tlv_size(mtypes + mt);
102 size_t nti = tlv_size(seq);
103 size_t ictbody =
sizeof(SPNEGO_OID) + nti;
104 size_t total = tlv_size(ictbody);
105 if (!out || total > cap)
111 wr_tag_len(out, &p, 0x60, ictbody);
112 memcpy(out + p, SPNEGO_OID,
sizeof(SPNEGO_OID));
113 p +=
sizeof(SPNEGO_OID);
114 wr_tag_len(out, &p, 0xa0, seq);
115 wr_tag_len(out, &p, 0x30, mtypes + mt);
116 wr_tag_len(out, &p, 0xa0, seqof);
117 wr_tag_len(out, &p, 0x30,
sizeof(NTLM_OID));
118 memcpy(out + p, NTLM_OID,
sizeof(NTLM_OID));
119 p +=
sizeof(NTLM_OID);
120 wr_tag_len(out, &p, 0xa2, octet);
121 wr_tag_len(out, &p, 0x04, pc_ntlm_len);
122 memcpy(out + p, ntlm, pc_ntlm_len);
127size_t pc_spnego_wrap_authenticate(
const uint8_t *ntlm,
size_t pc_ntlm_len, uint8_t *out,
size_t cap)
133 size_t octet = tlv_size(pc_ntlm_len);
134 size_t rt = tlv_size(octet);
135 size_t seq = tlv_size(rt);
136 size_t total = tlv_size(seq);
137 if (!out || total > cap)
143 wr_tag_len(out, &p, 0xa1, seq);
144 wr_tag_len(out, &p, 0x30, rt);
145 wr_tag_len(out, &p, 0xa2, octet);
146 wr_tag_len(out, &p, 0x04, pc_ntlm_len);
147 memcpy(out + p, ntlm, pc_ntlm_len);
152bool pc_spnego_parse_response(
const uint8_t *blob,
size_t len,
const uint8_t **pc_resp_token,
size_t *pc_resp_len)
154 if (!blob || !pc_resp_token || !pc_resp_len)
163 if (!der_read(blob, len, &pos, &tag, &clen, &cstart) || tag != 0xa1)
167 size_t neg_end = cstart + clen;
170 if (!der_read(blob, neg_end, &p, &tag, &clen, &cstart) || tag != 0x30)
174 size_t seq_end = cstart + clen;
179 if (!der_read(blob, seq_end, &p, &tag, &clen, &cstart))
189 if (!der_read(blob, cstart + clen, &q, &t2, &cl2, &cs2) || t2 != 0x04)
193 *pc_resp_token = blob + cs2;
SPNEGO (RFC 4178) GSS-API wrapping of the NTLMSSP tokens for the SMB2 client (PC_ENABLE_SMB).