radius_message.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. /*
  2. * Copyright (C) 2009 Martin Willi
  3. * HSR Hochschule fuer Technik Rapperswil
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include "radius_message.h"
  16. #include <utils/debug.h>
  17. #include <bio/bio_reader.h>
  18. #include <crypto/hashers/hasher.h>
  19. typedef struct private_radius_message_t private_radius_message_t;
  20. typedef struct rmsg_t rmsg_t;
  21. typedef struct rattr_t rattr_t;
  22. /**
  23. * RADIUS message header
  24. */
  25. struct rmsg_t {
  26. /** message code, radius_message_code_t */
  27. uint8_t code;
  28. /** message identifier */
  29. uint8_t identifier;
  30. /** length of Code, Identifier, Length, Authenticator and Attributes */
  31. uint16_t length;
  32. /** message authenticator, MD5 hash */
  33. uint8_t authenticator[HASH_SIZE_MD5];
  34. /** variable list of packed attributes */
  35. uint8_t attributes[];
  36. } __attribute__((packed));
  37. /**
  38. * RADIUS message attribute.
  39. */
  40. struct rattr_t {
  41. /** attribute type, radius_attribute_type_t */
  42. uint8_t type;
  43. /** length of the attriubte, including the Type, Length and Value fields */
  44. uint8_t length;
  45. /** variable length attribute value */
  46. uint8_t value[];
  47. } __attribute__((packed));
  48. /**
  49. * Private data of an radius_message_t object.
  50. */
  51. struct private_radius_message_t {
  52. /**
  53. * Public radius_message_t interface.
  54. */
  55. radius_message_t public;
  56. /**
  57. * message data, allocated
  58. */
  59. rmsg_t *msg;
  60. /**
  61. * User-Password to encrypt and encode, if any
  62. */
  63. chunk_t password;
  64. };
  65. /**
  66. * Described in header.
  67. */
  68. void libradius_init(void)
  69. {
  70. /* empty */
  71. }
  72. ENUM_BEGIN(radius_message_code_names, RMC_ACCESS_REQUEST, RMC_ACCOUNTING_RESPONSE,
  73. "Access-Request",
  74. "Access-Accept",
  75. "Access-Reject",
  76. "Accounting-Request",
  77. "Accounting-Response");
  78. ENUM_NEXT(radius_message_code_names, RMC_ACCESS_CHALLENGE, RMC_ACCESS_CHALLENGE, RMC_ACCOUNTING_RESPONSE,
  79. "Access-Challenge");
  80. ENUM_NEXT(radius_message_code_names, RMC_DISCONNECT_REQUEST, RMC_COA_NAK, RMC_ACCESS_CHALLENGE,
  81. "Disconnect-Request",
  82. "Disconnect-ACK",
  83. "Disconnect-NAK",
  84. "CoA-Request",
  85. "CoA-ACK",
  86. "CoA-NAK");
  87. ENUM_END(radius_message_code_names, RMC_COA_NAK);
  88. ENUM_BEGIN(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
  89. "User-Name",
  90. "User-Password",
  91. "CHAP-Password",
  92. "NAS-IP-Address",
  93. "NAS-Port",
  94. "Service-Type",
  95. "Framed-Protocol",
  96. "Framed-IP-Address",
  97. "Framed-IP-Netmask",
  98. "Framed-Routing",
  99. "Filter-Id",
  100. "Framed-MTU",
  101. "Framed-Compression",
  102. "Login-IP-Host",
  103. "Login-Service",
  104. "Login-TCP-Port",
  105. "Unassigned",
  106. "Reply-Message",
  107. "Callback-Number",
  108. "Callback-Id",
  109. "Unassigned",
  110. "Framed-Route",
  111. "Framed-IPX-Network",
  112. "State",
  113. "Class",
  114. "Vendor-Specific",
  115. "Session-Timeout",
  116. "Idle-Timeout",
  117. "Termination-Action",
  118. "Called-Station-Id",
  119. "Calling-Station-Id",
  120. "NAS-Identifier",
  121. "Proxy-State",
  122. "Login-LAT-Service",
  123. "Login-LAT-Node",
  124. "Login-LAT-Group",
  125. "Framed-AppleTalk-Link",
  126. "Framed-AppleTalk-Network",
  127. "Framed-AppleTalk-Zone",
  128. "Acct-Status-Type",
  129. "Acct-Delay-Time",
  130. "Acct-Input-Octets",
  131. "Acct-Output-Octets",
  132. "Acct-Session-Id",
  133. "Acct-Authentic",
  134. "Acct-Session-Time",
  135. "Acct-Input-Packets",
  136. "Acct-Output-Packets",
  137. "Acct-Terminate-Cause",
  138. "Acct-Multi-Session-Id",
  139. "Acct-Link-Count",
  140. "Acct-Input-Gigawords",
  141. "Acct-Output-Gigawords",
  142. "Unassigned",
  143. "Event-Timestamp",
  144. "Egress-VLANID",
  145. "Ingress-Filters",
  146. "Egress-VLAN-Name",
  147. "User-Priority-Table",
  148. "CHAP-Challenge",
  149. "NAS-Port-Type",
  150. "Port-Limit",
  151. "Login-LAT-Port",
  152. "Tunnel-Type",
  153. "Tunnel-Medium-Type",
  154. "Tunnel-Client-Endpoint",
  155. "Tunnel-Server-Endpoint",
  156. "Acct-Tunnel-Connection",
  157. "Tunnel-Password",
  158. "ARAP-Password",
  159. "ARAP-Features",
  160. "ARAP-Zone-Access",
  161. "ARAP-Security",
  162. "ARAP-Security-Data",
  163. "Password-Retry",
  164. "Prompt",
  165. "Connect-Info",
  166. "Configuration-Token",
  167. "EAP-Message",
  168. "Message-Authenticator",
  169. "Tunnel-Private-Group-ID",
  170. "Tunnel-Assignment-ID",
  171. "Tunnel-Preference",
  172. "ARAP-Challenge-Response",
  173. "Acct-Interim-Interval",
  174. "Acct-Tunnel-Packets-Lost",
  175. "NAS-Port-Id",
  176. "Framed-Pool",
  177. "CUI",
  178. "Tunnel-Client-Auth-ID",
  179. "Tunnel-Server-Auth-ID",
  180. "NAS-Filter-Rule",
  181. "Unassigned",
  182. "Originating-Line-Info",
  183. "NAS-IPv6-Address",
  184. "Framed-Interface-Id",
  185. "Framed-IPv6-Prefix",
  186. "Login-IPv6-Host",
  187. "Framed-IPv6-Route",
  188. "Framed-IPv6-Pool",
  189. "Error-Cause",
  190. "EAP-Key-Name",
  191. "Digest-Response",
  192. "Digest-Realm",
  193. "Digest-Nonce",
  194. "Digest-Response-Auth",
  195. "Digest-Nextnonce",
  196. "Digest-Method",
  197. "Digest-URI",
  198. "Digest-Qop",
  199. "Digest-Algorithm",
  200. "Digest-Entity-Body-Hash",
  201. "Digest-CNonce",
  202. "Digest-Nonce-Count",
  203. "Digest-Username",
  204. "Digest-Opaque",
  205. "Digest-Auth-Param",
  206. "Digest-AKA-Auts",
  207. "Digest-Domain",
  208. "Digest-Stale",
  209. "Digest-HA1",
  210. "SIP-AOR",
  211. "Delegated-IPv6-Prefix",
  212. "MIP6-Feature-Vector",
  213. "MIP6-Home-Link-Prefix");
  214. ENUM_NEXT(radius_attribute_type_names, RAT_FRAMED_IPV6_ADDRESS, RAT_STATEFUL_IPV6_ADDRESS_POOL, RAT_MIP6_HOME_LINK_PREFIX,
  215. "Framed-IPv6-Address",
  216. "DNS-Server-IPv6-Address",
  217. "Route-IPv6-Information",
  218. "Delegated-IPv6-Prefix-Pool",
  219. "Stateful-IPv6-Address-Pool");
  220. ENUM_END(radius_attribute_type_names, RAT_STATEFUL_IPV6_ADDRESS_POOL);
  221. /**
  222. * Attribute enumerator implementation
  223. */
  224. typedef struct {
  225. /** implements enumerator interface */
  226. enumerator_t public;
  227. /** currently pointing attribute */
  228. rattr_t *next;
  229. /** bytes left */
  230. int left;
  231. } attribute_enumerator_t;
  232. METHOD(enumerator_t, attribute_enumerate, bool,
  233. attribute_enumerator_t *this, va_list args)
  234. {
  235. chunk_t *data;
  236. int *type;
  237. VA_ARGS_VGET(args, type, data);
  238. if (this->left == 0)
  239. {
  240. return FALSE;
  241. }
  242. if (this->left < sizeof(rattr_t) ||
  243. this->left < this->next->length)
  244. {
  245. DBG1(DBG_IKE, "RADIUS message truncated");
  246. return FALSE;
  247. }
  248. *type = this->next->type;
  249. data->ptr = this->next->value;
  250. data->len = this->next->length - sizeof(rattr_t);
  251. this->left -= this->next->length;
  252. this->next = ((void*)this->next) + this->next->length;
  253. return TRUE;
  254. }
  255. METHOD(radius_message_t, create_enumerator, enumerator_t*,
  256. private_radius_message_t *this)
  257. {
  258. attribute_enumerator_t *e;
  259. if (ntohs(this->msg->length) < sizeof(rmsg_t) + sizeof(rattr_t))
  260. {
  261. return enumerator_create_empty();
  262. }
  263. INIT(e,
  264. .public = {
  265. .enumerate = enumerator_enumerate_default,
  266. .venumerate = _attribute_enumerate,
  267. .destroy = (void*)free,
  268. },
  269. .next = (rattr_t*)this->msg->attributes,
  270. .left = ntohs(this->msg->length) - sizeof(rmsg_t),
  271. );
  272. return &e->public;
  273. }
  274. /**
  275. * Vendor attribute enumerator implementation
  276. */
  277. typedef struct {
  278. /** implements enumerator interface */
  279. enumerator_t public;
  280. /** inner attribute enumerator */
  281. enumerator_t *inner;
  282. /** current vendor ID */
  283. uint32_t vendor;
  284. /** reader for current vendor ID */
  285. bio_reader_t *reader;
  286. } vendor_enumerator_t;
  287. METHOD(enumerator_t, vendor_enumerate, bool,
  288. vendor_enumerator_t *this, va_list args)
  289. {
  290. chunk_t inner_data, *data;
  291. int inner_type, *vendor, *type;
  292. uint8_t type8, len;
  293. VA_ARGS_VGET(args, vendor, type, data);
  294. while (TRUE)
  295. {
  296. if (this->reader)
  297. {
  298. if (this->reader->remaining(this->reader) >= 2 &&
  299. this->reader->read_uint8(this->reader, &type8) &&
  300. this->reader->read_uint8(this->reader, &len) && len >= 2 &&
  301. this->reader->read_data(this->reader, len - 2, data))
  302. {
  303. *vendor = this->vendor;
  304. *type = type8;
  305. return TRUE;
  306. }
  307. this->reader->destroy(this->reader);
  308. this->reader = NULL;
  309. }
  310. if (this->inner->enumerate(this->inner, &inner_type, &inner_data))
  311. {
  312. if (inner_type == RAT_VENDOR_SPECIFIC)
  313. {
  314. this->reader = bio_reader_create(inner_data);
  315. if (!this->reader->read_uint32(this->reader, &this->vendor))
  316. {
  317. this->reader->destroy(this->reader);
  318. this->reader = NULL;
  319. }
  320. }
  321. }
  322. else
  323. {
  324. return FALSE;
  325. }
  326. }
  327. }
  328. METHOD(enumerator_t, vendor_destroy, void,
  329. vendor_enumerator_t *this)
  330. {
  331. DESTROY_IF(this->reader);
  332. this->inner->destroy(this->inner);
  333. free(this);
  334. }
  335. METHOD(radius_message_t, create_vendor_enumerator, enumerator_t*,
  336. private_radius_message_t *this)
  337. {
  338. vendor_enumerator_t *e;
  339. INIT(e,
  340. .public = {
  341. .enumerate = enumerator_enumerate_default,
  342. .venumerate = _vendor_enumerate,
  343. .destroy = _vendor_destroy,
  344. },
  345. .inner = create_enumerator(this),
  346. );
  347. return &e->public;
  348. }
  349. METHOD(radius_message_t, add, void,
  350. private_radius_message_t *this, radius_attribute_type_t type, chunk_t data)
  351. {
  352. rattr_t *attribute;
  353. if (type == RAT_USER_PASSWORD && !this->password.len)
  354. {
  355. /* store a null-padded password */
  356. this->password = chunk_alloc(round_up(data.len, HASH_SIZE_MD5));
  357. memset(this->password.ptr + data.len, 0, this->password.len - data.len);
  358. memcpy(this->password.ptr, data.ptr, data.len);
  359. return;
  360. }
  361. data.len = min(data.len, MAX_RADIUS_ATTRIBUTE_SIZE);
  362. this->msg = realloc(this->msg,
  363. ntohs(this->msg->length) + sizeof(rattr_t) + data.len);
  364. attribute = ((void*)this->msg) + ntohs(this->msg->length);
  365. attribute->type = type;
  366. attribute->length = data.len + sizeof(rattr_t);
  367. memcpy(attribute->value, data.ptr, data.len);
  368. this->msg->length = htons(ntohs(this->msg->length) + attribute->length);
  369. }
  370. METHOD(radius_message_t, crypt, bool,
  371. private_radius_message_t *this, chunk_t salt, chunk_t in, chunk_t out,
  372. chunk_t secret, hasher_t *hasher)
  373. {
  374. char b[HASH_SIZE_MD5];
  375. /**
  376. * From RFC2548 (encryption):
  377. * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
  378. * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
  379. * . . .
  380. * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
  381. *
  382. * P/C = Plain/Crypted => in/out
  383. * S = secret
  384. * R = authenticator
  385. * A = salt
  386. */
  387. if (in.len != out.len)
  388. {
  389. return FALSE;
  390. }
  391. if (in.len % HASH_SIZE_MD5 || in.len < HASH_SIZE_MD5)
  392. {
  393. return FALSE;
  394. }
  395. if (out.ptr != in.ptr)
  396. {
  397. memcpy(out.ptr, in.ptr, in.len);
  398. }
  399. /* Preparse seed for first round:
  400. * b(1) = MD5(S + R + A) */
  401. if (!hasher->get_hash(hasher, secret, NULL) ||
  402. !hasher->get_hash(hasher,
  403. chunk_from_thing(this->msg->authenticator), NULL) ||
  404. !hasher->get_hash(hasher, salt, b))
  405. {
  406. return FALSE;
  407. }
  408. while (in.len)
  409. {
  410. /* p(i) = b(i) xor c(1) */
  411. memxor(out.ptr, b, HASH_SIZE_MD5);
  412. out = chunk_skip(out, HASH_SIZE_MD5);
  413. if (out.len)
  414. {
  415. /* Prepare seed for next round::
  416. * b(i) = MD5(S + c(i-1)) */
  417. if (!hasher->get_hash(hasher, secret, NULL) ||
  418. !hasher->get_hash(hasher,
  419. chunk_create(in.ptr, HASH_SIZE_MD5), b))
  420. {
  421. return FALSE;
  422. }
  423. }
  424. in = chunk_skip(in, HASH_SIZE_MD5);
  425. }
  426. return TRUE;
  427. }
  428. METHOD(radius_message_t, sign, bool,
  429. private_radius_message_t *this, uint8_t *req_auth, chunk_t secret,
  430. hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth)
  431. {
  432. if (rng)
  433. {
  434. /* build Request-Authenticator */
  435. if (!rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator))
  436. {
  437. return FALSE;
  438. }
  439. }
  440. else
  441. {
  442. /* prepare build of Response-Authenticator */
  443. if (req_auth)
  444. {
  445. memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
  446. }
  447. else
  448. {
  449. memset(this->msg->authenticator, 0, sizeof(this->msg->authenticator));
  450. }
  451. }
  452. if (this->password.len)
  453. {
  454. /* encrypt password inline */
  455. if (!crypt(this, chunk_empty, this->password, this->password,
  456. secret, hasher))
  457. {
  458. return FALSE;
  459. }
  460. add(this, RAT_USER_PASSWORD, this->password);
  461. chunk_clear(&this->password);
  462. }
  463. if (msg_auth)
  464. {
  465. char buf[HASH_SIZE_MD5];
  466. /* build Message-Authenticator attribute, using 16 null bytes */
  467. memset(buf, 0, sizeof(buf));
  468. add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf)));
  469. if (!signer->get_signature(signer,
  470. chunk_create((u_char*)this->msg, ntohs(this->msg->length)),
  471. ((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5))
  472. {
  473. return FALSE;
  474. }
  475. }
  476. if (!rng)
  477. {
  478. chunk_t msg;
  479. /* build Response-Authenticator */
  480. msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
  481. if (!hasher->get_hash(hasher, msg, NULL) ||
  482. !hasher->get_hash(hasher, secret, this->msg->authenticator))
  483. {
  484. return FALSE;
  485. }
  486. }
  487. return TRUE;
  488. }
  489. METHOD(radius_message_t, verify, bool,
  490. private_radius_message_t *this, uint8_t *req_auth, chunk_t secret,
  491. hasher_t *hasher, signer_t *signer)
  492. {
  493. char buf[HASH_SIZE_MD5], res_auth[HASH_SIZE_MD5];
  494. enumerator_t *enumerator;
  495. int type;
  496. chunk_t data, msg;
  497. bool has_eap = FALSE, has_auth = FALSE;
  498. msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
  499. if (this->msg->code != RMC_ACCESS_REQUEST)
  500. {
  501. /* replace Response by Request Authenticator for verification */
  502. memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5);
  503. if (req_auth)
  504. {
  505. memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
  506. }
  507. else
  508. {
  509. memset(this->msg->authenticator, 0, HASH_SIZE_MD5);
  510. }
  511. /* verify Response-Authenticator */
  512. if (!hasher->get_hash(hasher, msg, NULL) ||
  513. !hasher->get_hash(hasher, secret, buf) ||
  514. !memeq_const(buf, res_auth, HASH_SIZE_MD5))
  515. {
  516. DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed");
  517. return FALSE;
  518. }
  519. }
  520. /* verify Message-Authenticator attribute */
  521. enumerator = create_enumerator(this);
  522. while (enumerator->enumerate(enumerator, &type, &data))
  523. {
  524. if (type == RAT_MESSAGE_AUTHENTICATOR)
  525. {
  526. if (data.len != HASH_SIZE_MD5)
  527. {
  528. DBG1(DBG_CFG, "RADIUS Message-Authenticator invalid length");
  529. enumerator->destroy(enumerator);
  530. return FALSE;
  531. }
  532. memcpy(buf, data.ptr, data.len);
  533. memset(data.ptr, 0, data.len);
  534. if (signer->verify_signature(signer, msg,
  535. chunk_create(buf, sizeof(buf))))
  536. {
  537. /* restore Message-Authenticator */
  538. memcpy(data.ptr, buf, data.len);
  539. has_auth = TRUE;
  540. break;
  541. }
  542. else
  543. {
  544. DBG1(DBG_CFG, "RADIUS Message-Authenticator verification failed");
  545. enumerator->destroy(enumerator);
  546. return FALSE;
  547. }
  548. }
  549. else if (type == RAT_EAP_MESSAGE)
  550. {
  551. has_eap = TRUE;
  552. }
  553. }
  554. enumerator->destroy(enumerator);
  555. if (this->msg->code != RMC_ACCESS_REQUEST)
  556. {
  557. /* restore Response-Authenticator */
  558. memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5);
  559. }
  560. if (has_eap && !has_auth)
  561. { /* Message-Authenticator is required if we have an EAP-Message */
  562. DBG1(DBG_CFG, "RADIUS Message-Authenticator attribute missing");
  563. return FALSE;
  564. }
  565. return TRUE;
  566. }
  567. METHOD(radius_message_t, get_code, radius_message_code_t,
  568. private_radius_message_t *this)
  569. {
  570. return this->msg->code;
  571. }
  572. METHOD(radius_message_t, get_identifier, uint8_t,
  573. private_radius_message_t *this)
  574. {
  575. return this->msg->identifier;
  576. }
  577. METHOD(radius_message_t, set_identifier, void,
  578. private_radius_message_t *this, uint8_t identifier)
  579. {
  580. this->msg->identifier = identifier;
  581. }
  582. METHOD(radius_message_t, get_authenticator, uint8_t*,
  583. private_radius_message_t *this)
  584. {
  585. return this->msg->authenticator;
  586. }
  587. METHOD(radius_message_t, get_encoding, chunk_t,
  588. private_radius_message_t *this)
  589. {
  590. return chunk_create((u_char*)this->msg, ntohs(this->msg->length));
  591. }
  592. METHOD(radius_message_t, destroy, void,
  593. private_radius_message_t *this)
  594. {
  595. chunk_clear(&this->password);
  596. free(this->msg);
  597. free(this);
  598. }
  599. /**
  600. * Generic constructor
  601. */
  602. static private_radius_message_t *radius_message_create_empty()
  603. {
  604. private_radius_message_t *this;
  605. INIT(this,
  606. .public = {
  607. .create_enumerator = _create_enumerator,
  608. .create_vendor_enumerator = _create_vendor_enumerator,
  609. .add = _add,
  610. .get_code = _get_code,
  611. .get_identifier = _get_identifier,
  612. .set_identifier = _set_identifier,
  613. .get_authenticator = _get_authenticator,
  614. .get_encoding = _get_encoding,
  615. .sign = _sign,
  616. .verify = _verify,
  617. .crypt = _crypt,
  618. .destroy = _destroy,
  619. },
  620. );
  621. return this;
  622. }
  623. /**
  624. * See header
  625. */
  626. radius_message_t *radius_message_create(radius_message_code_t code)
  627. {
  628. private_radius_message_t *this = radius_message_create_empty();
  629. INIT(this->msg,
  630. .code = code,
  631. .identifier = 0,
  632. .length = htons(sizeof(rmsg_t)),
  633. );
  634. return &this->public;
  635. }
  636. /**
  637. * See header
  638. */
  639. radius_message_t *radius_message_parse(chunk_t data)
  640. {
  641. private_radius_message_t *this = radius_message_create_empty();
  642. this->msg = malloc(data.len);
  643. memcpy(this->msg, data.ptr, data.len);
  644. if (data.len < sizeof(rmsg_t) ||
  645. ntohs(this->msg->length) != data.len)
  646. {
  647. DBG1(DBG_IKE, "RADIUS message has invalid length");
  648. destroy(this);
  649. return NULL;
  650. }
  651. return &this->public;
  652. }