nsAuthSSPI.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /* vim:set ts=4 sw=4 sts=4 et cindent: */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. //
  6. // Negotiate Authentication Support Module
  7. //
  8. // Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
  9. // (formerly draft-brezak-spnego-http-04.txt)
  10. //
  11. // Also described here:
  12. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
  13. //
  14. #include "nsAuthSSPI.h"
  15. #include "nsIServiceManager.h"
  16. #include "nsIDNSService.h"
  17. #include "nsIDNSRecord.h"
  18. #include "nsNetCID.h"
  19. #include "nsCOMPtr.h"
  20. #include "nsICryptoHash.h"
  21. #include <windows.h>
  22. #define SEC_SUCCESS(Status) ((Status) >= 0)
  23. #ifndef KERB_WRAP_NO_ENCRYPT
  24. #define KERB_WRAP_NO_ENCRYPT 0x80000001
  25. #endif
  26. #ifndef SECBUFFER_PADDING
  27. #define SECBUFFER_PADDING 9
  28. #endif
  29. #ifndef SECBUFFER_STREAM
  30. #define SECBUFFER_STREAM 10
  31. #endif
  32. //-----------------------------------------------------------------------------
  33. static const wchar_t *const pTypeName [] = {
  34. L"Kerberos",
  35. L"Negotiate",
  36. L"NTLM"
  37. };
  38. #ifdef DEBUG
  39. #define CASE_(_x) case _x: return # _x;
  40. static const char *MapErrorCode(int rc)
  41. {
  42. switch (rc) {
  43. CASE_(SEC_E_OK)
  44. CASE_(SEC_I_CONTINUE_NEEDED)
  45. CASE_(SEC_I_COMPLETE_NEEDED)
  46. CASE_(SEC_I_COMPLETE_AND_CONTINUE)
  47. CASE_(SEC_E_INCOMPLETE_MESSAGE)
  48. CASE_(SEC_I_INCOMPLETE_CREDENTIALS)
  49. CASE_(SEC_E_INVALID_HANDLE)
  50. CASE_(SEC_E_TARGET_UNKNOWN)
  51. CASE_(SEC_E_LOGON_DENIED)
  52. CASE_(SEC_E_INTERNAL_ERROR)
  53. CASE_(SEC_E_NO_CREDENTIALS)
  54. CASE_(SEC_E_NO_AUTHENTICATING_AUTHORITY)
  55. CASE_(SEC_E_INSUFFICIENT_MEMORY)
  56. CASE_(SEC_E_INVALID_TOKEN)
  57. }
  58. return "<unknown>";
  59. }
  60. #else
  61. #define MapErrorCode(_rc) ""
  62. #endif
  63. //-----------------------------------------------------------------------------
  64. static PSecurityFunctionTableW sspi;
  65. static nsresult
  66. InitSSPI()
  67. {
  68. LOG((" InitSSPI\n"));
  69. sspi = InitSecurityInterfaceW();
  70. if (!sspi) {
  71. LOG(("InitSecurityInterfaceW failed"));
  72. return NS_ERROR_UNEXPECTED;
  73. }
  74. return NS_OK;
  75. }
  76. //-----------------------------------------------------------------------------
  77. static nsresult
  78. MakeSN(const char *principal, nsCString &result)
  79. {
  80. nsresult rv;
  81. nsAutoCString buf(principal);
  82. // The service name looks like "protocol@hostname", we need to map
  83. // this to a value that SSPI expects. To be consistent with IE, we
  84. // need to map '@' to '/' and canonicalize the hostname.
  85. int32_t index = buf.FindChar('@');
  86. if (index == kNotFound)
  87. return NS_ERROR_UNEXPECTED;
  88. nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
  89. if (NS_FAILED(rv))
  90. return rv;
  91. // This could be expensive if our DNS cache cannot satisfy the request.
  92. // However, we should have at least hit the OS resolver once prior to
  93. // reaching this code, so provided the OS resolver has this information
  94. // cached, we should not have to worry about blocking on this function call
  95. // for very long. NOTE: because we ask for the canonical hostname, we
  96. // might end up requiring extra network activity in cases where the OS
  97. // resolver might not have enough information to satisfy the request from
  98. // its cache. This is not an issue in versions of Windows up to WinXP.
  99. nsCOMPtr<nsIDNSRecord> record;
  100. rv = dns->Resolve(Substring(buf, index + 1),
  101. nsIDNSService::RESOLVE_CANONICAL_NAME,
  102. getter_AddRefs(record));
  103. if (NS_FAILED(rv))
  104. return rv;
  105. nsAutoCString cname;
  106. rv = record->GetCanonicalName(cname);
  107. if (NS_SUCCEEDED(rv)) {
  108. result = StringHead(buf, index) + NS_LITERAL_CSTRING("/") + cname;
  109. LOG(("Using SPN of [%s]\n", result.get()));
  110. }
  111. return rv;
  112. }
  113. //-----------------------------------------------------------------------------
  114. nsAuthSSPI::nsAuthSSPI(pType package)
  115. : mServiceFlags(REQ_DEFAULT)
  116. , mMaxTokenLen(0)
  117. , mPackage(package)
  118. , mCertDERData(nullptr)
  119. , mCertDERLength(0)
  120. {
  121. memset(&mCred, 0, sizeof(mCred));
  122. memset(&mCtxt, 0, sizeof(mCtxt));
  123. }
  124. nsAuthSSPI::~nsAuthSSPI()
  125. {
  126. Reset();
  127. if (mCred.dwLower || mCred.dwUpper) {
  128. #ifdef __MINGW32__
  129. (sspi->FreeCredentialsHandle)(&mCred);
  130. #else
  131. (sspi->FreeCredentialHandle)(&mCred);
  132. #endif
  133. memset(&mCred, 0, sizeof(mCred));
  134. }
  135. }
  136. void
  137. nsAuthSSPI::Reset()
  138. {
  139. mIsFirst = true;
  140. if (mCertDERData){
  141. free(mCertDERData);
  142. mCertDERData = nullptr;
  143. mCertDERLength = 0;
  144. }
  145. if (mCtxt.dwLower || mCtxt.dwUpper) {
  146. (sspi->DeleteSecurityContext)(&mCtxt);
  147. memset(&mCtxt, 0, sizeof(mCtxt));
  148. }
  149. }
  150. NS_IMPL_ISUPPORTS(nsAuthSSPI, nsIAuthModule)
  151. NS_IMETHODIMP
  152. nsAuthSSPI::Init(const char *serviceName,
  153. uint32_t serviceFlags,
  154. const char16_t *domain,
  155. const char16_t *username,
  156. const char16_t *password)
  157. {
  158. LOG((" nsAuthSSPI::Init\n"));
  159. mIsFirst = true;
  160. mCertDERLength = 0;
  161. mCertDERData = nullptr;
  162. // The caller must supply a service name to be used. (For why we now require
  163. // a service name for NTLM, see bug 487872.)
  164. NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
  165. nsresult rv;
  166. // XXX lazy initialization like this assumes that we are single threaded
  167. if (!sspi) {
  168. rv = InitSSPI();
  169. if (NS_FAILED(rv))
  170. return rv;
  171. }
  172. SEC_WCHAR *package;
  173. package = (SEC_WCHAR *) pTypeName[(int)mPackage];
  174. if (mPackage == PACKAGE_TYPE_NTLM) {
  175. // (bug 535193) For NTLM, just use the uri host, do not do canonical host lookups.
  176. // The incoming serviceName is in the format: "protocol@hostname", SSPI expects
  177. // "<service class>/<hostname>", so swap the '@' for a '/'.
  178. mServiceName.Assign(serviceName);
  179. int32_t index = mServiceName.FindChar('@');
  180. if (index == kNotFound)
  181. return NS_ERROR_UNEXPECTED;
  182. mServiceName.Replace(index, 1, '/');
  183. }
  184. else {
  185. // Kerberos requires the canonical host, MakeSN takes care of this through a
  186. // DNS lookup.
  187. rv = MakeSN(serviceName, mServiceName);
  188. if (NS_FAILED(rv))
  189. return rv;
  190. }
  191. mServiceFlags = serviceFlags;
  192. SECURITY_STATUS rc;
  193. PSecPkgInfoW pinfo;
  194. rc = (sspi->QuerySecurityPackageInfoW)(package, &pinfo);
  195. if (rc != SEC_E_OK) {
  196. LOG(("%s package not found\n", package));
  197. return NS_ERROR_UNEXPECTED;
  198. }
  199. mMaxTokenLen = pinfo->cbMaxToken;
  200. (sspi->FreeContextBuffer)(pinfo);
  201. MS_TimeStamp useBefore;
  202. SEC_WINNT_AUTH_IDENTITY_W ai;
  203. SEC_WINNT_AUTH_IDENTITY_W *pai = nullptr;
  204. // domain, username, and password will be null if nsHttpNTLMAuth's ChallengeReceived
  205. // returns false for identityInvalid. Use default credentials in this case by passing
  206. // null for pai.
  207. if (username && password) {
  208. // Keep a copy of these strings for the duration
  209. mUsername.Assign(username);
  210. mPassword.Assign(password);
  211. mDomain.Assign(domain);
  212. ai.Domain = reinterpret_cast<unsigned short*>(mDomain.BeginWriting());
  213. ai.DomainLength = mDomain.Length();
  214. ai.User = reinterpret_cast<unsigned short*>(mUsername.BeginWriting());
  215. ai.UserLength = mUsername.Length();
  216. ai.Password = reinterpret_cast<unsigned short*>(mPassword.BeginWriting());
  217. ai.PasswordLength = mPassword.Length();
  218. ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  219. pai = &ai;
  220. }
  221. rc = (sspi->AcquireCredentialsHandleW)(nullptr,
  222. package,
  223. SECPKG_CRED_OUTBOUND,
  224. nullptr,
  225. pai,
  226. nullptr,
  227. nullptr,
  228. &mCred,
  229. &useBefore);
  230. if (rc != SEC_E_OK)
  231. return NS_ERROR_UNEXPECTED;
  232. LOG(("AcquireCredentialsHandle() succeeded.\n"));
  233. return NS_OK;
  234. }
  235. // The arguments inToken and inTokenLen are used to pass in the server
  236. // certificate (when available) in the first call of the function. The
  237. // second time these arguments hold an input token.
  238. NS_IMETHODIMP
  239. nsAuthSSPI::GetNextToken(const void *inToken,
  240. uint32_t inTokenLen,
  241. void **outToken,
  242. uint32_t *outTokenLen)
  243. {
  244. // String for end-point bindings.
  245. const char end_point[] = "tls-server-end-point:";
  246. const int end_point_length = sizeof(end_point) - 1;
  247. const int hash_size = 32; // Size of a SHA256 hash.
  248. const int cbt_size = hash_size + end_point_length;
  249. SECURITY_STATUS rc;
  250. MS_TimeStamp ignored;
  251. DWORD ctxAttr, ctxReq = 0;
  252. CtxtHandle *ctxIn;
  253. SecBufferDesc ibd, obd;
  254. // Optional second input buffer for the CBT (Channel Binding Token)
  255. SecBuffer ib[2], ob;
  256. // Pointer to the block of memory that stores the CBT
  257. char* sspi_cbt = nullptr;
  258. SEC_CHANNEL_BINDINGS pendpoint_binding;
  259. LOG(("entering nsAuthSSPI::GetNextToken()\n"));
  260. if (!mCred.dwLower && !mCred.dwUpper) {
  261. LOG(("nsAuthSSPI::GetNextToken(), not initialized. exiting."));
  262. return NS_ERROR_NOT_INITIALIZED;
  263. }
  264. if (mServiceFlags & REQ_DELEGATE)
  265. ctxReq |= ISC_REQ_DELEGATE;
  266. if (mServiceFlags & REQ_MUTUAL_AUTH)
  267. ctxReq |= ISC_REQ_MUTUAL_AUTH;
  268. if (inToken) {
  269. if (mIsFirst) {
  270. // First time if it comes with a token,
  271. // the token represents the server certificate.
  272. mIsFirst = false;
  273. mCertDERLength = inTokenLen;
  274. mCertDERData = moz_xmalloc(inTokenLen);
  275. if (!mCertDERData)
  276. return NS_ERROR_OUT_OF_MEMORY;
  277. memcpy(mCertDERData, inToken, inTokenLen);
  278. // We are starting a new authentication sequence.
  279. // If we have already initialized our
  280. // security context, then we're in trouble because it means that the
  281. // first sequence failed. We need to bail or else we might end up in
  282. // an infinite loop.
  283. if (mCtxt.dwLower || mCtxt.dwUpper) {
  284. LOG(("Cannot restart authentication sequence!"));
  285. return NS_ERROR_UNEXPECTED;
  286. }
  287. ctxIn = nullptr;
  288. // The certificate needs to be erased before being passed
  289. // to InitializeSecurityContextW().
  290. inToken = nullptr;
  291. inTokenLen = 0;
  292. } else {
  293. ibd.ulVersion = SECBUFFER_VERSION;
  294. ibd.cBuffers = 0;
  295. ibd.pBuffers = ib;
  296. // If we have stored a certificate, the Channel Binding Token
  297. // needs to be generated and sent in the first input buffer.
  298. if (mCertDERLength > 0) {
  299. // First we create a proper Endpoint Binding structure.
  300. pendpoint_binding.dwInitiatorAddrType = 0;
  301. pendpoint_binding.cbInitiatorLength = 0;
  302. pendpoint_binding.dwInitiatorOffset = 0;
  303. pendpoint_binding.dwAcceptorAddrType = 0;
  304. pendpoint_binding.cbAcceptorLength = 0;
  305. pendpoint_binding.dwAcceptorOffset = 0;
  306. pendpoint_binding.cbApplicationDataLength = cbt_size;
  307. pendpoint_binding.dwApplicationDataOffset =
  308. sizeof(SEC_CHANNEL_BINDINGS);
  309. // Then add it to the array of sec buffers accordingly.
  310. ib[ibd.cBuffers].BufferType = SECBUFFER_CHANNEL_BINDINGS;
  311. ib[ibd.cBuffers].cbBuffer =
  312. pendpoint_binding.cbApplicationDataLength
  313. + pendpoint_binding.dwApplicationDataOffset;
  314. sspi_cbt = (char *) moz_xmalloc(ib[ibd.cBuffers].cbBuffer);
  315. if (!sspi_cbt){
  316. return NS_ERROR_OUT_OF_MEMORY;
  317. }
  318. // Helper to write in the memory block that stores the CBT
  319. char* sspi_cbt_ptr = sspi_cbt;
  320. ib[ibd.cBuffers].pvBuffer = sspi_cbt;
  321. ibd.cBuffers++;
  322. memcpy(sspi_cbt_ptr, &pendpoint_binding,
  323. pendpoint_binding.dwApplicationDataOffset);
  324. sspi_cbt_ptr += pendpoint_binding.dwApplicationDataOffset;
  325. memcpy(sspi_cbt_ptr, end_point, end_point_length);
  326. sspi_cbt_ptr += end_point_length;
  327. // Start hashing. We are always doing SHA256, but depending
  328. // on the certificate, a different alogirthm might be needed.
  329. nsAutoCString hashString;
  330. nsresult rv;
  331. nsCOMPtr<nsICryptoHash> crypto;
  332. crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
  333. if (NS_SUCCEEDED(rv))
  334. rv = crypto->Init(nsICryptoHash::SHA256);
  335. if (NS_SUCCEEDED(rv))
  336. rv = crypto->Update((unsigned char*)mCertDERData, mCertDERLength);
  337. if (NS_SUCCEEDED(rv))
  338. rv = crypto->Finish(false, hashString);
  339. if (NS_FAILED(rv)) {
  340. free(mCertDERData);
  341. mCertDERData = nullptr;
  342. mCertDERLength = 0;
  343. free(sspi_cbt);
  344. return rv;
  345. }
  346. // Once the hash has been computed, we store it in memory right
  347. // after the Endpoint structure and the "tls-server-end-point:"
  348. // char array.
  349. memcpy(sspi_cbt_ptr, hashString.get(), hash_size);
  350. // Free memory used to store the server certificate
  351. free(mCertDERData);
  352. mCertDERData = nullptr;
  353. mCertDERLength = 0;
  354. } // End of CBT computation.
  355. // We always need this SECBUFFER.
  356. ib[ibd.cBuffers].BufferType = SECBUFFER_TOKEN;
  357. ib[ibd.cBuffers].cbBuffer = inTokenLen;
  358. ib[ibd.cBuffers].pvBuffer = (void *) inToken;
  359. ibd.cBuffers++;
  360. ctxIn = &mCtxt;
  361. }
  362. } else { // First time and without a token (no server certificate)
  363. // We are starting a new authentication sequence. If we have already
  364. // initialized our security context, then we're in trouble because it
  365. // means that the first sequence failed. We need to bail or else we
  366. // might end up in an infinite loop.
  367. if (mCtxt.dwLower || mCtxt.dwUpper || mCertDERData || mCertDERLength) {
  368. LOG(("Cannot restart authentication sequence!"));
  369. return NS_ERROR_UNEXPECTED;
  370. }
  371. ctxIn = nullptr;
  372. mIsFirst = false;
  373. }
  374. obd.ulVersion = SECBUFFER_VERSION;
  375. obd.cBuffers = 1;
  376. obd.pBuffers = &ob;
  377. ob.BufferType = SECBUFFER_TOKEN;
  378. ob.cbBuffer = mMaxTokenLen;
  379. ob.pvBuffer = moz_xmalloc(ob.cbBuffer);
  380. if (!ob.pvBuffer){
  381. if (sspi_cbt)
  382. free(sspi_cbt);
  383. return NS_ERROR_OUT_OF_MEMORY;
  384. }
  385. memset(ob.pvBuffer, 0, ob.cbBuffer);
  386. NS_ConvertUTF8toUTF16 wSN(mServiceName);
  387. SEC_WCHAR *sn = (SEC_WCHAR *) wSN.get();
  388. rc = (sspi->InitializeSecurityContextW)(&mCred,
  389. ctxIn,
  390. sn,
  391. ctxReq,
  392. 0,
  393. SECURITY_NATIVE_DREP,
  394. inToken ? &ibd : nullptr,
  395. 0,
  396. &mCtxt,
  397. &obd,
  398. &ctxAttr,
  399. &ignored);
  400. if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) {
  401. if (rc == SEC_E_OK)
  402. LOG(("InitializeSecurityContext: succeeded.\n"));
  403. else
  404. LOG(("InitializeSecurityContext: continue.\n"));
  405. if (sspi_cbt)
  406. free(sspi_cbt);
  407. if (!ob.cbBuffer) {
  408. free(ob.pvBuffer);
  409. ob.pvBuffer = nullptr;
  410. }
  411. *outToken = ob.pvBuffer;
  412. *outTokenLen = ob.cbBuffer;
  413. if (rc == SEC_E_OK)
  414. return NS_SUCCESS_AUTH_FINISHED;
  415. return NS_OK;
  416. }
  417. LOG(("InitializeSecurityContext failed [rc=%d:%s]\n", rc, MapErrorCode(rc)));
  418. Reset();
  419. free(ob.pvBuffer);
  420. return NS_ERROR_FAILURE;
  421. }
  422. NS_IMETHODIMP
  423. nsAuthSSPI::Unwrap(const void *inToken,
  424. uint32_t inTokenLen,
  425. void **outToken,
  426. uint32_t *outTokenLen)
  427. {
  428. SECURITY_STATUS rc;
  429. SecBufferDesc ibd;
  430. SecBuffer ib[2];
  431. ibd.cBuffers = 2;
  432. ibd.pBuffers = ib;
  433. ibd.ulVersion = SECBUFFER_VERSION;
  434. // SSPI Buf
  435. ib[0].BufferType = SECBUFFER_STREAM;
  436. ib[0].cbBuffer = inTokenLen;
  437. ib[0].pvBuffer = moz_xmalloc(ib[0].cbBuffer);
  438. if (!ib[0].pvBuffer)
  439. return NS_ERROR_OUT_OF_MEMORY;
  440. memcpy(ib[0].pvBuffer, inToken, inTokenLen);
  441. // app data
  442. ib[1].BufferType = SECBUFFER_DATA;
  443. ib[1].cbBuffer = 0;
  444. ib[1].pvBuffer = nullptr;
  445. rc = (sspi->DecryptMessage)(
  446. &mCtxt,
  447. &ibd,
  448. 0, // no sequence numbers
  449. nullptr
  450. );
  451. if (SEC_SUCCESS(rc)) {
  452. // check if ib[1].pvBuffer is really just ib[0].pvBuffer, in which
  453. // case we can let the caller free it. Otherwise, we need to
  454. // clone it, and free the original
  455. if (ib[0].pvBuffer == ib[1].pvBuffer) {
  456. *outToken = ib[1].pvBuffer;
  457. }
  458. else {
  459. *outToken = nsMemory::Clone(ib[1].pvBuffer, ib[1].cbBuffer);
  460. free(ib[0].pvBuffer);
  461. if (!*outToken)
  462. return NS_ERROR_OUT_OF_MEMORY;
  463. }
  464. *outTokenLen = ib[1].cbBuffer;
  465. }
  466. else
  467. free(ib[0].pvBuffer);
  468. if (!SEC_SUCCESS(rc))
  469. return NS_ERROR_FAILURE;
  470. return NS_OK;
  471. }
  472. // utility class used to free memory on exit
  473. class secBuffers
  474. {
  475. public:
  476. SecBuffer ib[3];
  477. secBuffers() { memset(&ib, 0, sizeof(ib)); }
  478. ~secBuffers()
  479. {
  480. if (ib[0].pvBuffer)
  481. free(ib[0].pvBuffer);
  482. if (ib[1].pvBuffer)
  483. free(ib[1].pvBuffer);
  484. if (ib[2].pvBuffer)
  485. free(ib[2].pvBuffer);
  486. }
  487. };
  488. NS_IMETHODIMP
  489. nsAuthSSPI::Wrap(const void *inToken,
  490. uint32_t inTokenLen,
  491. bool confidential,
  492. void **outToken,
  493. uint32_t *outTokenLen)
  494. {
  495. SECURITY_STATUS rc;
  496. SecBufferDesc ibd;
  497. secBuffers bufs;
  498. SecPkgContext_Sizes sizes;
  499. rc = (sspi->QueryContextAttributesW)(
  500. &mCtxt,
  501. SECPKG_ATTR_SIZES,
  502. &sizes);
  503. if (!SEC_SUCCESS(rc))
  504. return NS_ERROR_FAILURE;
  505. ibd.cBuffers = 3;
  506. ibd.pBuffers = bufs.ib;
  507. ibd.ulVersion = SECBUFFER_VERSION;
  508. // SSPI
  509. bufs.ib[0].cbBuffer = sizes.cbSecurityTrailer;
  510. bufs.ib[0].BufferType = SECBUFFER_TOKEN;
  511. bufs.ib[0].pvBuffer = moz_xmalloc(sizes.cbSecurityTrailer);
  512. if (!bufs.ib[0].pvBuffer)
  513. return NS_ERROR_OUT_OF_MEMORY;
  514. // APP Data
  515. bufs.ib[1].BufferType = SECBUFFER_DATA;
  516. bufs.ib[1].pvBuffer = moz_xmalloc(inTokenLen);
  517. bufs.ib[1].cbBuffer = inTokenLen;
  518. if (!bufs.ib[1].pvBuffer)
  519. return NS_ERROR_OUT_OF_MEMORY;
  520. memcpy(bufs.ib[1].pvBuffer, inToken, inTokenLen);
  521. // SSPI
  522. bufs.ib[2].BufferType = SECBUFFER_PADDING;
  523. bufs.ib[2].cbBuffer = sizes.cbBlockSize;
  524. bufs.ib[2].pvBuffer = moz_xmalloc(bufs.ib[2].cbBuffer);
  525. if (!bufs.ib[2].pvBuffer)
  526. return NS_ERROR_OUT_OF_MEMORY;
  527. rc = (sspi->EncryptMessage)(&mCtxt,
  528. confidential ? 0 : KERB_WRAP_NO_ENCRYPT,
  529. &ibd, 0);
  530. if (SEC_SUCCESS(rc)) {
  531. int len = bufs.ib[0].cbBuffer + bufs.ib[1].cbBuffer + bufs.ib[2].cbBuffer;
  532. char *p = (char *) moz_xmalloc(len);
  533. if (!p)
  534. return NS_ERROR_OUT_OF_MEMORY;
  535. *outToken = (void *) p;
  536. *outTokenLen = len;
  537. memcpy(p, bufs.ib[0].pvBuffer, bufs.ib[0].cbBuffer);
  538. p += bufs.ib[0].cbBuffer;
  539. memcpy(p,bufs.ib[1].pvBuffer, bufs.ib[1].cbBuffer);
  540. p += bufs.ib[1].cbBuffer;
  541. memcpy(p,bufs.ib[2].pvBuffer, bufs.ib[2].cbBuffer);
  542. return NS_OK;
  543. }
  544. return NS_ERROR_FAILURE;
  545. }