Exemplo n.º 1
0
krb5_error_code
kg_encrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
           krb5_const_pointer in, krb5_pointer out, unsigned int length)
{
    krb5_error_code code;
    size_t blocksize;
    krb5_data ivd, *pivd, inputd;
    krb5_enc_data outputd;

    if (iv) {
        code = krb5_c_block_size(context, key->keyblock.enctype, &blocksize);
        if (code)
            return(code);

        ivd.length = blocksize;
        ivd.data = malloc(ivd.length);
        if (ivd.data == NULL)
            return ENOMEM;
        memcpy(ivd.data, iv, ivd.length);
        pivd = &ivd;
    } else {
        pivd = NULL;
    }

    inputd.length = length;
    inputd.data = (char *)in;

    outputd.ciphertext.length = length;
    outputd.ciphertext.data = out;

    code = krb5_k_encrypt(context, key, usage, pivd, &inputd, &outputd);
    if (pivd != NULL)
        free(pivd->data);
    return code;
}
Exemplo n.º 2
0
Arquivo: mk_priv.c Projeto: krb5/krb5
/*
 * Marshal a KRB-PRIV message into der_out, encrypted with key.  Store the
 * ciphertext in enc_out.  Use the timestamp and sequence number from rdata and
 * the addresses from local_addr and remote_addr (the second of which may be
 * NULL).  der_out and enc_out should be freed by the caller when finished.
 */
static krb5_error_code
create_krbpriv(krb5_context context, const krb5_data *userdata,
               krb5_key key, const krb5_replay_data *rdata,
               krb5_address *local_addr, krb5_address *remote_addr,
               krb5_data *cstate, krb5_data *der_out, krb5_enc_data *enc_out)
{
    krb5_enctype enctype = krb5_k_key_enctype(context, key);
    krb5_error_code ret;
    krb5_priv privmsg;
    krb5_priv_enc_part encpart;
    krb5_data *der_encpart = NULL, *der_krbpriv;
    size_t enclen;

    memset(&privmsg, 0, sizeof(privmsg));
    privmsg.enc_part.kvno = 0;
    privmsg.enc_part.enctype = enctype;
    encpart.user_data = *userdata;
    encpart.s_address = local_addr;
    encpart.r_address = remote_addr;
    encpart.timestamp = rdata->timestamp;
    encpart.usec = rdata->usec;
    encpart.seq_number = rdata->seq;

    /* Start by encoding the to-be-encrypted part of the message. */
    ret = encode_krb5_enc_priv_part(&encpart, &der_encpart);
    if (ret)
        return ret;

    /* put together an eblock for this encryption */
    ret = krb5_c_encrypt_length(context, enctype, der_encpart->length,
                                &enclen);
    if (ret)
        goto cleanup;

    ret = alloc_data(&privmsg.enc_part.ciphertext, enclen);
    if (ret)
        goto cleanup;

    ret = krb5_k_encrypt(context, key, KRB5_KEYUSAGE_KRB_PRIV_ENCPART,
                         (cstate->length > 0) ? cstate : NULL, der_encpart,
                         &privmsg.enc_part);
    if (ret)
        goto cleanup;

    ret = encode_krb5_priv(&privmsg, &der_krbpriv);
    if (ret)
        goto cleanup;

    *der_out = *der_krbpriv;
    free(der_krbpriv);

    *enc_out = privmsg.enc_part;
    memset(&privmsg.enc_part, 0, sizeof(privmsg.enc_part));

cleanup:
    zapfree(privmsg.enc_part.ciphertext.data,
            privmsg.enc_part.ciphertext.length);
    zapfreedata(der_encpart);
    return ret;
}
Exemplo n.º 3
0
krb5_error_code KRB5_CALLCONV
krb5_c_encrypt(krb5_context context, const krb5_keyblock *keyblock,
               krb5_keyusage usage, const krb5_data *cipher_state,
               const krb5_data *input, krb5_enc_data *output)
{
    krb5_key key;
    krb5_error_code ret;

    ret = krb5_k_create_key(context, keyblock, &key);
    if (ret != 0)
        return ret;
    ret = krb5_k_encrypt(context, key, usage, cipher_state, input, output);
    krb5_k_free_key(context, key);
    return ret;
}
Exemplo n.º 4
0
static krb5_error_code
mk_priv_basic(krb5_context context, const krb5_data *userdata,
              krb5_key key, krb5_replay_data *replaydata,
              krb5_address *local_addr, krb5_address *remote_addr,
              krb5_data *cstate, krb5_data *outbuf)
{
    krb5_enctype        enctype = krb5_k_key_enctype(context, key);
    krb5_error_code     retval;
    krb5_priv           privmsg;
    krb5_priv_enc_part  privmsg_enc_part;
    krb5_data           *scratch1, *scratch2;
    size_t              enclen;

    privmsg.enc_part.kvno = 0;  /* XXX allow user-set? */
    privmsg.enc_part.enctype = enctype;

    privmsg_enc_part.user_data = *userdata;
    privmsg_enc_part.s_address = local_addr;
    privmsg_enc_part.r_address = remote_addr;

    /* We should check too make sure one exists. */
    privmsg_enc_part.timestamp  = replaydata->timestamp;
    privmsg_enc_part.usec       = replaydata->usec;
    privmsg_enc_part.seq_number = replaydata->seq;

    /* start by encoding to-be-encrypted part of the message */
    if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1)))
        return retval;

    /* put together an eblock for this encryption */
    if ((retval = krb5_c_encrypt_length(context, enctype,
                                        scratch1->length, &enclen)))
        goto clean_scratch;

    privmsg.enc_part.ciphertext.length = enclen;
    if (!(privmsg.enc_part.ciphertext.data =
          malloc(privmsg.enc_part.ciphertext.length))) {
        retval = ENOMEM;
        goto clean_scratch;
    }

    if ((retval = krb5_k_encrypt(context, key,
                                 KRB5_KEYUSAGE_KRB_PRIV_ENCPART,
                                 (cstate->length > 0) ? cstate : NULL,
                                 scratch1, &privmsg.enc_part)))
        goto clean_encpart;

    if ((retval = encode_krb5_priv(&privmsg, &scratch2)))
        goto clean_encpart;

    *outbuf = *scratch2;
    free(scratch2);
    retval = 0;

clean_encpart:
    memset(privmsg.enc_part.ciphertext.data, 0,
           privmsg.enc_part.ciphertext.length);
    free(privmsg.enc_part.ciphertext.data);
    privmsg.enc_part.ciphertext.length = 0;
    privmsg.enc_part.ciphertext.data = 0;

clean_scratch:
    memset(scratch1->data, 0, scratch1->length);
    krb5_free_data(context, scratch1);

    return retval;
}
Exemplo n.º 5
0
krb5_error_code
gss_krb5int_make_seal_token_v3 (krb5_context context,
                                krb5_gss_ctx_id_rec *ctx,
                                const gss_buffer_desc * message,
                                gss_buffer_t token,
                                int conf_req_flag, int toktype)
{
    size_t bufsize = 16;
    unsigned char *outbuf = 0;
    krb5_error_code err;
    int key_usage;
    unsigned char acceptor_flag;
    const gss_buffer_desc *message2 = message;
#ifdef CFX_EXERCISE
    size_t rrc;
#endif
    size_t ec;
    unsigned short tok_id;
    krb5_checksum sum;
    krb5_key key;
    krb5_cksumtype cksumtype;

    acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
    key_usage = (toktype == KG_TOK_WRAP_MSG
                 ? (ctx->initiate
                    ? KG_USAGE_INITIATOR_SEAL
                    : KG_USAGE_ACCEPTOR_SEAL)
                 : (ctx->initiate
                    ? KG_USAGE_INITIATOR_SIGN
                    : KG_USAGE_ACCEPTOR_SIGN));
    if (ctx->have_acceptor_subkey) {
        key = ctx->acceptor_subkey;
        cksumtype = ctx->acceptor_subkey_cksumtype;
    } else {
        key = ctx->subkey;
        cksumtype = ctx->cksumtype;
    }
    assert(key != NULL);

#ifdef CFX_EXERCISE
    {
        static int initialized = 0;
        if (!initialized) {
            srand(time(0));
            initialized = 1;
        }
    }
#endif

    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
        krb5_data plain;
        krb5_enc_data cipher;
        size_t ec_max;

        /* 300: Adds some slop.  */
        if (SIZE_MAX - 300 < message->length)
            return ENOMEM;
        ec_max = SIZE_MAX - message->length - 300;
        if (ec_max > 0xffff)
            ec_max = 0xffff;
#ifdef CFX_EXERCISE
        /* For testing only.  For performance, always set ec = 0.  */
        ec = ec_max & rand();
#else
        ec = 0;
#endif
        plain.length = message->length + 16 + ec;
        plain.data = malloc(message->length + 16 + ec);
        if (plain.data == NULL)
            return ENOMEM;

        /* Get size of ciphertext.  */
        bufsize = 16 + krb5_encrypt_size (plain.length, key->keyblock.enctype);
        /* Allocate space for header plus encrypted data.  */
        outbuf = gssalloc_malloc(bufsize);
        if (outbuf == NULL) {
            free(plain.data);
            return ENOMEM;
        }

        /* TOK_ID */
        store_16_be(KG2_TOK_WRAP_MSG, outbuf);
        /* flags */
        outbuf[2] = (acceptor_flag
                     | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
                     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
        /* filler */
        outbuf[3] = 0xff;
        /* EC */
        store_16_be(ec, outbuf+4);
        /* RRC */
        store_16_be(0, outbuf+6);
        store_64_be(ctx->seq_send, outbuf+8);

        memcpy(plain.data, message->value, message->length);
        if (ec != 0)
            memset(plain.data + message->length, 'x', ec);
        memcpy(plain.data + message->length + ec, outbuf, 16);

        cipher.ciphertext.data = (char *)outbuf + 16;
        cipher.ciphertext.length = bufsize - 16;
        cipher.enctype = key->keyblock.enctype;
        err = krb5_k_encrypt(context, key, key_usage, 0, &plain, &cipher);
        zap(plain.data, plain.length);
        free(plain.data);
        plain.data = 0;
        if (err)
            goto error;

        /* Now that we know we're returning a valid token....  */
        ctx->seq_send++;

#ifdef CFX_EXERCISE
        rrc = rand() & 0xffff;
        if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
                                    (bufsize-16) - (rrc % (bufsize - 16))))
            store_16_be(rrc, outbuf+6);
        /* If the rotate fails, don't worry about it.  */
#endif
    } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
        krb5_data plain;
        size_t cksumsize;

        /* Here, message is the application-supplied data; message2 is
           what goes into the output token.  They may be the same, or
           message2 may be empty (for MIC).  */

        tok_id = KG2_TOK_WRAP_MSG;

    wrap_with_checksum:
        plain.length = message->length + 16;
        plain.data = malloc(message->length + 16);
        if (plain.data == NULL)
            return ENOMEM;

        err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
        if (err)
            goto error;

        assert(cksumsize <= 0xffff);

        bufsize = 16 + message2->length + cksumsize;
        outbuf = gssalloc_malloc(bufsize);
        if (outbuf == NULL) {
            free(plain.data);
            plain.data = 0;
            err = ENOMEM;
            goto error;
        }

        /* TOK_ID */
        store_16_be(tok_id, outbuf);
        /* flags */
        outbuf[2] = (acceptor_flag
                     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
        /* filler */
        outbuf[3] = 0xff;
        if (toktype == KG_TOK_WRAP_MSG) {
            /* Use 0 for checksum calculation, substitute
               checksum length later.  */
            /* EC */
            store_16_be(0, outbuf+4);
            /* RRC */
            store_16_be(0, outbuf+6);
        } else {
            /* MIC and DEL store 0xFF in EC and RRC.  */
            store_16_be(0xffff, outbuf+4);
            store_16_be(0xffff, outbuf+6);
        }
        store_64_be(ctx->seq_send, outbuf+8);

        memcpy(plain.data, message->value, message->length);
        memcpy(plain.data + message->length, outbuf, 16);

        /* Fill in the output token -- data contents, if any, and
           space for the checksum.  */
        if (message2->length)
            memcpy(outbuf + 16, message2->value, message2->length);

        sum.contents = outbuf + 16 + message2->length;
        sum.length = cksumsize;

        err = krb5_k_make_checksum(context, cksumtype, key,
                                   key_usage, &plain, &sum);
        zap(plain.data, plain.length);
        free(plain.data);
        plain.data = 0;
        if (err) {
            zap(outbuf,bufsize);
            goto error;
        }
        if (sum.length != cksumsize)
            abort();
        memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
        krb5_free_checksum_contents(context, &sum);
        sum.contents = 0;
        /* Now that we know we're actually generating the token...  */
        ctx->seq_send++;

        if (toktype == KG_TOK_WRAP_MSG) {
#ifdef CFX_EXERCISE
            rrc = rand() & 0xffff;
            /* If the rotate fails, don't worry about it.  */
            if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
                                        (bufsize-16) - (rrc % (bufsize - 16))))
                store_16_be(rrc, outbuf+6);
#endif
            /* Fix up EC field.  */
            store_16_be(cksumsize, outbuf+4);
        } else {
            store_16_be(0xffff, outbuf+6);
        }
    } else if (toktype == KG_TOK_MIC_MSG) {
        tok_id = KG2_TOK_MIC_MSG;
        message2 = &empty_message;
        goto wrap_with_checksum;
    } else if (toktype == KG_TOK_DEL_CTX) {
        tok_id = KG2_TOK_DEL_CTX;
        message = message2 = &empty_message;
        goto wrap_with_checksum;
    } else
        abort();

    token->value = outbuf;
    token->length = bufsize;
    return 0;

error:
    gssalloc_free(outbuf);
    token->value = NULL;
    token->length = 0;
    return err;
}
Exemplo n.º 6
0
int
main ()
{
    krb5_context context = 0;
    krb5_data  in, in2, out, out2, check, check2, state, signdata;
    krb5_crypto_iov iov[5];
    int i, j, pos;
    unsigned int dummy;
    size_t len;
    krb5_enc_data enc_out, enc_out2;
    krb5_keyblock *keyblock;
    krb5_key key;

    memset(iov, 0, sizeof(iov));

    in.data = "This is a test.\n";
    in.length = strlen (in.data);
    in2.data = "This is another test.\n";
    in2.length = strlen (in2.data);

    test ("Seeding random number generator",
          krb5_c_random_seed (context, &in));

    /* Set up output buffers. */
    out.data = malloc(2048);
    out2.data = malloc(2048);
    check.data = malloc(2048);
    check2.data = malloc(2048);
    if (out.data == NULL || out2.data == NULL
        || check.data == NULL || check2.data == NULL)
        abort();
    out.magic = KV5M_DATA;
    out.length = 2048;
    out2.magic = KV5M_DATA;
    out2.length = 2048;
    check.length = 2048;
    check2.length = 2048;

    for (i = 0; interesting_enctypes[i]; i++) {
        krb5_enctype enctype = interesting_enctypes [i];

        printf ("Testing enctype %d\n", enctype);
        test ("Initializing a keyblock",
              krb5_init_keyblock (context, enctype, 0, &keyblock));
        test ("Generating random keyblock",
              krb5_c_make_random_key (context, enctype, keyblock));
        test ("Creating opaque key from keyblock",
              krb5_k_create_key (context, keyblock, &key));

        enc_out.ciphertext = out;
        enc_out2.ciphertext = out2;
        /* We use an intermediate `len' because size_t may be different size
           than `int' */
        krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
        enc_out.ciphertext.length = len;

        /* Encrypt, decrypt, and see if we got the plaintext back again. */
        test ("Encrypting (c)",
              krb5_c_encrypt (context, keyblock, 7, 0, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Decrypting",
              krb5_c_decrypt (context, keyblock, 7, 0, &enc_out, &check));
        test ("Comparing", compare_results (&in, &check));

        /* Try again with the opaque-key-using variants. */
        memset(out.data, 0, out.length);
        test ("Encrypting (k)",
              krb5_k_encrypt (context, key, 7, 0, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Decrypting",
              krb5_k_decrypt (context, key, 7, 0, &enc_out, &check));
        test ("Comparing", compare_results (&in, &check));

        /* Check if this enctype supports IOV encryption. */
        if ( krb5_c_crypto_length(context, keyblock->enctype,
                                  KRB5_CRYPTO_TYPE_HEADER, &dummy) == 0 ){
            /* Set up iovecs for stream decryption. */
            memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
            iov[0].flags= KRB5_CRYPTO_TYPE_STREAM;
            iov[0].data.data = out2.data;
            iov[0].data.length = enc_out.ciphertext.length;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;

            /* Decrypt the encrypted data from above and check it. */
            test("IOV stream decrypting (c)",
                 krb5_c_decrypt_iov( context, keyblock, 7, 0, iov, 2));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Try again with the opaque-key-using variant. */
            memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
            test("IOV stream decrypting (k)",
                 krb5_k_decrypt_iov( context, key, 7, 0, iov, 2));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Set up iovecs for AEAD encryption. */
            signdata.magic = KV5M_DATA;
            signdata.data = (char *) "This should be signed";
            signdata.length = strlen(signdata.data);
            iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
            iov[1].data = in; /*We'll need to copy memory before encrypt*/
            iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
            iov[2].data = signdata;
            iov[3].flags = KRB5_CRYPTO_TYPE_PADDING;
            iov[4].flags = KRB5_CRYPTO_TYPE_TRAILER;

            /* "Allocate" data for the iovec buffers from the "out" buffer. */
            test("Setting up iov lengths",
                 krb5_c_crypto_length_iov(context, keyblock->enctype, iov, 5));
            for (j=0,pos=0; j <= 4; j++ ){
                if (iov[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
                    continue;
                iov[j].data.data = &out.data[pos];
                pos += iov[j].data.length;
            }
            assert (iov[1].data.length == in.length);
            memcpy(iov[1].data.data, in.data, in.length);

            /* Encrypt and decrypt in place, and check the result. */
            test("iov encrypting (c)",
                 krb5_c_encrypt_iov(context, keyblock, 7, 0, iov, 5));
            assert(iov[1].data.length == in.length);
            display("Header", &iov[0].data);
            display("Data", &iov[1].data);
            display("Padding", &iov[3].data);
            display("Trailer", &iov[4].data);
            test("iov decrypting",
                 krb5_c_decrypt_iov(context, keyblock, 7, 0, iov, 5));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Try again with opaque-key-using variants. */
            test("iov encrypting (k)",
                 krb5_k_encrypt_iov(context, key, 7, 0, iov, 5));
            assert(iov[1].data.length == in.length);
            display("Header", &iov[0].data);
            display("Data", &iov[1].data);
            display("Padding", &iov[3].data);
            display("Trailer", &iov[4].data);
            test("iov decrypting",
                 krb5_k_decrypt_iov(context, key, 7, 0, iov, 5));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));
        }

        enc_out.ciphertext.length = out.length;
        check.length = 2048;

        test ("init_state",
              krb5_c_init_state (context, keyblock, 7, &state));
        test ("Encrypting with state",
              krb5_c_encrypt (context, keyblock, 7, &state, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Encrypting again with state",
              krb5_c_encrypt (context, keyblock, 7, &state, &in2, &enc_out2));
        display ("Enc output", &enc_out2.ciphertext);
        test ("free_state",
              krb5_c_free_state (context, keyblock, &state));
        test ("init_state",
              krb5_c_init_state (context, keyblock, 7, &state));
        test ("Decrypting with state",
              krb5_c_decrypt (context, keyblock, 7, &state, &enc_out, &check));
        test ("Decrypting again with state",
              krb5_c_decrypt (context, keyblock, 7, &state, &enc_out2, &check2));
        test ("free_state",
              krb5_c_free_state (context, keyblock, &state));
        test ("Comparing",
              compare_results (&in, &check));
        test ("Comparing",
              compare_results (&in2, &check2));

        krb5_free_keyblock (context, keyblock);
        krb5_k_free_key (context, key);
    }

    /* Test the RC4 decrypt fallback from key usage 9 to 8. */
    test ("Initializing an RC4 keyblock",
          krb5_init_keyblock (context, ENCTYPE_ARCFOUR_HMAC, 0, &keyblock));
    test ("Generating random RC4 key",
          krb5_c_make_random_key (context, ENCTYPE_ARCFOUR_HMAC, keyblock));
    enc_out.ciphertext = out;
    krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
    enc_out.ciphertext.length = len;
    check.length = 2048;
    test ("Encrypting with RC4 key usage 8",
          krb5_c_encrypt (context, keyblock, 8, 0, &in, &enc_out));
    display ("Enc output", &enc_out.ciphertext);
    test ("Decrypting with RC4 key usage 9",
          krb5_c_decrypt (context, keyblock, 9, 0, &enc_out, &check));
    test ("Comparing", compare_results (&in, &check));

    krb5_free_keyblock (context, keyblock);
    free(out.data);
    free(out2.data);
    free(check.data);
    free(check2.data);
    return 0;
}