Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/extensions/auth/nsAuthGSSAPI.cpp
Line
Count
Source (jump to first uncovered line)
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
//
7
// GSSAPI 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
//
15
//
16
17
#include "mozilla/ArrayUtils.h"
18
#include "mozilla/IntegerPrintfMacros.h"
19
20
#include "nsCOMPtr.h"
21
#include "nsIPrefService.h"
22
#include "nsIServiceManager.h"
23
#include "nsMemory.h"
24
#include "nsNativeCharsetUtils.h"
25
#include "mozilla/Preferences.h"
26
#include "mozilla/SharedLibrary.h"
27
#include "mozilla/Telemetry.h"
28
29
#include "nsAuthGSSAPI.h"
30
31
#ifdef XP_MACOSX
32
#include <Kerberos/Kerberos.h>
33
#endif
34
35
#ifdef XP_MACOSX
36
typedef KLStatus (*KLCacheHasValidTickets_type)(
37
    KLPrincipal,
38
    KLKerberosVersion,
39
    KLBoolean *,
40
    KLPrincipal *,
41
    char **);
42
#endif
43
44
#if defined(HAVE_RES_NINIT)
45
#include <sys/types.h>
46
#include <netinet/in.h>
47
#include <arpa/nameser.h>
48
#include <resolv.h>
49
#endif
50
51
using namespace mozilla;
52
53
//-----------------------------------------------------------------------------
54
55
// We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced
56
// by by a different name depending on the implementation of gss but always
57
// has the same value
58
59
static gss_OID_desc gss_c_nt_hostbased_service =
60
    { 10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04" };
61
62
static const char kNegotiateAuthGssLib[] =
63
    "network.negotiate-auth.gsslib";
64
static const char kNegotiateAuthNativeImp[] =
65
   "network.negotiate-auth.using-native-gsslib";
66
67
static struct GSSFunction {
68
    const char *str;
69
    PRFuncPtr func;
70
} gssFuncs[] = {
71
    { "gss_display_status", nullptr },
72
    { "gss_init_sec_context", nullptr },
73
    { "gss_indicate_mechs", nullptr },
74
    { "gss_release_oid_set", nullptr },
75
    { "gss_delete_sec_context", nullptr },
76
    { "gss_import_name", nullptr },
77
    { "gss_release_buffer", nullptr },
78
    { "gss_release_name", nullptr },
79
    { "gss_wrap", nullptr },
80
    { "gss_unwrap", nullptr }
81
};
82
83
static bool      gssNativeImp = true;
84
static PRLibrary* gssLibrary = nullptr;
85
86
0
#define gss_display_status_ptr      ((gss_display_status_type)*gssFuncs[0].func)
87
0
#define gss_init_sec_context_ptr    ((gss_init_sec_context_type)*gssFuncs[1].func)
88
0
#define gss_indicate_mechs_ptr      ((gss_indicate_mechs_type)*gssFuncs[2].func)
89
0
#define gss_release_oid_set_ptr     ((gss_release_oid_set_type)*gssFuncs[3].func)
90
0
#define gss_delete_sec_context_ptr  ((gss_delete_sec_context_type)*gssFuncs[4].func)
91
0
#define gss_import_name_ptr         ((gss_import_name_type)*gssFuncs[5].func)
92
0
#define gss_release_buffer_ptr      ((gss_release_buffer_type)*gssFuncs[6].func)
93
0
#define gss_release_name_ptr        ((gss_release_name_type)*gssFuncs[7].func)
94
0
#define gss_wrap_ptr                ((gss_wrap_type)*gssFuncs[8].func)
95
0
#define gss_unwrap_ptr              ((gss_unwrap_type)*gssFuncs[9].func)
96
97
#ifdef XP_MACOSX
98
static PRFuncPtr KLCacheHasValidTicketsPtr;
99
#define KLCacheHasValidTickets_ptr \
100
        ((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr)
101
#endif
102
103
static nsresult
104
gssInit()
105
0
{
106
#ifdef XP_WIN
107
    nsAutoString libPathU;
108
    Preferences::GetString(kNegotiateAuthGssLib, libPathU);
109
    NS_ConvertUTF16toUTF8 libPath(libPathU);
110
#else
111
    nsAutoCString libPath;
112
0
    Preferences::GetCString(kNegotiateAuthGssLib, libPath);
113
0
#endif
114
0
    gssNativeImp = Preferences::GetBool(kNegotiateAuthNativeImp);
115
0
116
0
    PRLibrary *lib = nullptr;
117
0
118
0
    if (!libPath.IsEmpty()) {
119
0
        LOG(("Attempting to load user specified library [%s]\n", libPath.get()));
120
0
        gssNativeImp = false;
121
#ifdef XP_WIN
122
        lib = LoadLibraryWithFlags(libPathU.get());
123
#else
124
        lib = LoadLibraryWithFlags(libPath.get());
125
0
#endif
126
0
    }
127
0
    else {
128
#ifdef XP_WIN
129
        #ifdef _WIN64
130
        NS_NAMED_LITERAL_STRING(kLibName, "gssapi64.dll");
131
        #else
132
        NS_NAMED_LITERAL_STRING(kLibName, "gssapi32.dll");
133
        #endif
134
135
        lib = LoadLibraryWithFlags(kLibName.get());
136
#elif defined(__OpenBSD__)
137
        /* OpenBSD doesn't register inter-library dependencies in basesystem
138
         * libs therefor we need to load all the libraries gssapi depends on,
139
         * in the correct order and with LD_GLOBAL for GSSAPI auth to work
140
         * fine.
141
         */
142
143
        const char *const verLibNames[] = {
144
            "libasn1.so",
145
            "libcrypto.so",
146
            "libroken.so",
147
            "libheimbase.so",
148
            "libcom_err.so",
149
            "libkrb5.so",
150
            "libgssapi.so"
151
        };
152
153
        PRLibSpec libSpec;
154
        for (size_t i = 0; i < ArrayLength(verLibNames); ++i) {
155
            libSpec.type = PR_LibSpec_Pathname;
156
            libSpec.value.pathname = verLibNames[i];
157
            lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_GLOBAL);
158
        }
159
160
#else
161
162
0
        const char *const libNames[] = {
163
0
            "gss",
164
0
            "gssapi_krb5",
165
0
            "gssapi"
166
0
        };
167
0
168
0
        const char *const verLibNames[] = {
169
0
            "libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */
170
0
            "libgssapi.so.4",      /* Heimdal - Suse10, MDK */
171
0
            "libgssapi.so.1"       /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
172
0
        };
173
0
174
0
        for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) {
175
0
            lib = PR_LoadLibrary(verLibNames[i]);
176
0
177
0
            /* The CITI libgssapi library calls exit() during
178
0
             * initialization if it's not correctly configured. Try to
179
0
             * ensure that we never use this library for our GSSAPI
180
0
             * support, as its just a wrapper library, anyway.
181
0
             * See Bugzilla #325433
182
0
             */
183
0
            if (lib &&
184
0
                PR_FindFunctionSymbol(lib,
185
0
                                      "internal_krb5_gss_initialize") &&
186
0
                PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) {
187
0
                LOG(("CITI libgssapi found, which calls exit(). Skipping\n"));
188
0
                PR_UnloadLibrary(lib);
189
0
                lib = nullptr;
190
0
            }
191
0
        }
192
0
193
0
        for (size_t i = 0; i < ArrayLength(libNames) && !lib; ++i) {
194
0
            char *libName = PR_GetLibraryName(nullptr, libNames[i]);
195
0
            if (libName) {
196
0
                lib = PR_LoadLibrary(libName);
197
0
                PR_FreeLibraryName(libName);
198
0
199
0
                if (lib &&
200
0
                    PR_FindFunctionSymbol(lib,
201
0
                                          "internal_krb5_gss_initialize") &&
202
0
                    PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) {
203
0
                    LOG(("CITI libgssapi found, which calls exit(). Skipping\n"));
204
0
                    PR_UnloadLibrary(lib);
205
0
                    lib = nullptr;
206
0
                }
207
0
            }
208
0
        }
209
0
#endif
210
0
    }
211
0
212
0
    if (!lib) {
213
0
        LOG(("Fail to load gssapi library\n"));
214
0
        return NS_ERROR_FAILURE;
215
0
    }
216
0
217
0
    LOG(("Attempting to load gss functions\n"));
218
0
219
0
    for (size_t i = 0; i < ArrayLength(gssFuncs); ++i) {
220
0
        gssFuncs[i].func = PR_FindFunctionSymbol(lib, gssFuncs[i].str);
221
0
        if (!gssFuncs[i].func) {
222
0
            LOG(("Fail to load %s function from gssapi library\n", gssFuncs[i].str));
223
0
            PR_UnloadLibrary(lib);
224
0
            return NS_ERROR_FAILURE;
225
0
        }
226
0
    }
227
#ifdef XP_MACOSX
228
    if (gssNativeImp &&
229
            !(KLCacheHasValidTicketsPtr =
230
               PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) {
231
        LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n"));
232
        PR_UnloadLibrary(lib);
233
        return NS_ERROR_FAILURE;
234
    }
235
#endif
236
237
0
    gssLibrary = lib;
238
0
    return NS_OK;
239
0
}
240
241
// Generate proper GSSAPI error messages from the major and
242
// minor status codes.
243
void
244
LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix)
245
0
{
246
0
    if (!MOZ_LOG_TEST(gNegotiateLog, LogLevel::Debug)) {
247
0
        return;
248
0
    }
249
0
250
0
    OM_uint32 new_stat;
251
0
    OM_uint32 msg_ctx = 0;
252
0
    gss_buffer_desc status1_string;
253
0
    gss_buffer_desc status2_string;
254
0
    OM_uint32 ret;
255
0
    nsAutoCString errorStr;
256
0
    errorStr.Assign(prefix);
257
0
258
0
    if (!gssLibrary)
259
0
        return;
260
0
261
0
    errorStr += ": ";
262
0
    do {
263
0
        ret = gss_display_status_ptr(&new_stat,
264
0
                                     maj_stat,
265
0
                                     GSS_C_GSS_CODE,
266
0
                                     GSS_C_NULL_OID,
267
0
                                     &msg_ctx,
268
0
                                     &status1_string);
269
0
        errorStr.Append((const char *) status1_string.value, status1_string.length);
270
0
        gss_release_buffer_ptr(&new_stat, &status1_string);
271
0
272
0
        errorStr += '\n';
273
0
        ret = gss_display_status_ptr(&new_stat,
274
0
                                     min_stat,
275
0
                                     GSS_C_MECH_CODE,
276
0
                                     GSS_C_NULL_OID,
277
0
                                     &msg_ctx,
278
0
                                     &status2_string);
279
0
        errorStr.Append((const char *) status2_string.value, status2_string.length);
280
0
        errorStr += '\n';
281
0
    } while (!GSS_ERROR(ret) && msg_ctx != 0);
282
0
283
0
    LOG(("%s\n", errorStr.get()));
284
0
}
285
286
//-----------------------------------------------------------------------------
287
288
nsAuthGSSAPI::nsAuthGSSAPI(pType package)
289
    : mServiceFlags(REQ_DEFAULT)
290
0
{
291
0
    OM_uint32 minstat;
292
0
    OM_uint32 majstat;
293
0
    gss_OID_set mech_set;
294
0
    gss_OID item;
295
0
296
0
    unsigned int i;
297
0
    static gss_OID_desc gss_krb5_mech_oid_desc =
298
0
        { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
299
0
    static gss_OID_desc gss_spnego_mech_oid_desc =
300
0
        { 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
301
0
302
0
    LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n"));
303
0
304
0
    mComplete = false;
305
0
306
0
    if (!gssLibrary && NS_FAILED(gssInit()))
307
0
        return;
308
0
309
0
    mCtx = GSS_C_NO_CONTEXT;
310
0
    mMechOID = &gss_krb5_mech_oid_desc;
311
0
312
0
    // if the type is kerberos we accept it as default
313
0
    // and exit
314
0
315
0
    if (package == PACKAGE_TYPE_KERBEROS)
316
0
        return;
317
0
318
0
    // Now, look at the list of supported mechanisms,
319
0
    // if SPNEGO is found, then use it.
320
0
    // Otherwise, set the desired mechanism to
321
0
    // GSS_C_NO_OID and let the system try to use
322
0
    // the default mechanism.
323
0
    //
324
0
    // Using Kerberos directly (instead of negotiating
325
0
    // with SPNEGO) may work in some cases depending
326
0
    // on how smart the server side is.
327
0
328
0
    majstat = gss_indicate_mechs_ptr(&minstat, &mech_set);
329
0
    if (GSS_ERROR(majstat))
330
0
        return;
331
0
332
0
    if (mech_set) {
333
0
        for (i=0; i<mech_set->count; i++) {
334
0
            item = &mech_set->elements[i];
335
0
            if (item->length == gss_spnego_mech_oid_desc.length &&
336
0
                !memcmp(item->elements, gss_spnego_mech_oid_desc.elements,
337
0
                item->length)) {
338
0
                // ok, we found it
339
0
                mMechOID = &gss_spnego_mech_oid_desc;
340
0
                break;
341
0
            }
342
0
        }
343
0
        gss_release_oid_set_ptr(&minstat, &mech_set);
344
0
    }
345
0
}
346
347
void
348
nsAuthGSSAPI::Reset()
349
0
{
350
0
    if (gssLibrary && mCtx != GSS_C_NO_CONTEXT) {
351
0
        OM_uint32 minor_status;
352
0
        gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER);
353
0
    }
354
0
    mCtx = GSS_C_NO_CONTEXT;
355
0
    mComplete = false;
356
0
}
357
358
/* static */ void
359
nsAuthGSSAPI::Shutdown()
360
0
{
361
0
    if (gssLibrary) {
362
0
        PR_UnloadLibrary(gssLibrary);
363
0
        gssLibrary = nullptr;
364
0
    }
365
0
}
366
367
/* Limitations apply to this class's thread safety. See the header file */
368
NS_IMPL_ISUPPORTS(nsAuthGSSAPI, nsIAuthModule)
369
370
NS_IMETHODIMP
371
nsAuthGSSAPI::Init(const char *serviceName,
372
                   uint32_t    serviceFlags,
373
                   const char16_t *domain,
374
                   const char16_t *username,
375
                   const char16_t *password)
376
0
{
377
0
    // we don't expect to be passed any user credentials
378
0
    NS_ASSERTION(!domain && !username && !password, "unexpected credentials");
379
0
380
0
    // it's critial that the caller supply a service name to be used
381
0
    NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
382
0
383
0
    LOG(("entering nsAuthGSSAPI::Init()\n"));
384
0
385
0
    if (!gssLibrary)
386
0
       return NS_ERROR_NOT_INITIALIZED;
387
0
388
0
    mServiceName = serviceName;
389
0
    mServiceFlags = serviceFlags;
390
0
391
0
    static bool sTelemetrySent = false;
392
0
    if (!sTelemetrySent) {
393
0
        mozilla::Telemetry::Accumulate(
394
0
            mozilla::Telemetry::NTLM_MODULE_USED_2,
395
0
            serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
396
0
                ? NTLM_MODULE_KERBEROS_PROXY
397
0
                : NTLM_MODULE_KERBEROS_DIRECT);
398
0
        sTelemetrySent = true;
399
0
    }
400
0
401
0
    return NS_OK;
402
0
}
403
404
NS_IMETHODIMP
405
nsAuthGSSAPI::GetNextToken(const void *inToken,
406
                           uint32_t    inTokenLen,
407
                           void      **outToken,
408
                           uint32_t   *outTokenLen)
409
0
{
410
0
    OM_uint32 major_status, minor_status;
411
0
    OM_uint32 req_flags = 0;
412
0
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
413
0
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
414
0
    gss_buffer_t  in_token_ptr = GSS_C_NO_BUFFER;
415
0
    gss_name_t server;
416
0
    nsAutoCString userbuf;
417
0
    nsresult rv;
418
0
419
0
    LOG(("entering nsAuthGSSAPI::GetNextToken()\n"));
420
0
421
0
    if (!gssLibrary)
422
0
       return NS_ERROR_NOT_INITIALIZED;
423
0
424
0
    // If they've called us again after we're complete, reset to start afresh.
425
0
    if (mComplete)
426
0
        Reset();
427
0
428
0
    if (mServiceFlags & REQ_DELEGATE)
429
0
        req_flags |= GSS_C_DELEG_FLAG;
430
0
431
0
    if (mServiceFlags & REQ_MUTUAL_AUTH)
432
0
        req_flags |= GSS_C_MUTUAL_FLAG;
433
0
434
0
    input_token.value = (void *)mServiceName.get();
435
0
    input_token.length = mServiceName.Length() + 1;
436
0
437
0
#if defined(HAVE_RES_NINIT)
438
0
    res_ninit(&_res);
439
0
#endif
440
0
    major_status = gss_import_name_ptr(&minor_status,
441
0
                                   &input_token,
442
0
                                   &gss_c_nt_hostbased_service,
443
0
                                   &server);
444
0
    input_token.value = nullptr;
445
0
    input_token.length = 0;
446
0
    if (GSS_ERROR(major_status)) {
447
0
        LogGssError(major_status, minor_status, "gss_import_name() failed");
448
0
        return NS_ERROR_FAILURE;
449
0
    }
450
0
451
0
    if (inToken) {
452
0
        input_token.length = inTokenLen;
453
0
        input_token.value = (void *) inToken;
454
0
        in_token_ptr = &input_token;
455
0
    }
456
0
    else if (mCtx != GSS_C_NO_CONTEXT) {
457
0
        // If there is no input token, then we are starting a new
458
0
        // authentication sequence.  If we have already initialized our
459
0
        // security context, then we're in trouble because it means that the
460
0
        // first sequence failed.  We need to bail or else we might end up in
461
0
        // an infinite loop.
462
0
        LOG(("Cannot restart authentication sequence!"));
463
0
        return NS_ERROR_UNEXPECTED;
464
0
    }
465
0
466
#if defined(XP_MACOSX)
467
    // Suppress Kerberos prompts to get credentials.  See bug 240643.
468
    // We can only use Mac OS X specific kerb functions if we are using
469
    // the native lib
470
    KLBoolean found;
471
    bool doingMailTask = mServiceName.Find("imap@") ||
472
                           mServiceName.Find("pop@") ||
473
                           mServiceName.Find("smtp@") ||
474
                           mServiceName.Find("ldap@");
475
476
    if (!doingMailTask && (gssNativeImp &&
477
         (KLCacheHasValidTickets_ptr(nullptr, kerberosVersion_V5, &found, nullptr, nullptr) != klNoErr || !found)))
478
    {
479
        major_status = GSS_S_FAILURE;
480
        minor_status = 0;
481
    }
482
    else
483
#endif /* XP_MACOSX */
484
0
    major_status = gss_init_sec_context_ptr(&minor_status,
485
0
                                            GSS_C_NO_CREDENTIAL,
486
0
                                            &mCtx,
487
0
                                            server,
488
0
                                            mMechOID,
489
0
                                            req_flags,
490
0
                                            GSS_C_INDEFINITE,
491
0
                                            GSS_C_NO_CHANNEL_BINDINGS,
492
0
                                            in_token_ptr,
493
0
                                            nullptr,
494
0
                                            &output_token,
495
0
                                            nullptr,
496
0
                                            nullptr);
497
0
498
0
    if (GSS_ERROR(major_status)) {
499
0
        LogGssError(major_status, minor_status, "gss_init_sec_context() failed");
500
0
        Reset();
501
0
        rv = NS_ERROR_FAILURE;
502
0
        goto end;
503
0
    }
504
0
    if (major_status == GSS_S_COMPLETE) {
505
0
        // Mark ourselves as being complete, so that if we're called again
506
0
        // we know to start afresh.
507
0
        mComplete = true;
508
0
    }
509
0
    else if (major_status == GSS_S_CONTINUE_NEEDED) {
510
0
        //
511
0
        // The important thing is that we do NOT reset the
512
0
        // context here because it will be needed on the
513
0
        // next call.
514
0
        //
515
0
    }
516
0
517
0
    *outTokenLen = output_token.length;
518
0
    if (output_token.length != 0)
519
0
        *outToken = moz_xmemdup(output_token.value, output_token.length);
520
0
    else
521
0
        *outToken = nullptr;
522
0
523
0
    gss_release_buffer_ptr(&minor_status, &output_token);
524
0
525
0
    if (major_status == GSS_S_COMPLETE)
526
0
        rv = NS_SUCCESS_AUTH_FINISHED;
527
0
    else
528
0
        rv = NS_OK;
529
0
530
0
end:
531
0
    gss_release_name_ptr(&minor_status, &server);
532
0
533
0
    LOG(("  leaving nsAuthGSSAPI::GetNextToken [rv=%" PRIx32 "]",
534
0
         static_cast<uint32_t>(rv)));
535
0
    return rv;
536
0
}
537
538
NS_IMETHODIMP
539
nsAuthGSSAPI::Unwrap(const void *inToken,
540
                     uint32_t    inTokenLen,
541
                     void      **outToken,
542
                     uint32_t   *outTokenLen)
543
0
{
544
0
    OM_uint32 major_status, minor_status;
545
0
546
0
    gss_buffer_desc input_token;
547
0
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
548
0
549
0
    input_token.value = (void *) inToken;
550
0
    input_token.length = inTokenLen;
551
0
552
0
    major_status = gss_unwrap_ptr(&minor_status,
553
0
                                  mCtx,
554
0
                                  &input_token,
555
0
                                  &output_token,
556
0
                                  nullptr,
557
0
                                  nullptr);
558
0
    if (GSS_ERROR(major_status)) {
559
0
        LogGssError(major_status, minor_status, "gss_unwrap() failed");
560
0
        Reset();
561
0
        gss_release_buffer_ptr(&minor_status, &output_token);
562
0
        return NS_ERROR_FAILURE;
563
0
    }
564
0
565
0
    *outTokenLen = output_token.length;
566
0
567
0
    if (output_token.length)
568
0
        *outToken = moz_xmemdup(output_token.value, output_token.length);
569
0
    else
570
0
        *outToken = nullptr;
571
0
572
0
    gss_release_buffer_ptr(&minor_status, &output_token);
573
0
574
0
    return NS_OK;
575
0
}
576
577
NS_IMETHODIMP
578
nsAuthGSSAPI::Wrap(const void *inToken,
579
                   uint32_t    inTokenLen,
580
                   bool        confidential,
581
                   void      **outToken,
582
                   uint32_t   *outTokenLen)
583
0
{
584
0
    OM_uint32 major_status, minor_status;
585
0
586
0
    gss_buffer_desc input_token;
587
0
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
588
0
589
0
    input_token.value = (void *) inToken;
590
0
    input_token.length = inTokenLen;
591
0
592
0
    major_status = gss_wrap_ptr(&minor_status,
593
0
                                mCtx,
594
0
                                confidential,
595
0
                                GSS_C_QOP_DEFAULT,
596
0
                                &input_token,
597
0
                                nullptr,
598
0
                                &output_token);
599
0
600
0
    if (GSS_ERROR(major_status)) {
601
0
        LogGssError(major_status, minor_status, "gss_wrap() failed");
602
0
        Reset();
603
0
        gss_release_buffer_ptr(&minor_status, &output_token);
604
0
        return NS_ERROR_FAILURE;
605
0
    }
606
0
607
0
    *outTokenLen = output_token.length;
608
0
609
0
    /* it is not possible for output_token.length to be zero */
610
0
    *outToken = moz_xmemdup(output_token.value, output_token.length);
611
0
    gss_release_buffer_ptr(&minor_status, &output_token);
612
0
613
0
    return NS_OK;
614
0
}
615