extensions/auth/nsAuthSSPI.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial