/crypto/heimdal/lib/ntlm/ntlm.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1803 lines · 1152 code · 273 blank · 378 comment · 155 complexity · d668f0afbb881ede87bfedc427598822 MD5 · raw file

  1. /*
  2. * Copyright (c) 2006 - 2008 Kungliga Tekniska Hรถgskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. *
  19. * 3. Neither the name of the Institute nor the names of its contributors
  20. * may be used to endorse or promote products derived from this software
  21. * without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  27. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33. * SUCH DAMAGE.
  34. */
  35. #include <config.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <assert.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <errno.h>
  42. #include <limits.h>
  43. #include <roken.h>
  44. #include <parse_units.h>
  45. #include <krb5.h>
  46. #define HC_DEPRECATED_CRYPTO
  47. #include "krb5-types.h"
  48. #include "crypto-headers.h"
  49. #include <heimntlm.h>
  50. /*! \mainpage Heimdal NTLM library
  51. *
  52. * \section intro Introduction
  53. *
  54. * Heimdal libheimntlm library is a implementation of the NTLM
  55. * protocol, both version 1 and 2. The GSS-API mech that uses this
  56. * library adds support for transport encryption and integrity
  57. * checking.
  58. *
  59. * NTLM is a protocol for mutual authentication, its still used in
  60. * many protocol where Kerberos is not support, one example is
  61. * EAP/X802.1x mechanism LEAP from Microsoft and Cisco.
  62. *
  63. * This is a support library for the core protocol, its used in
  64. * Heimdal to implement and GSS-API mechanism. There is also support
  65. * in the KDC to do remote digest authenticiation, this to allow
  66. * services to authenticate users w/o direct access to the users ntlm
  67. * hashes (same as Kerberos arcfour enctype keys).
  68. *
  69. * More information about the NTLM protocol can found here
  70. * http://davenport.sourceforge.net/ntlm.html .
  71. *
  72. * The Heimdal projects web page: http://www.h5l.org/
  73. *
  74. * @section ntlm_example NTLM Example
  75. *
  76. * Example to to use @ref test_ntlm.c .
  77. *
  78. * @example test_ntlm.c
  79. *
  80. * Example how to use the NTLM primitives.
  81. *
  82. */
  83. /** @defgroup ntlm_core Heimdal NTLM library
  84. *
  85. * The NTLM core functions implement the string2key generation
  86. * function, message encode and decode function, and the hash function
  87. * functions.
  88. */
  89. struct sec_buffer {
  90. uint16_t length;
  91. uint16_t allocated;
  92. uint32_t offset;
  93. };
  94. static const unsigned char ntlmsigature[8] = "NTLMSSP\x00";
  95. /*
  96. *
  97. */
  98. #define CHECK(f, e) \
  99. do { \
  100. ret = f; \
  101. if (ret != (ssize_t)(e)) { \
  102. ret = HNTLM_ERR_DECODE; \
  103. goto out; \
  104. } \
  105. } while(/*CONSTCOND*/0)
  106. static struct units ntlm_flag_units[] = {
  107. #define ntlm_flag(x) { #x, NTLM_##x }
  108. ntlm_flag(ENC_56),
  109. ntlm_flag(NEG_KEYEX),
  110. ntlm_flag(ENC_128),
  111. ntlm_flag(MBZ1),
  112. ntlm_flag(MBZ2),
  113. ntlm_flag(MBZ3),
  114. ntlm_flag(NEG_VERSION),
  115. ntlm_flag(MBZ4),
  116. ntlm_flag(NEG_TARGET_INFO),
  117. ntlm_flag(NON_NT_SESSION_KEY),
  118. ntlm_flag(MBZ5),
  119. ntlm_flag(NEG_IDENTIFY),
  120. ntlm_flag(NEG_NTLM2),
  121. ntlm_flag(TARGET_SHARE),
  122. ntlm_flag(TARGET_SERVER),
  123. ntlm_flag(TARGET_DOMAIN),
  124. ntlm_flag(NEG_ALWAYS_SIGN),
  125. ntlm_flag(MBZ6),
  126. ntlm_flag(OEM_SUPPLIED_WORKSTATION),
  127. ntlm_flag(OEM_SUPPLIED_DOMAIN),
  128. ntlm_flag(NEG_ANONYMOUS),
  129. ntlm_flag(NEG_NT_ONLY),
  130. ntlm_flag(NEG_NTLM),
  131. ntlm_flag(MBZ8),
  132. ntlm_flag(NEG_LM_KEY),
  133. ntlm_flag(NEG_DATAGRAM),
  134. ntlm_flag(NEG_SEAL),
  135. ntlm_flag(NEG_SIGN),
  136. ntlm_flag(MBZ9),
  137. ntlm_flag(NEG_TARGET),
  138. ntlm_flag(NEG_OEM),
  139. ntlm_flag(NEG_UNICODE),
  140. #undef ntlm_flag
  141. {NULL, 0}
  142. };
  143. size_t
  144. heim_ntlm_unparse_flags(uint32_t flags, char *s, size_t len)
  145. {
  146. return unparse_flags(flags, ntlm_flag_units, s, len);
  147. }
  148. /**
  149. * heim_ntlm_free_buf frees the ntlm buffer
  150. *
  151. * @param p buffer to be freed
  152. *
  153. * @ingroup ntlm_core
  154. */
  155. void
  156. heim_ntlm_free_buf(struct ntlm_buf *p)
  157. {
  158. if (p->data)
  159. free(p->data);
  160. p->data = NULL;
  161. p->length = 0;
  162. }
  163. static int
  164. ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf)
  165. {
  166. unsigned char *p;
  167. size_t len, i;
  168. len = strlen(string);
  169. if (len / 2 > UINT_MAX)
  170. return ERANGE;
  171. buf->length = len * 2;
  172. buf->data = malloc(buf->length);
  173. if (buf->data == NULL && len != 0) {
  174. heim_ntlm_free_buf(buf);
  175. return ENOMEM;
  176. }
  177. p = buf->data;
  178. for (i = 0; i < len; i++) {
  179. unsigned char t = (unsigned char)string[i];
  180. if (t & 0x80) {
  181. heim_ntlm_free_buf(buf);
  182. return EINVAL;
  183. }
  184. if (up)
  185. t = toupper(t);
  186. p[(i * 2) + 0] = t;
  187. p[(i * 2) + 1] = 0;
  188. }
  189. return 0;
  190. }
  191. /*
  192. *
  193. */
  194. static krb5_error_code
  195. ret_sec_buffer(krb5_storage *sp, struct sec_buffer *buf)
  196. {
  197. krb5_error_code ret;
  198. CHECK(krb5_ret_uint16(sp, &buf->length), 0);
  199. CHECK(krb5_ret_uint16(sp, &buf->allocated), 0);
  200. CHECK(krb5_ret_uint32(sp, &buf->offset), 0);
  201. out:
  202. return ret;
  203. }
  204. static krb5_error_code
  205. store_sec_buffer(krb5_storage *sp, const struct sec_buffer *buf)
  206. {
  207. krb5_error_code ret;
  208. CHECK(krb5_store_uint16(sp, buf->length), 0);
  209. CHECK(krb5_store_uint16(sp, buf->allocated), 0);
  210. CHECK(krb5_store_uint32(sp, buf->offset), 0);
  211. out:
  212. return ret;
  213. }
  214. /*
  215. * Strings are either OEM or UNICODE. The later is encoded as ucs2 on
  216. * wire, but using utf8 in memory.
  217. */
  218. static krb5_error_code
  219. len_string(int ucs2, const char *s)
  220. {
  221. size_t len = strlen(s);
  222. if (ucs2)
  223. len *= 2;
  224. return len;
  225. }
  226. /*
  227. *
  228. */
  229. static krb5_error_code
  230. ret_string(krb5_storage *sp, int ucs2, size_t len, char **s)
  231. {
  232. krb5_error_code ret;
  233. *s = malloc(len + 1);
  234. if (*s == NULL)
  235. return ENOMEM;
  236. CHECK(krb5_storage_read(sp, *s, len), len);
  237. (*s)[len] = '\0';
  238. if (ucs2) {
  239. size_t i;
  240. for (i = 0; i < len / 2; i++) {
  241. (*s)[i] = (*s)[i * 2];
  242. if ((*s)[i * 2 + 1]) {
  243. free(*s);
  244. *s = NULL;
  245. return EINVAL;
  246. }
  247. }
  248. (*s)[i] = '\0';
  249. }
  250. ret = 0;
  251. out:
  252. return ret;
  253. }
  254. static krb5_error_code
  255. ret_sec_string(krb5_storage *sp, int ucs2, struct sec_buffer *desc, char **s)
  256. {
  257. krb5_error_code ret = 0;
  258. CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
  259. CHECK(ret_string(sp, ucs2, desc->length, s), 0);
  260. out:
  261. return ret;
  262. }
  263. static krb5_error_code
  264. put_string(krb5_storage *sp, int ucs2, const char *s)
  265. {
  266. krb5_error_code ret;
  267. struct ntlm_buf buf;
  268. if (ucs2) {
  269. ret = ascii2ucs2le(s, 0, &buf);
  270. if (ret)
  271. return ret;
  272. } else {
  273. buf.data = rk_UNCONST(s);
  274. buf.length = strlen(s);
  275. }
  276. CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length);
  277. if (ucs2)
  278. heim_ntlm_free_buf(&buf);
  279. ret = 0;
  280. out:
  281. return ret;
  282. }
  283. /*
  284. *
  285. */
  286. static krb5_error_code
  287. ret_buf(krb5_storage *sp, struct sec_buffer *desc, struct ntlm_buf *buf)
  288. {
  289. krb5_error_code ret;
  290. buf->data = malloc(desc->length);
  291. buf->length = desc->length;
  292. CHECK(krb5_storage_seek(sp, desc->offset, SEEK_SET), desc->offset);
  293. CHECK(krb5_storage_read(sp, buf->data, buf->length), buf->length);
  294. ret = 0;
  295. out:
  296. return ret;
  297. }
  298. static krb5_error_code
  299. put_buf(krb5_storage *sp, const struct ntlm_buf *buf)
  300. {
  301. krb5_error_code ret;
  302. CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length);
  303. ret = 0;
  304. out:
  305. return ret;
  306. }
  307. /**
  308. * Frees the ntlm_targetinfo message
  309. *
  310. * @param ti targetinfo to be freed
  311. *
  312. * @ingroup ntlm_core
  313. */
  314. void
  315. heim_ntlm_free_targetinfo(struct ntlm_targetinfo *ti)
  316. {
  317. free(ti->servername);
  318. free(ti->domainname);
  319. free(ti->dnsdomainname);
  320. free(ti->dnsservername);
  321. free(ti->dnstreename);
  322. memset(ti, 0, sizeof(*ti));
  323. }
  324. static int
  325. encode_ti_string(krb5_storage *out, uint16_t type, int ucs2, char *s)
  326. {
  327. krb5_error_code ret;
  328. CHECK(krb5_store_uint16(out, type), 0);
  329. CHECK(krb5_store_uint16(out, len_string(ucs2, s)), 0);
  330. CHECK(put_string(out, ucs2, s), 0);
  331. out:
  332. return ret;
  333. }
  334. /**
  335. * Encodes a ntlm_targetinfo message.
  336. *
  337. * @param ti the ntlm_targetinfo message to encode.
  338. * @param ucs2 ignored
  339. * @param data is the return buffer with the encoded message, should be
  340. * freed with heim_ntlm_free_buf().
  341. *
  342. * @return In case of success 0 is return, an errors, a errno in what
  343. * went wrong.
  344. *
  345. * @ingroup ntlm_core
  346. */
  347. int
  348. heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo *ti,
  349. int ucs2,
  350. struct ntlm_buf *data)
  351. {
  352. krb5_error_code ret;
  353. krb5_storage *out;
  354. data->data = NULL;
  355. data->length = 0;
  356. out = krb5_storage_emem();
  357. if (out == NULL)
  358. return ENOMEM;
  359. krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
  360. if (ti->servername)
  361. CHECK(encode_ti_string(out, 1, ucs2, ti->servername), 0);
  362. if (ti->domainname)
  363. CHECK(encode_ti_string(out, 2, ucs2, ti->domainname), 0);
  364. if (ti->dnsservername)
  365. CHECK(encode_ti_string(out, 3, ucs2, ti->dnsservername), 0);
  366. if (ti->dnsdomainname)
  367. CHECK(encode_ti_string(out, 4, ucs2, ti->dnsdomainname), 0);
  368. if (ti->dnstreename)
  369. CHECK(encode_ti_string(out, 5, ucs2, ti->dnstreename), 0);
  370. if (ti->avflags) {
  371. CHECK(krb5_store_uint16(out, 6), 0);
  372. CHECK(krb5_store_uint16(out, 4), 0);
  373. CHECK(krb5_store_uint32(out, ti->avflags), 0);
  374. }
  375. /* end tag */
  376. CHECK(krb5_store_int16(out, 0), 0);
  377. CHECK(krb5_store_int16(out, 0), 0);
  378. {
  379. krb5_data d;
  380. ret = krb5_storage_to_data(out, &d);
  381. data->data = d.data;
  382. data->length = d.length;
  383. }
  384. out:
  385. krb5_storage_free(out);
  386. return ret;
  387. }
  388. /**
  389. * Decodes an NTLM targetinfo message
  390. *
  391. * @param data input data buffer with the encode NTLM targetinfo message
  392. * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message).
  393. * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo().
  394. *
  395. * @return In case of success 0 is return, an errors, a errno in what
  396. * went wrong.
  397. *
  398. * @ingroup ntlm_core
  399. */
  400. int
  401. heim_ntlm_decode_targetinfo(const struct ntlm_buf *data,
  402. int ucs2,
  403. struct ntlm_targetinfo *ti)
  404. {
  405. uint16_t type, len;
  406. krb5_storage *in;
  407. int ret = 0, done = 0;
  408. memset(ti, 0, sizeof(*ti));
  409. if (data->length == 0)
  410. return 0;
  411. in = krb5_storage_from_readonly_mem(data->data, data->length);
  412. if (in == NULL)
  413. return ENOMEM;
  414. krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
  415. while (!done) {
  416. CHECK(krb5_ret_uint16(in, &type), 0);
  417. CHECK(krb5_ret_uint16(in, &len), 0);
  418. switch (type) {
  419. case 0:
  420. done = 1;
  421. break;
  422. case 1:
  423. CHECK(ret_string(in, ucs2, len, &ti->servername), 0);
  424. break;
  425. case 2:
  426. CHECK(ret_string(in, ucs2, len, &ti->domainname), 0);
  427. break;
  428. case 3:
  429. CHECK(ret_string(in, ucs2, len, &ti->dnsservername), 0);
  430. break;
  431. case 4:
  432. CHECK(ret_string(in, ucs2, len, &ti->dnsdomainname), 0);
  433. break;
  434. case 5:
  435. CHECK(ret_string(in, ucs2, len, &ti->dnstreename), 0);
  436. break;
  437. case 6:
  438. CHECK(krb5_ret_uint32(in, &ti->avflags), 0);
  439. break;
  440. default:
  441. krb5_storage_seek(in, len, SEEK_CUR);
  442. break;
  443. }
  444. }
  445. out:
  446. if (in)
  447. krb5_storage_free(in);
  448. return ret;
  449. }
  450. /**
  451. * Frees the ntlm_type1 message
  452. *
  453. * @param data message to be freed
  454. *
  455. * @ingroup ntlm_core
  456. */
  457. void
  458. heim_ntlm_free_type1(struct ntlm_type1 *data)
  459. {
  460. if (data->domain)
  461. free(data->domain);
  462. if (data->hostname)
  463. free(data->hostname);
  464. memset(data, 0, sizeof(*data));
  465. }
  466. int
  467. heim_ntlm_decode_type1(const struct ntlm_buf *buf, struct ntlm_type1 *data)
  468. {
  469. krb5_error_code ret;
  470. unsigned char sig[8];
  471. uint32_t type;
  472. struct sec_buffer domain, hostname;
  473. krb5_storage *in;
  474. memset(data, 0, sizeof(*data));
  475. in = krb5_storage_from_readonly_mem(buf->data, buf->length);
  476. if (in == NULL) {
  477. ret = ENOMEM;
  478. goto out;
  479. }
  480. krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
  481. CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
  482. CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
  483. CHECK(krb5_ret_uint32(in, &type), 0);
  484. CHECK(type, 1);
  485. CHECK(krb5_ret_uint32(in, &data->flags), 0);
  486. if (data->flags & NTLM_OEM_SUPPLIED_DOMAIN)
  487. CHECK(ret_sec_buffer(in, &domain), 0);
  488. if (data->flags & NTLM_OEM_SUPPLIED_WORKSTATION)
  489. CHECK(ret_sec_buffer(in, &hostname), 0);
  490. #if 0
  491. if (domain.offset > 32) {
  492. CHECK(krb5_ret_uint32(in, &data->os[0]), 0);
  493. CHECK(krb5_ret_uint32(in, &data->os[1]), 0);
  494. }
  495. #endif
  496. if (data->flags & NTLM_OEM_SUPPLIED_DOMAIN)
  497. CHECK(ret_sec_string(in, 0, &domain, &data->domain), 0);
  498. if (data->flags & NTLM_OEM_SUPPLIED_WORKSTATION)
  499. CHECK(ret_sec_string(in, 0, &hostname, &data->hostname), 0);
  500. out:
  501. if (in)
  502. krb5_storage_free(in);
  503. if (ret)
  504. heim_ntlm_free_type1(data);
  505. return ret;
  506. }
  507. /**
  508. * Encodes an ntlm_type1 message.
  509. *
  510. * @param type1 the ntlm_type1 message to encode.
  511. * @param data is the return buffer with the encoded message, should be
  512. * freed with heim_ntlm_free_buf().
  513. *
  514. * @return In case of success 0 is return, an errors, a errno in what
  515. * went wrong.
  516. *
  517. * @ingroup ntlm_core
  518. */
  519. int
  520. heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data)
  521. {
  522. krb5_error_code ret;
  523. struct sec_buffer domain, hostname;
  524. krb5_storage *out;
  525. uint32_t base, flags;
  526. flags = type1->flags;
  527. base = 16;
  528. if (type1->domain) {
  529. base += 8;
  530. flags |= NTLM_OEM_SUPPLIED_DOMAIN;
  531. }
  532. if (type1->hostname) {
  533. base += 8;
  534. flags |= NTLM_OEM_SUPPLIED_WORKSTATION;
  535. }
  536. if (type1->os[0])
  537. base += 8;
  538. domain.offset = base;
  539. if (type1->domain) {
  540. domain.length = len_string(0, type1->domain);
  541. domain.allocated = domain.length;
  542. } else {
  543. domain.length = 0;
  544. domain.allocated = 0;
  545. }
  546. hostname.offset = domain.allocated + domain.offset;
  547. if (type1->hostname) {
  548. hostname.length = len_string(0, type1->hostname);
  549. hostname.allocated = hostname.length;
  550. } else {
  551. hostname.length = 0;
  552. hostname.allocated = 0;
  553. }
  554. out = krb5_storage_emem();
  555. if (out == NULL)
  556. return ENOMEM;
  557. krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
  558. CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
  559. sizeof(ntlmsigature));
  560. CHECK(krb5_store_uint32(out, 1), 0);
  561. CHECK(krb5_store_uint32(out, flags), 0);
  562. CHECK(store_sec_buffer(out, &domain), 0);
  563. CHECK(store_sec_buffer(out, &hostname), 0);
  564. #if 0
  565. CHECK(krb5_store_uint32(out, type1->os[0]), 0);
  566. CHECK(krb5_store_uint32(out, type1->os[1]), 0);
  567. #endif
  568. if (type1->domain)
  569. CHECK(put_string(out, 0, type1->domain), 0);
  570. if (type1->hostname)
  571. CHECK(put_string(out, 0, type1->hostname), 0);
  572. {
  573. krb5_data d;
  574. ret = krb5_storage_to_data(out, &d);
  575. data->data = d.data;
  576. data->length = d.length;
  577. }
  578. out:
  579. krb5_storage_free(out);
  580. return ret;
  581. }
  582. /**
  583. * Frees the ntlm_type2 message
  584. *
  585. * @param data message to be freed
  586. *
  587. * @ingroup ntlm_core
  588. */
  589. void
  590. heim_ntlm_free_type2(struct ntlm_type2 *data)
  591. {
  592. if (data->targetname)
  593. free(data->targetname);
  594. heim_ntlm_free_buf(&data->targetinfo);
  595. memset(data, 0, sizeof(*data));
  596. }
  597. int
  598. heim_ntlm_decode_type2(const struct ntlm_buf *buf, struct ntlm_type2 *type2)
  599. {
  600. krb5_error_code ret;
  601. unsigned char sig[8];
  602. uint32_t type, ctx[2];
  603. struct sec_buffer targetname, targetinfo;
  604. krb5_storage *in;
  605. int ucs2 = 0;
  606. memset(type2, 0, sizeof(*type2));
  607. in = krb5_storage_from_readonly_mem(buf->data, buf->length);
  608. if (in == NULL) {
  609. ret = ENOMEM;
  610. goto out;
  611. }
  612. krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
  613. CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
  614. CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
  615. CHECK(krb5_ret_uint32(in, &type), 0);
  616. CHECK(type, 2);
  617. CHECK(ret_sec_buffer(in, &targetname), 0);
  618. CHECK(krb5_ret_uint32(in, &type2->flags), 0);
  619. if (type2->flags & NTLM_NEG_UNICODE)
  620. ucs2 = 1;
  621. CHECK(krb5_storage_read(in, type2->challenge, sizeof(type2->challenge)),
  622. sizeof(type2->challenge));
  623. CHECK(krb5_ret_uint32(in, &ctx[0]), 0); /* context */
  624. CHECK(krb5_ret_uint32(in, &ctx[1]), 0);
  625. CHECK(ret_sec_buffer(in, &targetinfo), 0);
  626. /* os version */
  627. if (type2->flags & NTLM_NEG_VERSION) {
  628. CHECK(krb5_ret_uint32(in, &type2->os[0]), 0);
  629. CHECK(krb5_ret_uint32(in, &type2->os[1]), 0);
  630. }
  631. CHECK(ret_sec_string(in, ucs2, &targetname, &type2->targetname), 0);
  632. CHECK(ret_buf(in, &targetinfo, &type2->targetinfo), 0);
  633. ret = 0;
  634. out:
  635. if (in)
  636. krb5_storage_free(in);
  637. if (ret)
  638. heim_ntlm_free_type2(type2);
  639. return ret;
  640. }
  641. /**
  642. * Encodes an ntlm_type2 message.
  643. *
  644. * @param type2 the ntlm_type2 message to encode.
  645. * @param data is the return buffer with the encoded message, should be
  646. * freed with heim_ntlm_free_buf().
  647. *
  648. * @return In case of success 0 is return, an errors, a errno in what
  649. * went wrong.
  650. *
  651. * @ingroup ntlm_core
  652. */
  653. int
  654. heim_ntlm_encode_type2(const struct ntlm_type2 *type2, struct ntlm_buf *data)
  655. {
  656. struct sec_buffer targetname, targetinfo;
  657. krb5_error_code ret;
  658. krb5_storage *out = NULL;
  659. uint32_t base;
  660. int ucs2 = 0;
  661. base = 48;
  662. if (type2->flags & NTLM_NEG_VERSION)
  663. base += 8;
  664. if (type2->flags & NTLM_NEG_UNICODE)
  665. ucs2 = 1;
  666. targetname.offset = base;
  667. targetname.length = len_string(ucs2, type2->targetname);
  668. targetname.allocated = targetname.length;
  669. targetinfo.offset = targetname.allocated + targetname.offset;
  670. targetinfo.length = type2->targetinfo.length;
  671. targetinfo.allocated = type2->targetinfo.length;
  672. out = krb5_storage_emem();
  673. if (out == NULL)
  674. return ENOMEM;
  675. krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
  676. CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
  677. sizeof(ntlmsigature));
  678. CHECK(krb5_store_uint32(out, 2), 0);
  679. CHECK(store_sec_buffer(out, &targetname), 0);
  680. CHECK(krb5_store_uint32(out, type2->flags), 0);
  681. CHECK(krb5_storage_write(out, type2->challenge, sizeof(type2->challenge)),
  682. sizeof(type2->challenge));
  683. CHECK(krb5_store_uint32(out, 0), 0); /* context */
  684. CHECK(krb5_store_uint32(out, 0), 0);
  685. CHECK(store_sec_buffer(out, &targetinfo), 0);
  686. /* os version */
  687. if (type2->flags & NTLM_NEG_VERSION) {
  688. CHECK(krb5_store_uint32(out, type2->os[0]), 0);
  689. CHECK(krb5_store_uint32(out, type2->os[1]), 0);
  690. }
  691. CHECK(put_string(out, ucs2, type2->targetname), 0);
  692. CHECK(krb5_storage_write(out, type2->targetinfo.data,
  693. type2->targetinfo.length),
  694. type2->targetinfo.length);
  695. {
  696. krb5_data d;
  697. ret = krb5_storage_to_data(out, &d);
  698. data->data = d.data;
  699. data->length = d.length;
  700. }
  701. out:
  702. krb5_storage_free(out);
  703. return ret;
  704. }
  705. /**
  706. * Frees the ntlm_type3 message
  707. *
  708. * @param data message to be freed
  709. *
  710. * @ingroup ntlm_core
  711. */
  712. void
  713. heim_ntlm_free_type3(struct ntlm_type3 *data)
  714. {
  715. heim_ntlm_free_buf(&data->lm);
  716. heim_ntlm_free_buf(&data->ntlm);
  717. if (data->targetname)
  718. free(data->targetname);
  719. if (data->username)
  720. free(data->username);
  721. if (data->ws)
  722. free(data->ws);
  723. heim_ntlm_free_buf(&data->sessionkey);
  724. memset(data, 0, sizeof(*data));
  725. }
  726. /*
  727. *
  728. */
  729. int
  730. heim_ntlm_decode_type3(const struct ntlm_buf *buf,
  731. int ucs2,
  732. struct ntlm_type3 *type3)
  733. {
  734. krb5_error_code ret;
  735. unsigned char sig[8];
  736. uint32_t type;
  737. krb5_storage *in;
  738. struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
  739. uint32_t min_offset = 72;
  740. memset(type3, 0, sizeof(*type3));
  741. memset(&sessionkey, 0, sizeof(sessionkey));
  742. in = krb5_storage_from_readonly_mem(buf->data, buf->length);
  743. if (in == NULL) {
  744. ret = ENOMEM;
  745. goto out;
  746. }
  747. krb5_storage_set_byteorder(in, KRB5_STORAGE_BYTEORDER_LE);
  748. CHECK(krb5_storage_read(in, sig, sizeof(sig)), sizeof(sig));
  749. CHECK(memcmp(ntlmsigature, sig, sizeof(ntlmsigature)), 0);
  750. CHECK(krb5_ret_uint32(in, &type), 0);
  751. CHECK(type, 3);
  752. CHECK(ret_sec_buffer(in, &lm), 0);
  753. if (lm.allocated)
  754. min_offset = min(min_offset, lm.offset);
  755. CHECK(ret_sec_buffer(in, &ntlm), 0);
  756. if (ntlm.allocated)
  757. min_offset = min(min_offset, ntlm.offset);
  758. CHECK(ret_sec_buffer(in, &target), 0);
  759. if (target.allocated)
  760. min_offset = min(min_offset, target.offset);
  761. CHECK(ret_sec_buffer(in, &username), 0);
  762. if (username.allocated)
  763. min_offset = min(min_offset, username.offset);
  764. CHECK(ret_sec_buffer(in, &ws), 0);
  765. if (ws.allocated)
  766. min_offset = min(min_offset, ws.offset);
  767. if (min_offset > 52) {
  768. CHECK(ret_sec_buffer(in, &sessionkey), 0);
  769. min_offset = max(min_offset, sessionkey.offset);
  770. CHECK(krb5_ret_uint32(in, &type3->flags), 0);
  771. }
  772. if (min_offset > 52 + 8 + 4 + 8) {
  773. CHECK(krb5_ret_uint32(in, &type3->os[0]), 0);
  774. CHECK(krb5_ret_uint32(in, &type3->os[1]), 0);
  775. }
  776. CHECK(ret_buf(in, &lm, &type3->lm), 0);
  777. CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0);
  778. CHECK(ret_sec_string(in, ucs2, &target, &type3->targetname), 0);
  779. CHECK(ret_sec_string(in, ucs2, &username, &type3->username), 0);
  780. CHECK(ret_sec_string(in, ucs2, &ws, &type3->ws), 0);
  781. if (sessionkey.offset)
  782. CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0);
  783. out:
  784. if (in)
  785. krb5_storage_free(in);
  786. if (ret)
  787. heim_ntlm_free_type3(type3);
  788. return ret;
  789. }
  790. /**
  791. * Encodes an ntlm_type3 message.
  792. *
  793. * @param type3 the ntlm_type3 message to encode.
  794. * @param data is the return buffer with the encoded message, should be
  795. * freed with heim_ntlm_free_buf().
  796. *
  797. * @return In case of success 0 is return, an errors, a errno in what
  798. * went wrong.
  799. *
  800. * @ingroup ntlm_core
  801. */
  802. int
  803. heim_ntlm_encode_type3(const struct ntlm_type3 *type3, struct ntlm_buf *data)
  804. {
  805. struct sec_buffer lm, ntlm, target, username, sessionkey, ws;
  806. krb5_error_code ret;
  807. krb5_storage *out = NULL;
  808. uint32_t base;
  809. int ucs2 = 0;
  810. memset(&lm, 0, sizeof(lm));
  811. memset(&ntlm, 0, sizeof(ntlm));
  812. memset(&target, 0, sizeof(target));
  813. memset(&username, 0, sizeof(username));
  814. memset(&ws, 0, sizeof(ws));
  815. memset(&sessionkey, 0, sizeof(sessionkey));
  816. base = 52;
  817. base += 8; /* sessionkey sec buf */
  818. base += 4; /* flags */
  819. if (type3->os[0]) {
  820. base += 8;
  821. }
  822. if (type3->flags & NTLM_NEG_UNICODE)
  823. ucs2 = 1;
  824. target.offset = base;
  825. target.length = len_string(ucs2, type3->targetname);
  826. target.allocated = target.length;
  827. username.offset = target.offset + target.allocated;
  828. username.length = len_string(ucs2, type3->username);
  829. username.allocated = username.length;
  830. ws.offset = username.offset + username.allocated;
  831. ws.length = len_string(ucs2, type3->ws);
  832. ws.allocated = ws.length;
  833. lm.offset = ws.offset + ws.allocated;
  834. lm.length = type3->lm.length;
  835. lm.allocated = type3->lm.length;
  836. ntlm.offset = lm.offset + lm.allocated;
  837. ntlm.length = type3->ntlm.length;
  838. ntlm.allocated = ntlm.length;
  839. sessionkey.offset = ntlm.offset + ntlm.allocated;
  840. sessionkey.length = type3->sessionkey.length;
  841. sessionkey.allocated = type3->sessionkey.length;
  842. out = krb5_storage_emem();
  843. if (out == NULL)
  844. return ENOMEM;
  845. krb5_storage_set_byteorder(out, KRB5_STORAGE_BYTEORDER_LE);
  846. CHECK(krb5_storage_write(out, ntlmsigature, sizeof(ntlmsigature)),
  847. sizeof(ntlmsigature));
  848. CHECK(krb5_store_uint32(out, 3), 0);
  849. CHECK(store_sec_buffer(out, &lm), 0);
  850. CHECK(store_sec_buffer(out, &ntlm), 0);
  851. CHECK(store_sec_buffer(out, &target), 0);
  852. CHECK(store_sec_buffer(out, &username), 0);
  853. CHECK(store_sec_buffer(out, &ws), 0);
  854. CHECK(store_sec_buffer(out, &sessionkey), 0);
  855. CHECK(krb5_store_uint32(out, type3->flags), 0);
  856. #if 0
  857. CHECK(krb5_store_uint32(out, 0), 0); /* os0 */
  858. CHECK(krb5_store_uint32(out, 0), 0); /* os1 */
  859. #endif
  860. CHECK(put_string(out, ucs2, type3->targetname), 0);
  861. CHECK(put_string(out, ucs2, type3->username), 0);
  862. CHECK(put_string(out, ucs2, type3->ws), 0);
  863. CHECK(put_buf(out, &type3->lm), 0);
  864. CHECK(put_buf(out, &type3->ntlm), 0);
  865. CHECK(put_buf(out, &type3->sessionkey), 0);
  866. {
  867. krb5_data d;
  868. ret = krb5_storage_to_data(out, &d);
  869. data->data = d.data;
  870. data->length = d.length;
  871. }
  872. out:
  873. krb5_storage_free(out);
  874. return ret;
  875. }
  876. /*
  877. *
  878. */
  879. static void
  880. splitandenc(unsigned char *hash,
  881. unsigned char *challenge,
  882. unsigned char *answer)
  883. {
  884. EVP_CIPHER_CTX ctx;
  885. unsigned char key[8];
  886. key[0] = hash[0];
  887. key[1] = (hash[0] << 7) | (hash[1] >> 1);
  888. key[2] = (hash[1] << 6) | (hash[2] >> 2);
  889. key[3] = (hash[2] << 5) | (hash[3] >> 3);
  890. key[4] = (hash[3] << 4) | (hash[4] >> 4);
  891. key[5] = (hash[4] << 3) | (hash[5] >> 5);
  892. key[6] = (hash[5] << 2) | (hash[6] >> 6);
  893. key[7] = (hash[6] << 1);
  894. EVP_CIPHER_CTX_init(&ctx);
  895. EVP_CipherInit_ex(&ctx, EVP_des_cbc(), NULL, key, NULL, 1);
  896. EVP_Cipher(&ctx, answer, challenge, 8);
  897. EVP_CIPHER_CTX_cleanup(&ctx);
  898. memset(key, 0, sizeof(key));
  899. }
  900. /**
  901. * Calculate the NTLM key, the password is assumed to be in UTF8.
  902. *
  903. * @param password password to calcute the key for.
  904. * @param key calcuted key, should be freed with heim_ntlm_free_buf().
  905. *
  906. * @return In case of success 0 is return, an errors, a errno in what
  907. * went wrong.
  908. *
  909. * @ingroup ntlm_core
  910. */
  911. int
  912. heim_ntlm_nt_key(const char *password, struct ntlm_buf *key)
  913. {
  914. struct ntlm_buf buf;
  915. EVP_MD_CTX *m;
  916. int ret;
  917. key->data = malloc(MD5_DIGEST_LENGTH);
  918. if (key->data == NULL)
  919. return ENOMEM;
  920. key->length = MD5_DIGEST_LENGTH;
  921. ret = ascii2ucs2le(password, 0, &buf);
  922. if (ret) {
  923. heim_ntlm_free_buf(key);
  924. return ret;
  925. }
  926. m = EVP_MD_CTX_create();
  927. if (m == NULL) {
  928. heim_ntlm_free_buf(key);
  929. heim_ntlm_free_buf(&buf);
  930. return ENOMEM;
  931. }
  932. EVP_DigestInit_ex(m, EVP_md4(), NULL);
  933. EVP_DigestUpdate(m, buf.data, buf.length);
  934. EVP_DigestFinal_ex(m, key->data, NULL);
  935. EVP_MD_CTX_destroy(m);
  936. heim_ntlm_free_buf(&buf);
  937. return 0;
  938. }
  939. /**
  940. * Calculate NTLMv1 response hash
  941. *
  942. * @param key the ntlm v1 key
  943. * @param len length of key
  944. * @param challenge sent by the server
  945. * @param answer calculated answer, should be freed with heim_ntlm_free_buf().
  946. *
  947. * @return In case of success 0 is return, an errors, a errno in what
  948. * went wrong.
  949. *
  950. * @ingroup ntlm_core
  951. */
  952. int
  953. heim_ntlm_calculate_ntlm1(void *key, size_t len,
  954. unsigned char challenge[8],
  955. struct ntlm_buf *answer)
  956. {
  957. unsigned char res[21];
  958. if (len != MD4_DIGEST_LENGTH)
  959. return HNTLM_ERR_INVALID_LENGTH;
  960. memcpy(res, key, len);
  961. memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH);
  962. answer->data = malloc(24);
  963. if (answer->data == NULL)
  964. return ENOMEM;
  965. answer->length = 24;
  966. splitandenc(&res[0], challenge, ((unsigned char *)answer->data) + 0);
  967. splitandenc(&res[7], challenge, ((unsigned char *)answer->data) + 8);
  968. splitandenc(&res[14], challenge, ((unsigned char *)answer->data) + 16);
  969. return 0;
  970. }
  971. int
  972. heim_ntlm_v1_base_session(void *key, size_t len,
  973. struct ntlm_buf *session)
  974. {
  975. EVP_MD_CTX *m;
  976. session->length = MD4_DIGEST_LENGTH;
  977. session->data = malloc(session->length);
  978. if (session->data == NULL) {
  979. session->length = 0;
  980. return ENOMEM;
  981. }
  982. m = EVP_MD_CTX_create();
  983. if (m == NULL) {
  984. heim_ntlm_free_buf(session);
  985. return ENOMEM;
  986. }
  987. EVP_DigestInit_ex(m, EVP_md4(), NULL);
  988. EVP_DigestUpdate(m, key, len);
  989. EVP_DigestFinal_ex(m, session->data, NULL);
  990. EVP_MD_CTX_destroy(m);
  991. return 0;
  992. }
  993. int
  994. heim_ntlm_v2_base_session(void *key, size_t len,
  995. struct ntlm_buf *ntlmResponse,
  996. struct ntlm_buf *session)
  997. {
  998. unsigned int hmaclen;
  999. HMAC_CTX c;
  1000. if (ntlmResponse->length <= 16)
  1001. return HNTLM_ERR_INVALID_LENGTH;
  1002. session->data = malloc(16);
  1003. if (session->data == NULL)
  1004. return ENOMEM;
  1005. session->length = 16;
  1006. /* Note: key is the NTLMv2 key */
  1007. HMAC_CTX_init(&c);
  1008. HMAC_Init_ex(&c, key, len, EVP_md5(), NULL);
  1009. HMAC_Update(&c, ntlmResponse->data, 16);
  1010. HMAC_Final(&c, session->data, &hmaclen);
  1011. HMAC_CTX_cleanup(&c);
  1012. return 0;
  1013. }
  1014. int
  1015. heim_ntlm_keyex_wrap(struct ntlm_buf *base_session,
  1016. struct ntlm_buf *session,
  1017. struct ntlm_buf *encryptedSession)
  1018. {
  1019. EVP_CIPHER_CTX c;
  1020. int ret;
  1021. session->length = MD4_DIGEST_LENGTH;
  1022. session->data = malloc(session->length);
  1023. if (session->data == NULL) {
  1024. session->length = 0;
  1025. return ENOMEM;
  1026. }
  1027. encryptedSession->length = MD4_DIGEST_LENGTH;
  1028. encryptedSession->data = malloc(encryptedSession->length);
  1029. if (encryptedSession->data == NULL) {
  1030. heim_ntlm_free_buf(session);
  1031. encryptedSession->length = 0;
  1032. return ENOMEM;
  1033. }
  1034. EVP_CIPHER_CTX_init(&c);
  1035. ret = EVP_CipherInit_ex(&c, EVP_rc4(), NULL, base_session->data, NULL, 1);
  1036. if (ret != 1) {
  1037. EVP_CIPHER_CTX_cleanup(&c);
  1038. heim_ntlm_free_buf(encryptedSession);
  1039. heim_ntlm_free_buf(session);
  1040. return HNTLM_ERR_CRYPTO;
  1041. }
  1042. if (RAND_bytes(session->data, session->length) != 1) {
  1043. EVP_CIPHER_CTX_cleanup(&c);
  1044. heim_ntlm_free_buf(encryptedSession);
  1045. heim_ntlm_free_buf(session);
  1046. return HNTLM_ERR_RAND;
  1047. }
  1048. EVP_Cipher(&c, encryptedSession->data, session->data, encryptedSession->length);
  1049. EVP_CIPHER_CTX_cleanup(&c);
  1050. return 0;
  1051. }
  1052. /**
  1053. * Generates an NTLMv1 session random with assosited session master key.
  1054. *
  1055. * @param key the ntlm v1 key
  1056. * @param len length of key
  1057. * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
  1058. * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
  1059. *
  1060. * @return In case of success 0 is return, an errors, a errno in what
  1061. * went wrong.
  1062. *
  1063. * @ingroup ntlm_core
  1064. */
  1065. int
  1066. heim_ntlm_build_ntlm1_master(void *key, size_t len,
  1067. struct ntlm_buf *session,
  1068. struct ntlm_buf *master)
  1069. {
  1070. struct ntlm_buf sess;
  1071. int ret;
  1072. ret = heim_ntlm_v1_base_session(key, len, &sess);
  1073. if (ret)
  1074. return ret;
  1075. ret = heim_ntlm_keyex_wrap(&sess, session, master);
  1076. heim_ntlm_free_buf(&sess);
  1077. return ret;
  1078. }
  1079. /**
  1080. * Generates an NTLMv2 session random with associated session master key.
  1081. *
  1082. * @param key the NTLMv2 key
  1083. * @param len length of key
  1084. * @param blob the NTLMv2 "blob"
  1085. * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
  1086. * @param master calculated session master key, should be freed with heim_ntlm_free_buf().
  1087. *
  1088. * @return In case of success 0 is return, an errors, a errno in what
  1089. * went wrong.
  1090. *
  1091. * @ingroup ntlm_core
  1092. */
  1093. int
  1094. heim_ntlm_build_ntlm2_master(void *key, size_t len,
  1095. struct ntlm_buf *blob,
  1096. struct ntlm_buf *session,
  1097. struct ntlm_buf *master)
  1098. {
  1099. struct ntlm_buf sess;
  1100. int ret;
  1101. ret = heim_ntlm_v2_base_session(key, len, blob, &sess);
  1102. if (ret)
  1103. return ret;
  1104. ret = heim_ntlm_keyex_wrap(&sess, session, master);
  1105. heim_ntlm_free_buf(&sess);
  1106. return ret;
  1107. }
  1108. /**
  1109. * Given a key and encrypted session, unwrap the session key
  1110. *
  1111. * @param baseKey the sessionBaseKey
  1112. * @param encryptedSession encrypted session, type3.session field.
  1113. * @param session generated session nonce, should be freed with heim_ntlm_free_buf().
  1114. *
  1115. * @return In case of success 0 is return, an errors, a errno in what
  1116. * went wrong.
  1117. *
  1118. * @ingroup ntlm_core
  1119. */
  1120. int
  1121. heim_ntlm_keyex_unwrap(struct ntlm_buf *baseKey,
  1122. struct ntlm_buf *encryptedSession,
  1123. struct ntlm_buf *session)
  1124. {
  1125. EVP_CIPHER_CTX c;
  1126. memset(session, 0, sizeof(*session));
  1127. if (baseKey->length != MD4_DIGEST_LENGTH)
  1128. return HNTLM_ERR_INVALID_LENGTH;
  1129. session->length = MD4_DIGEST_LENGTH;
  1130. session->data = malloc(session->length);
  1131. if (session->data == NULL) {
  1132. session->length = 0;
  1133. return ENOMEM;
  1134. }
  1135. EVP_CIPHER_CTX_init(&c);
  1136. if (EVP_CipherInit_ex(&c, EVP_rc4(), NULL, baseKey->data, NULL, 0) != 1) {
  1137. EVP_CIPHER_CTX_cleanup(&c);
  1138. heim_ntlm_free_buf(session);
  1139. return HNTLM_ERR_CRYPTO;
  1140. }
  1141. EVP_Cipher(&c, session->data, encryptedSession->data, session->length);
  1142. EVP_CIPHER_CTX_cleanup(&c);
  1143. return 0;
  1144. }
  1145. /**
  1146. * Generates an NTLMv2 session key.
  1147. *
  1148. * @param key the ntlm key
  1149. * @param len length of key
  1150. * @param username name of the user, as sent in the message, assumed to be in UTF8.
  1151. * @param target the name of the target, assumed to be in UTF8.
  1152. * @param ntlmv2 the ntlmv2 session key
  1153. *
  1154. * @return 0 on success, or an error code on failure.
  1155. *
  1156. * @ingroup ntlm_core
  1157. */
  1158. int
  1159. heim_ntlm_ntlmv2_key(const void *key, size_t len,
  1160. const char *username,
  1161. const char *target,
  1162. unsigned char ntlmv2[16])
  1163. {
  1164. int ret;
  1165. unsigned int hmaclen;
  1166. HMAC_CTX c;
  1167. HMAC_CTX_init(&c);
  1168. HMAC_Init_ex(&c, key, len, EVP_md5(), NULL);
  1169. {
  1170. struct ntlm_buf buf;
  1171. /* uppercase username and turn it into ucs2-le */
  1172. ret = ascii2ucs2le(username, 1, &buf);
  1173. if (ret)
  1174. goto out;
  1175. HMAC_Update(&c, buf.data, buf.length);
  1176. free(buf.data);
  1177. /* uppercase target and turn into ucs2-le */
  1178. ret = ascii2ucs2le(target, 1, &buf);
  1179. if (ret)
  1180. goto out;
  1181. HMAC_Update(&c, buf.data, buf.length);
  1182. free(buf.data);
  1183. }
  1184. HMAC_Final(&c, ntlmv2, &hmaclen);
  1185. out:
  1186. HMAC_CTX_cleanup(&c);
  1187. return ret;
  1188. }
  1189. /*
  1190. *
  1191. */
  1192. #define NTTIME_EPOCH 0x019DB1DED53E8000LL
  1193. static uint64_t
  1194. unix2nttime(time_t unix_time)
  1195. {
  1196. long long wt;
  1197. wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
  1198. return wt;
  1199. }
  1200. static time_t
  1201. nt2unixtime(uint64_t t)
  1202. {
  1203. t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000);
  1204. if (t > (((uint64_t)(time_t)(~(uint64_t)0)) >> 1))
  1205. return 0;
  1206. return (time_t)t;
  1207. }
  1208. /**
  1209. * Calculate LMv2 response
  1210. *
  1211. * @param key the ntlm key
  1212. * @param len length of key
  1213. * @param username name of the user, as sent in the message, assumed to be in UTF8.
  1214. * @param target the name of the target, assumed to be in UTF8.
  1215. * @param serverchallenge challenge as sent by the server in the type2 message.
  1216. * @param ntlmv2 calculated session key
  1217. * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
  1218. *
  1219. * @return In case of success 0 is return, an errors, a errno in what
  1220. * went wrong.
  1221. *
  1222. * @ingroup ntlm_core
  1223. */
  1224. int
  1225. heim_ntlm_calculate_lm2(const void *key, size_t len,
  1226. const char *username,
  1227. const char *target,
  1228. const unsigned char serverchallenge[8],
  1229. unsigned char ntlmv2[16],
  1230. struct ntlm_buf *answer)
  1231. {
  1232. unsigned char clientchallenge[8];
  1233. if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1)
  1234. return HNTLM_ERR_RAND;
  1235. /* calculate ntlmv2 key */
  1236. heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
  1237. answer->data = malloc(24);
  1238. if (answer->data == NULL)
  1239. return ENOMEM;
  1240. answer->length = 24;
  1241. heim_ntlm_derive_ntlm2_sess(ntlmv2, clientchallenge, 8,
  1242. serverchallenge, answer->data);
  1243. memcpy(((uint8_t *)answer->data) + 16, clientchallenge, 8);
  1244. return 0;
  1245. }
  1246. /**
  1247. * Calculate NTLMv2 response
  1248. *
  1249. * @param key the ntlm key
  1250. * @param len length of key
  1251. * @param username name of the user, as sent in the message, assumed to be in UTF8.
  1252. * @param target the name of the target, assumed to be in UTF8.
  1253. * @param serverchallenge challenge as sent by the server in the type2 message.
  1254. * @param infotarget infotarget as sent by the server in the type2 message.
  1255. * @param ntlmv2 calculated session key
  1256. * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
  1257. *
  1258. * @return In case of success 0 is return, an errors, a errno in what
  1259. * went wrong.
  1260. *
  1261. * @ingroup ntlm_core
  1262. */
  1263. int
  1264. heim_ntlm_calculate_ntlm2(const void *key, size_t len,
  1265. const char *username,
  1266. const char *target,
  1267. const unsigned char serverchallenge[8],
  1268. const struct ntlm_buf *infotarget,
  1269. unsigned char ntlmv2[16],
  1270. struct ntlm_buf *answer)
  1271. {
  1272. krb5_error_code ret;
  1273. krb5_data data;
  1274. unsigned char ntlmv2answer[16];
  1275. krb5_storage *sp;
  1276. unsigned char clientchallenge[8];
  1277. uint64_t t;
  1278. t = unix2nttime(time(NULL));
  1279. if (RAND_bytes(clientchallenge, sizeof(clientchallenge)) != 1)
  1280. return HNTLM_ERR_RAND;
  1281. /* calculate ntlmv2 key */
  1282. heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
  1283. /* calculate and build ntlmv2 answer */
  1284. sp = krb5_storage_emem();
  1285. if (sp == NULL)
  1286. return ENOMEM;
  1287. krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
  1288. CHECK(krb5_store_uint32(sp, 0x00000101), 0);
  1289. CHECK(krb5_store_uint32(sp, 0), 0);
  1290. /* timestamp le 64 bit ts */
  1291. CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0);
  1292. CHECK(krb5_store_uint32(sp, t >> 32), 0);
  1293. CHECK(krb5_storage_write(sp, clientchallenge, 8), 8);
  1294. CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
  1295. CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length),
  1296. infotarget->length);
  1297. CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */
  1298. CHECK(krb5_storage_to_data(sp, &data), 0);
  1299. krb5_storage_free(sp);
  1300. sp = NULL;
  1301. heim_ntlm_derive_ntlm2_sess(ntlmv2, data.data, data.length, serverchallenge, ntlmv2answer);
  1302. sp = krb5_storage_emem();
  1303. if (sp == NULL) {
  1304. krb5_data_free(&data);
  1305. return ENOMEM;
  1306. }
  1307. CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16);
  1308. CHECK(krb5_storage_write(sp, data.data, data.length), data.length);
  1309. krb5_data_free(&data);
  1310. CHECK(krb5_storage_to_data(sp, &data), 0);
  1311. krb5_storage_free(sp);
  1312. sp = NULL;
  1313. answer->data = data.data;
  1314. answer->length = data.length;
  1315. return 0;
  1316. out:
  1317. if (sp)
  1318. krb5_storage_free(sp);
  1319. return ret;
  1320. }
  1321. static const int authtimediff = 3600 * 2; /* 2 hours */
  1322. /**
  1323. * Verify NTLMv2 response.
  1324. *
  1325. * @param key the ntlm key
  1326. * @param len length of key
  1327. * @param username name of the user, as sent in the message, assumed to be in UTF8.
  1328. * @param target the name of the target, assumed to be in UTF8.
  1329. * @param now the time now (0 if the library should pick it up itself)
  1330. * @param serverchallenge challenge as sent by the server in the type2 message.
  1331. * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf().
  1332. * @param infotarget infotarget as sent by the server in the type2 message.
  1333. * @param ntlmv2 calculated session key
  1334. *
  1335. * @return In case of success 0 is return, an errors, a errno in what
  1336. * went wrong.
  1337. *
  1338. * @ingroup ntlm_core
  1339. */
  1340. int
  1341. heim_ntlm_verify_ntlm2(const void *key, size_t len,
  1342. const char *username,
  1343. const char *target,
  1344. time_t now,
  1345. const unsigned char serverchallenge[8],
  1346. const struct ntlm_buf *answer,
  1347. struct ntlm_buf *infotarget,
  1348. unsigned char ntlmv2[16])
  1349. {
  1350. krb5_error_code ret;
  1351. unsigned char clientanswer[16];
  1352. unsigned char clientnonce[8];
  1353. unsigned char serveranswer[16];
  1354. krb5_storage *sp;
  1355. time_t authtime;
  1356. uint32_t temp;
  1357. uint64_t t;
  1358. infotarget->length = 0;
  1359. infotarget->data = NULL;
  1360. if (answer->length < 16)
  1361. return HNTLM_ERR_INVALID_LENGTH;
  1362. if (now == 0)
  1363. now = time(NULL);
  1364. /* calculate ntlmv2 key */
  1365. heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2);
  1366. /* calculate and build ntlmv2 answer */
  1367. sp = krb5_storage_from_readonly_mem(answer->data, answer->length);
  1368. if (sp == NULL)
  1369. return ENOMEM;
  1370. krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
  1371. CHECK(krb5_storage_read(sp, clientanswer, 16), 16);
  1372. CHECK(krb5_ret_uint32(sp, &temp), 0);
  1373. CHECK(temp, 0x00000101);
  1374. CHECK(krb5_ret_uint32(sp, &temp), 0);
  1375. CHECK(temp, 0);
  1376. /* timestamp le 64 bit ts */
  1377. CHECK(krb5_ret_uint32(sp, &temp), 0);
  1378. t = temp;
  1379. CHECK(krb5_ret_uint32(sp, &temp), 0);
  1380. t |= ((uint64_t)temp)<< 32;
  1381. authtime = nt2unixtime(t);
  1382. if (abs((int)(authtime - now)) > authtimediff) {
  1383. ret = HNTLM_ERR_TIME_SKEW;
  1384. goto out;
  1385. }
  1386. /* client challenge */
  1387. CHECK(krb5_storage_read(sp, clientnonce, 8), 8);
  1388. CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */
  1389. /* should really unparse the infotarget, but lets pick up everything */
  1390. infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR);
  1391. infotarget->data = malloc(infotarget->length);
  1392. if (infotarget->data == NULL) {
  1393. ret = ENOMEM;
  1394. goto out;
  1395. }
  1396. CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length),
  1397. infotarget->length);
  1398. /* XXX remove the unknown ?? */
  1399. krb5_storage_free(sp);
  1400. sp = NULL;
  1401. if (answer->length < 16) {
  1402. ret = HNTLM_ERR_INVALID_LENGTH;
  1403. goto out;
  1404. }
  1405. heim_ntlm_derive_ntlm2_sess(ntlmv2,
  1406. ((unsigned char *)answer->data) + 16, answer->length - 16,
  1407. serverchallenge,
  1408. serveranswer);
  1409. if (memcmp(serveranswer, clientanswer, 16) != 0) {
  1410. heim_ntlm_free_buf(infotarget);
  1411. return HNTLM_ERR_AUTH;
  1412. }
  1413. return 0;
  1414. out:
  1415. heim_ntlm_free_buf(infotarget);
  1416. if (sp)
  1417. krb5_storage_free(sp);
  1418. return ret;
  1419. }
  1420. /*
  1421. * Calculate the NTLM2 Session Response
  1422. *
  1423. * @param clnt_nonce client nonce
  1424. * @param svr_chal server challage
  1425. * @param ntlm2_hash ntlm hash
  1426. * @param lm The LM response, should be freed with heim_ntlm_free_buf().
  1427. * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf().
  1428. *
  1429. * @return In case of success 0 is return, an errors, a errno in what
  1430. * went wrong.
  1431. *
  1432. * @ingroup ntlm_core
  1433. */
  1434. int
  1435. heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8],
  1436. const unsigned char svr_chal[8],
  1437. const unsigned char ntlm_hash[16],
  1438. struct ntlm_buf *lm,
  1439. struct ntlm_buf *ntlm)
  1440. {
  1441. unsigned char ntlm2_sess_hash[8];
  1442. unsigned char res[21], *resp;
  1443. int code;
  1444. code = heim_ntlm_calculate_ntlm2_sess_hash(clnt_nonce, svr_chal,
  1445. ntlm2_sess_hash);
  1446. if (code) {
  1447. return code;
  1448. }
  1449. lm->data = malloc(24);
  1450. if (lm->data == NULL) {
  1451. return ENOMEM;
  1452. }
  1453. lm->length = 24;
  1454. ntlm->data = malloc(24);
  1455. if (ntlm->data == NULL) {
  1456. free(lm->data);
  1457. lm->data = NULL;
  1458. return ENOMEM;
  1459. }
  1460. ntlm->length = 24;
  1461. /* first setup the lm resp */
  1462. memset(lm->data, 0, 24);
  1463. memcpy(lm->data, clnt_nonce, 8);
  1464. memset(res, 0, sizeof(res));
  1465. memcpy(res, ntlm_hash, 16);
  1466. resp = ntlm->data;
  1467. splitandenc(&res[0], ntlm2_sess_hash, resp + 0);
  1468. splitandenc(&res[7], ntlm2_sess_hash, resp + 8);
  1469. splitandenc(&res[14], ntlm2_sess_hash, resp + 16);
  1470. return 0;
  1471. }
  1472. /*
  1473. * Calculate the NTLM2 Session "Verifier"
  1474. *
  1475. * @param clnt_nonce client nonce
  1476. * @param svr_chal server challage
  1477. * @param hash The NTLM session verifier
  1478. *
  1479. * @return In case of success 0 is return, an errors, a errno in what
  1480. * went wrong.
  1481. *
  1482. * @ingroup ntlm_core
  1483. */
  1484. int
  1485. heim_ntlm_calculate_ntlm2_sess_hash(const unsigned char clnt_nonce[8],
  1486. const unsigned char svr_chal[8],
  1487. unsigned char verifier[8])
  1488. {
  1489. unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH];
  1490. EVP_MD_CTX *m;
  1491. m = EVP_MD_CTX_create();
  1492. if (m == NULL)
  1493. return ENOMEM;
  1494. EVP_DigestInit_ex(m, EVP_md5(), NULL);
  1495. EVP_DigestUpdate(m, svr_chal, 8); /* session nonce part 1 */
  1496. EVP_DigestUpdate(m, clnt_nonce, 8); /* session nonce part 2 */
  1497. EVP_DigestFinal_ex(m, ntlm2_sess_hash, NULL); /* will only use first 8 bytes */
  1498. EVP_MD_CTX_destroy(m);
  1499. memcpy(verifier, ntlm2_sess_hash, 8);
  1500. return 0;
  1501. }
  1502. /*
  1503. * Derive a NTLM2 session key
  1504. *
  1505. * @param sessionkey session key from domain controller
  1506. * @param clnt_nonce client nonce
  1507. * @param svr_chal server challenge
  1508. * @param derivedkey salted session key
  1509. *
  1510. * @return In case of success 0 is return, an errors, a errno in what
  1511. * went wrong.
  1512. *
  1513. * @ingroup ntlm_core
  1514. */
  1515. void
  1516. heim_ntlm_derive_ntlm2_sess(const unsigned char sessionkey[16],
  1517. const unsigned char *clnt_nonce, size_t clnt_nonce_length,
  1518. const unsigned char svr_chal[8],
  1519. unsigned char derivedkey[16])
  1520. {
  1521. unsigned int hmaclen;
  1522. HMAC_CTX c;
  1523. /* HMAC(Ksession, serverchallenge || clientchallenge) */
  1524. HMAC_CTX_init(&c);
  1525. HMAC_Init_ex(&c, sessionkey, 16, EVP_md5(), NULL);
  1526. HMAC_Update(&c, svr_chal, 8);
  1527. HMAC_Update(&c, clnt_nonce, clnt_nonce_length);
  1528. HMAC_Final(&c, derivedkey, &hmaclen);
  1529. HMAC_CTX_cleanup(&c);
  1530. }