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)
34 out[(*p)++] = (uint8_t)clen;
35 else if (clen < 0x100)
38 out[(*p)++] = (uint8_t)clen;
40 else if (clen < 0x10000)
43 out[(*p)++] = (uint8_t)(clen >> 8);
44 out[(*p)++] = (uint8_t)clen;
49 out[(*p)++] = (uint8_t)(clen >> 16);
50 out[(*p)++] = (uint8_t)(clen >> 8);
51 out[(*p)++] = (uint8_t)clen;
57static bool der_read(
const uint8_t *buf,
size_t len,
size_t *pos, uint8_t *tag,
size_t *clen,
size_t *cstart)
67 if (nb == 0 || nb > 4 || p + nb > len)
70 for (
size_t i = 0; i < nb; i++)
71 l = (l << 8) | buf[p++];
81size_t spnego_wrap_negotiate(
const uint8_t *ntlm,
size_t ntlm_len, uint8_t *out,
size_t cap)
85 size_t octet = tlv_size(ntlm_len);
86 size_t mt = tlv_size(octet);
87 size_t seqof = tlv_size(
sizeof(NTLM_OID));
88 size_t mtypes = tlv_size(seqof);
89 size_t seq = tlv_size(mtypes + mt);
90 size_t nti = tlv_size(seq);
91 size_t ictbody =
sizeof(SPNEGO_OID) + nti;
92 size_t total = tlv_size(ictbody);
93 if (!out || total > cap)
97 wr_tag_len(out, &p, 0x60, ictbody);
98 memcpy(out + p, SPNEGO_OID,
sizeof(SPNEGO_OID));
99 p +=
sizeof(SPNEGO_OID);
100 wr_tag_len(out, &p, 0xa0, seq);
101 wr_tag_len(out, &p, 0x30, mtypes + mt);
102 wr_tag_len(out, &p, 0xa0, seqof);
103 wr_tag_len(out, &p, 0x30,
sizeof(NTLM_OID));
104 memcpy(out + p, NTLM_OID,
sizeof(NTLM_OID));
105 p +=
sizeof(NTLM_OID);
106 wr_tag_len(out, &p, 0xa2, octet);
107 wr_tag_len(out, &p, 0x04, ntlm_len);
108 memcpy(out + p, ntlm, ntlm_len);
113size_t spnego_wrap_authenticate(
const uint8_t *ntlm,
size_t ntlm_len, uint8_t *out,
size_t cap)
117 size_t octet = tlv_size(ntlm_len);
118 size_t rt = tlv_size(octet);
119 size_t seq = tlv_size(rt);
120 size_t total = tlv_size(seq);
121 if (!out || total > cap)
125 wr_tag_len(out, &p, 0xa1, seq);
126 wr_tag_len(out, &p, 0x30, rt);
127 wr_tag_len(out, &p, 0xa2, octet);
128 wr_tag_len(out, &p, 0x04, ntlm_len);
129 memcpy(out + p, ntlm, ntlm_len);
134bool spnego_parse_response(
const uint8_t *blob,
size_t len,
const uint8_t **resp_token,
size_t *resp_len)
136 if (!blob || !resp_token || !resp_len)
143 if (!der_read(blob, len, &pos, &tag, &clen, &cstart) || tag != 0xa1)
145 size_t neg_end = cstart + clen;
148 if (!der_read(blob, neg_end, &p, &tag, &clen, &cstart) || tag != 0x30)
150 size_t seq_end = cstart + clen;
155 if (!der_read(blob, seq_end, &p, &tag, &clen, &cstart))
163 if (!der_read(blob, cstart + clen, &q, &t2, &cl2, &cs2) || t2 != 0x04)
165 *resp_token = blob + cs2;
SPNEGO (RFC 4178) GSS-API wrapping of the NTLMSSP tokens for the SMB2 client (DETWS_ENABLE_SMB).