示例#1
0
int
srp_decrypt_aes256_hmac_sha1(
    srp_gss_ctx_id_t srp_context_handle,
    unsigned char *in_hmacbuf,
    int in_hmacbuf_len,
    unsigned char *in_ciphertext,
    int in_ciphertext_len,
    unsigned char *ret_plaintext)
{
    int sts = 0;
    unsigned char *cipherhmac_buf = NULL;
    unsigned char *plaintext = NULL;
    unsigned char *ciphertext_start = NULL;
    int cipherhmac_buf_len = 0;
    int ciphertext_len = 0;
    int hmac_computed_len = 0;
    unsigned char hmac[SRP_SHA1_HMAC_BUFSIZ] = {0};
    unsigned char hmac_computed[SRP_SHA1_HMAC_BUFSIZ] = {0};

    /* Splice in_hmacbuf + in_ciphertext together, this is the ciphertext */
    cipherhmac_buf_len = in_hmacbuf_len + in_ciphertext_len;

    /* Buffer must adhere to AES-256 padding requirements */
    ciphertext_len = AES256PAD((cipherhmac_buf_len - SRP_SHA1_HMAC_BUFSIZ));
    cipherhmac_buf = (unsigned char *) calloc(cipherhmac_buf_len,
                                              sizeof(unsigned char));
    if (!cipherhmac_buf)
    {
        sts = ENOMEM;
        goto error;
    }

    plaintext = (unsigned char *) calloc(ciphertext_len,
                                         sizeof(unsigned char));
    if (!plaintext )
    {
        sts = ENOMEM;
        goto error;
    }

    memcpy(cipherhmac_buf, in_hmacbuf, in_hmacbuf_len);
    memcpy(cipherhmac_buf + in_hmacbuf_len, in_ciphertext, in_ciphertext_len);

    /* Save the HMAC-SHA1 verifier from client */
    memcpy(hmac, cipherhmac_buf, SRP_SHA1_HMAC_BUFSIZ);

    srp_print_hex(hmac,
                   SRP_SHA1_HMAC_BUFSIZ,
                   "srp_decrypt_aes256_hmac_sha1: client hmac");

    /* Perform hmac-sha validation over the ciphertext */
    ciphertext_start = cipherhmac_buf + SRP_SHA1_HMAC_BUFSIZ;
    if (!srp_compute_hmac(
         srp_context_handle->hmac_ctx,
         ciphertext_start,
         ciphertext_len,
         hmac_computed,
         &hmac_computed_len))
    {
        sts = EINVAL;
        goto error;
    }

    /* Verify computed verifier matches client verifier */
    if (hmac_computed_len != SRP_SHA1_HMAC_BUFSIZ ||
        memcmp(hmac, hmac_computed, hmac_computed_len) != 0)
    {
        srp_print_hex(hmac_computed,
                       SRP_SHA1_HMAC_BUFSIZ,
                       "srp_decrypt_aes256_hmac_sha1: ERROR computed hmac");
        /* verifier failed, return error */
        sts = GSS_S_DEFECTIVE_TOKEN;
        goto error;
    }

    /* This is the full ciphertext, which can then be decrypted. */
    AES_cbc_encrypt(ciphertext_start,
                    plaintext,
                    ciphertext_len,
                    &srp_context_handle->aes_decrypt_key,
                    srp_context_handle->aes_decrypt_iv,
                    AES_DECRYPT);

    memcpy(ret_plaintext, plaintext, ciphertext_len);

error:
    if (plaintext)
    {
        free(plaintext);
    }
    if (cipherhmac_buf)
    {
        free(cipherhmac_buf);
    }
    return sts;
}
示例#2
0
int
srp_encrypt_aes256_hmac_sha1(
    srp_gss_ctx_id_t srp_context_handle,
    unsigned char *plaintext,
    int plaintext_len,
    unsigned char *out_ciphertext,
    unsigned char **out_hmacbuf,
    int *out_hmacbuf_len)
{
    int sts = 0;
    int hmacbuf_len = 0;
    int hmac_bufpad_len = 0;
    int ciphertext_len = 0;
    int ciphertext_pad_len = 0;
    int verifier_len = 0;
    unsigned char *hmacbuf = NULL;
    unsigned char *hmacbuf_end = NULL;
    unsigned char *ciphertext = NULL;
    unsigned char *ret_hmacbuf = NULL;

    /*
     * Message format:
     *   ciphertext = AES256(key, plaintext)
     *   |-- HMAC-SHA1(ciphertext) (20) --|-- ciphertext --|)
     *
     * Result:
     *   Contiguous ciphertext buffer is split into two pieces across
     *   iov, as iov[1] cannot be resized, but iov[0] can.
     *
     *     iov[0] data: |-- AES256 (verifier-len) --|
     *     iov[1] data: |-- AES256 (plaintext-len) --|
     */

    ciphertext_pad_len = AES256PAD(plaintext_len);
    /*
     * Note: The below padding may cause buffer expansion which cannot fit into
     * the original iov[1] payload buffer. The "residual data" from this
     * expansion is returned in iov[0], semantically the hmac verifier.
     */
    hmac_bufpad_len = ciphertext_pad_len + SRP_SHA1_HMAC_BUFSIZ;
    hmacbuf = (unsigned char *) calloc(hmac_bufpad_len, sizeof(unsigned char));
    if (!hmacbuf)
    {
        sts = ENOMEM;
        goto error;
    }
    hmacbuf_end = hmacbuf;

    /* Same size as the input buffer; holds the output cipher text */
    ciphertext_len = ciphertext_pad_len;
    ciphertext = (unsigned char *) calloc(ciphertext_len,
                                          sizeof(unsigned char));
    if (!ciphertext)
    {
        sts = ENOMEM;
        goto error;
    }

    /* AES256 encrypt the plaintext payload data */
    AES_cbc_encrypt(
        plaintext,
        ciphertext,
        ciphertext_len,
        &srp_context_handle->aes_encrypt_key,
        srp_context_handle->aes_encrypt_iv,
        AES_ENCRYPT);

    /* Perform hmac-sha validation over ciphertext payload */
    if (!srp_compute_hmac(
         srp_context_handle->hmac_ctx,
         ciphertext,
         ciphertext_len,
         hmacbuf,
         &hmacbuf_len))
    {
        sts = EINVAL;
        goto error;
    }

    if (hmacbuf_len > SRP_SHA1_HMAC_BUFSIZ)
    {
        hmacbuf_len = SRP_SHA1_HMAC_BUFSIZ;
    }
    hmacbuf_end += hmacbuf_len;

    srp_print_hex(hmacbuf,
                  hmacbuf_len,
                  "srp_encrypt_aes256_hmac_sha1: hmac =");

    /* Copy the ciphertext message after the HMAC data */
    memcpy(hmacbuf_end, ciphertext, ciphertext_len);

    /* Verifier data: what cannot fit into iov[1] */
    verifier_len = hmac_bufpad_len - ciphertext_len;

    ret_hmacbuf = (unsigned char *) calloc(verifier_len,
                                           sizeof(unsigned char));
    if (!ret_hmacbuf)
    {
        sts = ENOMEM;
        goto error;
    }

    /* Split cipher text into two iov values: iov[0] = HMAC code */
    memcpy(ret_hmacbuf, hmacbuf, verifier_len);

    /* iov[1] = cipher text */
    memcpy(out_ciphertext,
           hmacbuf + verifier_len,
           plaintext_len);

    /* Additional iov[0] length due to padding expansion */
    *out_hmacbuf = ret_hmacbuf;
    *out_hmacbuf_len = verifier_len;

error:
    if (sts)
    {
        if (ret_hmacbuf)
        {
            free(ret_hmacbuf);
        }
    }
    if (hmacbuf)
    {
        free(hmacbuf);
    }
    if (ciphertext)
    {
        free(ciphertext);
    }
    return sts;
}
示例#3
0
static
OM_uint32
_srp_gss_validate_client(
    OM_uint32 *minor_status,
    srp_gss_ctx_id_t srp_context_handle,
    int state,
    gss_buffer_t input_token,
    gss_buffer_t output_token)
{
    OM_uint32 maj = 0;
    OM_uint32 min = 0;
    int berror = 0;
    ber_tag_t ber_state = 0;
    BerElement *ber = NULL;
    BerElement *ber_resp = NULL;
    struct berval ber_HAMK = {0};
    struct berval *ber_srp_bytes_M = NULL;
    struct berval ber_ctx = {0};
    const unsigned char *bytes_HAMK = NULL;
    int bytes_HAMK_len = 0;
    struct berval *flatten = NULL;
    PVMDIR_SERVER_CONTEXT hServer = NULL;

    ber_ctx.bv_val = (void *) input_token->value;
    ber_ctx.bv_len = input_token->length;
    ber = ber_init(&ber_ctx);
    if (!ber)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_debug_printf("_srp_gss_validate_client(): "
                     "state=SRP_AUTH_CLIENT_VALIDATE\n");

    /*
     * ptr points to ASN.1 encoded data which is dependent on the authentication
     * state. The appropriate decoder format string is applied for each state
     */
    berror = ber_scanf(ber, "t{O}", &ber_state, &ber_srp_bytes_M);
    if (berror == -1)
    {
        maj = GSS_S_FAILURE;
        min = GSS_S_DEFECTIVE_TOKEN;
        goto error;
    }

    /*
     * This is mostly impossible, as state IS the "t" field.
     * More a double check for proper decoding.
     */
    if ((int) ber_state != state || ber_srp_bytes_M->bv_len == 0)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_print_hex(ber_srp_bytes_M->bv_val, (int) ber_srp_bytes_M->bv_len,
                  "_srp_gss_validate_client(accept_sec_ctx) received bytes_M");

    if (srp_context_handle->bUseCSRP)
    {
        srp_verifier_verify_session(
            srp_context_handle->srp_ver,
            ber_srp_bytes_M->bv_val,
            &bytes_HAMK);
        if (!bytes_HAMK)
        {
            min = rpc_s_auth_mut_fail;
        }
    }
    else
    {
        hServer = srp_context_handle->hServer;
        min = cli_rpc_srp_verifier_verify_session(
                  hServer->hBinding,
                  srp_context_handle->srp_ver,
                  ber_srp_bytes_M->bv_val, (int) ber_srp_bytes_M->bv_len,
                  &bytes_HAMK, &bytes_HAMK_len);
    }
    if (min || !bytes_HAMK)
    {
        /*
         * Bad password will cause this to fail. Do not bail on error here.
         * Merely generate a NULL HAMK response below, to complete the
         * SRP protocol exchange with the client. The client tests for an
         * empty HAMK token, and formulates the proper error.
         */
        srp_debug_printf("_srp_gss_validate_client: "
                         "srp_verifier_verify_session() failed!!!\n");
    }

    /*
     * ASN.1 encode the bytes_HAMK value, sending it back to the client
     * for validation. That will complete the authentication process if that
     * succeeds.
     */

    ber_resp = ber_alloc_t(LBER_USE_DER);
    if (!ber_resp)
    {
        maj = GSS_S_FAILURE;
        min = ENOMEM;
        goto error;
    }
    if (min == 0)
    {
        if (srp_context_handle->bUseCSRP)
        {
            bytes_HAMK_len = srp_verifier_get_session_key_length(srp_context_handle->srp_ver);
        }
        else
        {
            /*
             * Generate HAMK response. When min is an error code,
             * an empty HAMK response (zero length) is created.
             */
            min = cli_rpc_srp_verifier_get_session_key_length(
                      hServer->hBinding,
                      srp_context_handle->srp_ver,
                      (long *) &ber_HAMK.bv_len);
            if (min)
            {
                maj = GSS_S_FAILURE;
                goto error;
            }
        }
    }

    ber_HAMK.bv_val = (void *) bytes_HAMK;
    ber_HAMK.bv_len = bytes_HAMK_len;
    berror = ber_printf(ber_resp, "t{O}",
                  (int) SRP_AUTH_SERVER_VALIDATE,
                  &ber_HAMK);
    if (berror == -1)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    berror = ber_flatten(ber_resp, &flatten);
    if (berror == -1)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    output_token->value = gssalloc_calloc(1, flatten->bv_len);
    if (!output_token->value)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }
    output_token->length = flatten->bv_len;
    memcpy(output_token->value, flatten->bv_val, flatten->bv_len);

    /*
     * From server's perspective, authentication is done. However,
     * there is a final output_token to process by gss_init_sec_context().
     */
    maj = GSS_S_COMPLETE;

error:
    if (ber_srp_bytes_M)
    {
        ber_bvfree(ber_srp_bytes_M);
    }
    if (!srp_context_handle->bUseCSRP && bytes_HAMK)
    {
        free((void *) bytes_HAMK);
    }
    ber_bvfree(flatten);
    ber_free(ber, 1);
    ber_free(ber_resp, 1);
    if (maj)
    {
        if (min)
        {
            *minor_status = min;
        }
    }
    return maj;
}
示例#4
0
krb5_error_code
srp_make_enc_keyblock(
    srp_gss_ctx_id_t srp_context_handle)
{
    char *srp_session_key_str = NULL;
    unsigned char *hmac_key = NULL;
    int b64_alloc_len = 0;

    unsigned char *ptr_expanded_key = NULL;
    unsigned char expanded_session_key[SRP_EXPAND_KEY_LEN] = {0};

    unsigned char srp_session_key[SRP_EXPAND_SESSION_KEY_LEN] = {0};
    int srp_session_key_len = sizeof(srp_session_key);

    unsigned char iv_data[AES_BLOCK_SIZE] = {0};
    int iv_data_len = sizeof(iv_data);

    int b64_session_key_len = 0;
    krb5_error_code krb5_err = KRB5_BAD_ENCTYPE;

    if (!srp_context_handle->srp_session_key ||
        srp_context_handle->srp_session_key_len == 0)
    {
        krb5_err = GSS_S_DEFECTIVE_TOKEN;
        goto error;
    }

    srp_print_hex(srp_context_handle->srp_session_key,
                  srp_context_handle->srp_session_key_len,
                  "srp_make_enc_keyblock: SRP-negotiated session key ");

    /* Expand SRP session key to obtain more bytes for IV/session key */
    krb5_err = srp_expand_session_key(
                   srp_context_handle->srp_session_key,
                   srp_context_handle->srp_session_key_len,
                   srp_context_handle->upn_name,         /* salt */
                   (int) strlen(srp_context_handle->upn_name), /* salt length */
                   SRP_EXPAND_KEY_ITER,
                   sizeof(expanded_session_key),
                   expanded_session_key);
    if (krb5_err)
    {
        goto error;
    }

    /* Carve up parts of the expanded key for various purposes */
    ptr_expanded_key = expanded_session_key;

    /* Initialization vector */
    memcpy(iv_data, ptr_expanded_key, iv_data_len);
    ptr_expanded_key += iv_data_len;

    srp_print_hex(iv_data,
                  iv_data_len,
                  "srp_make_enc_keyblock: got initialization vector ");

    /* SRP "derived session" key */
    memcpy(srp_session_key, ptr_expanded_key, srp_session_key_len);
    ptr_expanded_key += sizeof(srp_session_key);

    /* HMAC key, remaining 16 bytes */
    hmac_key = ptr_expanded_key;

    srp_print_hex(srp_session_key,
                  srp_session_key_len,
                  "srp_make_enc_keyblock: got derived session key");

    /* Build b64 encoded string of SRP session key */
    b64_alloc_len = (srp_session_key_len + 2) / 3  * 4 + 1;
    srp_session_key_str = calloc(b64_alloc_len, sizeof(char));
    if (!srp_session_key_str)
    {
        krb5_err = ENOMEM;
        goto error;
    }

    krb5_err = sasl_encode64(
                   srp_session_key,
                   srp_session_key_len,
                   srp_session_key_str,
                   b64_alloc_len,
                   &b64_session_key_len);
    if (krb5_err)
    {
        krb5_err = ENOMEM;
        goto error;
    }
    srp_session_key_str[b64_session_key_len] = '\0';

    srp_context_handle->keyblock = calloc(1, sizeof(krb5_keyblock));
    if (!srp_context_handle->keyblock)
    {
        krb5_err = ENOMEM;
        goto error;
    }

    /* Generate encryption key from SRP shared key */
    krb5_err = srp_gen_keyblock(
                   srp_context_handle->krb5_ctx,
                   SRP_ENC_KEYTYPE,
                   srp_session_key_str,
                   srp_context_handle->upn_name,
                   srp_context_handle->keyblock);
    if (krb5_err)
    {
        goto error;
    }

    srp_print_hex(srp_context_handle->keyblock->contents,
                  srp_context_handle->keyblock->length,
                  "srp_make_enc_keyblock: keyblock value");

     memset(srp_context_handle->aes_encrypt_iv, 0, iv_data_len);
     memcpy(srp_context_handle->aes_encrypt_iv, iv_data, iv_data_len);

     memset(srp_context_handle->aes_decrypt_iv, 0, iv_data_len);
     memcpy(srp_context_handle->aes_decrypt_iv, iv_data, iv_data_len);

    AES_set_encrypt_key(
        srp_context_handle->keyblock->contents,
        srp_context_handle->keyblock->length * 8,
        &srp_context_handle->aes_encrypt_key);
    AES_set_decrypt_key(
        srp_context_handle->keyblock->contents,
        srp_context_handle->keyblock->length * 8,
        &srp_context_handle->aes_decrypt_key);

    if (srp_init_hmac(&srp_context_handle->hmac_ctx,
                      hmac_key,
                      SRP_EXPAND_HMAC_KEY))
    {
        krb5_err = ENOMEM;
        goto error;
    }

error:
    if (krb5_err)
    {
        if (srp_context_handle->keyblock)
        {
            free(srp_context_handle->keyblock);
        }
    }

    if (srp_session_key_str)
    {
        free(srp_session_key_str);
    }
    return krb5_err;
}
示例#5
0
static
OM_uint32
_srp_gss_auth_init(
    OM_uint32 *minor_status,
    srp_gss_ctx_id_t srp_context_handle,
    int state,
    gss_buffer_t input_token,
    gss_buffer_t output_token)
{
    ber_tag_t ber_state = 0;
    struct berval ber_ctx = {0};
    struct berval *ber_upn = NULL;
    struct berval *ber_bytes_A = NULL;
    struct berval ber_salt = {0};
    struct berval ber_mda = {0};
    struct berval ber_B = {0};
    struct berval *flatten = NULL;
    BerElement *ber = NULL;
    BerElement *ber_resp = NULL;
    int berror = 0;
    int sts = 0;
    OM_uint32 maj = 0;
    OM_uint32 min = 0;
    OM_uint32 min_tmp = 0;
    gss_buffer_desc tmp_in_tok = {0};
    gss_buffer_desc disp_name_buf = {0};
    gss_buffer_t disp_name = NULL;
    gss_OID disp_name_OID = NULL;
    char *srp_upn_name = NULL;
    int srp_decode_mda_len = 0;
    int srp_decode_salt_len = 0;
    const unsigned char *srp_mda = NULL;
    const unsigned char *srp_salt = NULL;
    SRP_HashAlgorithm hash_alg = SRP_SHA1;
    SRP_NGType ng_type = SRP_NG_2048;
    struct SRPVerifier *ver = NULL;
    const unsigned char *srp_bytes_B = NULL;
    int srp_bytes_B_len = 0;
    const unsigned char *srp_session_key = NULL;
    unsigned char *ret_srp_session_key = NULL;
    int srp_session_key_len = 0;
    ber_int_t gss_srp_version_maj = 0;
    ber_int_t gss_srp_version_min = 0;
    PVMDIR_SERVER_CONTEXT hServer = NULL;
    srp_verifier_handle_t hSrp = NULL; /* aliased / cast to "ver" variable */
    srp_secret_blob_data srp_data = {0};
    int bUseCSRP = 0; /* Use CRP library directly */

    ber_ctx.bv_val = (void *) input_token->value;
    ber_ctx.bv_len = input_token->length;
    ber = ber_init(&ber_ctx);
    if (!ber)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_debug_printf("_srp_gss_auth_init(): state=SRP_AUTH_INIT\n");

    /*
     * ptr points to ASN.1 encoded data which is dependent on the authentication
     * state. The appropriate decoder format string is applied for each state
     */
    berror = ber_scanf(ber, "t{ii",
                       &ber_state, &gss_srp_version_maj, &gss_srp_version_min);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_scanf(t{ii): failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }
    berror = ber_scanf(ber, "OO}", &ber_upn, &ber_bytes_A);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_scanf(OO): failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_debug_printf("_srp_gss_auth_init(accept_sec_context): protocol version %d.%d\n",
                     gss_srp_version_maj, gss_srp_version_min);
    srp_print_hex(ber_bytes_A->bv_val,
                  (int) ber_bytes_A->bv_len,
                  "_srp_gss_auth_init(accept_sec_context): bytes_A");
    /*
     * This is mostly impossible, as state IS the "t" field.
     * More a double check for proper decoding.
     */
    if ((int) ber_state != state)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    tmp_in_tok.value = ber_upn->bv_val;
    tmp_in_tok.length = ber_upn->bv_len;
    maj = gss_import_name(&min,
                          &tmp_in_tok,
                          NULL,
                          &srp_context_handle->gss_upn_name);
    if (maj)
    {
        srp_debug_printf("_srp_gss_auth_init() gss_import_name failed maj=%d\n", maj);
        goto error;
    }

    maj = gss_display_name(&min,
                           srp_context_handle->gss_upn_name,
                           &disp_name_buf,
                           &disp_name_OID);
    if (maj)
    {
        srp_debug_printf("_srp_gss_auth_init() gss_display_name failed maj=%d\n", maj);
        goto error;
    }

    disp_name = &disp_name_buf;
    srp_debug_printf("_srp_gss_auth_init() srp_gss_accept_sec_context: UPN name=%.*s\n",
                     (int) disp_name_buf.length, (char *) disp_name_buf.value);

    srp_upn_name = calloc(disp_name_buf.length + 1, sizeof(char));
    if (!srp_upn_name)
    {
        maj = GSS_S_FAILURE;
        min = ENOMEM;
        goto error;
    }
    snprintf(srp_upn_name,
             disp_name_buf.length+1,
             "%.*s",
             (int) disp_name_buf.length,
             (char *) disp_name_buf.value);


    maj = _srp_gss_auth_create_machine_acct_binding(
              &bUseCSRP,
              &min,
              &hServer);
    if (maj)
    {
        srp_debug_printf("_srp_gss_auth_init() _srp_gss_auth_create_machine_acct_binding failed maj=%d\n", maj);
        maj = GSS_S_FAILURE;
        goto error;
    }

    if (!bUseCSRP)
    {
        sts = cli_rpc_srp_verifier_new(
                hServer ? hServer->hBinding : NULL,
                hash_alg,
                ng_type,
                srp_upn_name,
                ber_bytes_A->bv_val, (int) ber_bytes_A->bv_len,
                &srp_bytes_B, &srp_bytes_B_len,
                &srp_salt, &srp_decode_salt_len,
                &srp_mda, &srp_decode_mda_len,
                NULL, NULL, /* n_hex, g_hex */
                &hSrp);
        if (sts)
        {
            srp_debug_printf("_srp_gss_auth_init() cli_rpc_srp_verifier_new: failed sts=%d\n", sts);
            maj = GSS_S_FAILURE;
            min = sts;
            goto error;
        }
        ver = (struct SRPVerifier *) hSrp, hSrp = NULL;
    }
    else
    {
        sts = _get_srp_secret_decoded(
                  srp_upn_name,
                  &srp_data);
        if (sts)
        {
            srp_debug_printf("_srp_gss_auth_init() _get_srp_secret_decoded: failed sts=%d\n", sts);
            maj = GSS_S_FAILURE;
            min = sts;
            goto error;
        }

        /* Call SRP library implementation directly */
        ver =  srp_verifier_new(hash_alg, 
                                ng_type,
                                srp_upn_name,

                                /* SRP Salt value */
                                srp_data.salt, srp_data.salt_len,

                                /* SRP "V" verifier secret */
                                srp_data.v, srp_data.v_len,

                                /* SRP bytes_A */
                                ber_bytes_A->bv_val, (int) ber_bytes_A->bv_len,

                                /* SRP bytes B */
                                &srp_bytes_B, &srp_bytes_B_len,

                                /* SRP n_hex / g_hex */
                                NULL, NULL);
        if (!ver)
        {
            srp_debug_printf("_srp_gss_auth_init() srp_verifier_new: failed sts=%d\n", sts);
            maj = GSS_S_FAILURE;
            goto error;
        }
        srp_salt = srp_data.salt;
        srp_decode_salt_len = srp_data.salt_len;

    }

    if (!srp_bytes_B)
    {
        srp_debug_printf("_srp_gss_auth_init() srp_verifier_new: failed!\n");
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_print_hex(srp_salt, srp_decode_salt_len,
                  "_srp_gss_auth_init(accept_sec_context): srp_salt value");
    srp_print_hex(srp_bytes_B, srp_bytes_B_len,
                  "_srp_gss_auth_init(accept_sec_context): srp_B value");
    ber_mda.bv_val = (unsigned char *) srp_mda;
    ber_mda.bv_len = srp_decode_mda_len;

    ber_salt.bv_val = (unsigned char *) srp_salt;
    ber_salt.bv_len = srp_decode_salt_len;
    /*
     * B is computed: (kv + g**b) % N
     */
    ber_B.bv_val = (void *) srp_bytes_B;
    ber_B.bv_len = srp_bytes_B_len;

    ber_resp = ber_alloc_t(LBER_USE_DER);
    if (!ber_resp)
    {
        maj = GSS_S_FAILURE;
        min = ENOMEM;
        goto error;
    }

    /*
     * Response format:
     * tag | MDA | salt | B
     */
    berror = ber_printf(ber_resp, "t{OOO}",
                 SRP_AUTH_SALT_RESP,
                 &ber_mda,
                 &ber_salt,
                 &ber_B);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_printf: failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }

    berror = ber_flatten(ber_resp, &flatten);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_flatten: failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }

    output_token->value = gssalloc_calloc(1, flatten->bv_len);
    if (!output_token->value)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }
    output_token->length = flatten->bv_len;
    memcpy(output_token->value, flatten->bv_val, flatten->bv_len);

    if (bUseCSRP)
    {
        srp_session_key = srp_verifier_get_session_key(ver, &srp_session_key_len);
    }
    else
    {
        sts = cli_rpc_srp_verifier_get_session_key(
            hServer ? hServer->hBinding : NULL,
            ver,
            &srp_session_key,
            &srp_session_key_len);
        if (sts)
        {
            min = sts;
            maj = GSS_S_FAILURE;
            goto error;
        }

    }

    if (srp_session_key && srp_session_key_len > 0)
    {
        ret_srp_session_key =
            calloc(srp_session_key_len, sizeof(unsigned char));
        if (!ret_srp_session_key)
        {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
            goto error;
        }
    }
    memcpy(ret_srp_session_key,
           srp_session_key,
           srp_session_key_len);

    /* Set context handle/return values here; all previous calls succeeded */
    maj = GSS_S_CONTINUE_NEEDED;
    srp_context_handle->hServer = hServer, hServer = NULL;

    /* Used in generating Kerberos keyblock salt value */
    srp_context_handle->upn_name = srp_upn_name, srp_upn_name = NULL;
    srp_context_handle->srp_ver = ver, ver = NULL;

    /* Return the SRP session key in the context handle */
    srp_context_handle->srp_session_key_len = srp_session_key_len;
    srp_context_handle->srp_session_key = ret_srp_session_key, ret_srp_session_key = NULL;
    srp_context_handle->bUseCSRP = bUseCSRP;

    srp_print_hex(srp_session_key, srp_session_key_len,
                  "_srp_gss_auth_init(accept_sec_ctx) got session key");

error:
    if (ver)
    {
        if (bUseCSRP)
        {
            srp_verifier_delete(ver);
        }
        else
        {
            cli_rpc_srp_verifier_delete(
                hServer ? hServer->hBinding : NULL,
                (void **) &ver);
        }
    }
    VmDirCloseServer(hServer);
    if (srp_upn_name)
    {
        free(srp_upn_name);
    }
    if (ber_upn)
    {
        ber_bvfree(ber_upn);
    }
    if (ber_bytes_A)
    {
        ber_bvfree(ber_bytes_A);
    }
    ber_bvfree(flatten);
    ber_free(ber, 1);
    ber_free(ber_resp, 1);

    if (disp_name)
    {
        gss_release_buffer(&min_tmp, disp_name);
    }
    if (!bUseCSRP && srp_bytes_B)
    {
        free((void *) srp_bytes_B);
    }
    if (!bUseCSRP && srp_salt)
    {
        free((void *) srp_salt);
    }
    if (srp_mda)
    {
        free((void *) srp_mda);
    }
    if (!bUseCSRP && srp_session_key)
    {
        free((void *) srp_session_key);
    }
    if (bUseCSRP)
    {
        _free_srp_secret_decoded(&srp_data);
    }
    if (ret_srp_session_key)
    {
        free((void *) ret_srp_session_key);
    }

    if (maj)
    {
        if (min)
        {
            *minor_status = min;
        }
    }
    return maj;
}