Exemple #1
0
/* Derive a usage key from a session key and krb5 usage constant. */
static krb5_error_code
usage_key(const struct krb5_enc_provider *enc,
          const struct krb5_hash_provider *hash,
          const krb5_keyblock *session_keyblock, krb5_keyusage usage,
          krb5_keyblock *out)
{
    char salt_buf[14];
    unsigned int salt_len;
    krb5_data out_data = make_data(out->contents, out->length);
    krb5_crypto_iov iov;
    krb5_keyusage ms_usage;

    /* Generate the salt. */
    ms_usage = krb5int_arcfour_translate_usage(usage);
    if (session_keyblock->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
        memcpy(salt_buf, l40, 10);
        store_32_le(ms_usage, salt_buf + 10);
        salt_len = 14;
    } else {
        store_32_le(ms_usage, salt_buf);
        salt_len = 4;
    }

    /* Compute HMAC(key, salt) to produce the usage key. */
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = make_data(salt_buf, salt_len);
    return krb5int_hmac_keyblock(hash, session_keyblock, &iov, 1, &out_data);
}
Exemple #2
0
krb5_error_code krb5int_hmacmd5_checksum(const struct krb5_cksumtypes *ctp,
                                         krb5_key key, krb5_keyusage usage,
                                         const krb5_crypto_iov *data,
                                         size_t num_data,
                                         krb5_data *output)
{
    krb5_keyusage ms_usage;
    krb5_error_code ret;
    krb5_keyblock ks, *keyblock;
    krb5_crypto_iov *hash_iov = NULL, iov;
    krb5_data ds = empty_data(), hashval = empty_data();
    char t[4];

    if (key == NULL || key->keyblock.length > ctp->hash->blocksize)
        return KRB5_BAD_ENCTYPE;
    if (ctp->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR) {
        /* Compute HMAC(key, "signaturekey\0") to get the signing key ks. */
        ret = alloc_data(&ds, ctp->hash->hashsize);
        if (ret != 0)
            goto cleanup;

        iov.flags = KRB5_CRYPTO_TYPE_DATA;
        iov.data = make_data("signaturekey", 13);
        ret = krb5int_hmac(ctp->hash, key, &iov, 1, &ds);
        if (ret)
            goto cleanup;
        ks.length = key->keyblock.length;
        ks.contents = (krb5_octet *) ds.data;
        keyblock = &ks;
    } else  /* For md5-hmac, just use the key. */
        keyblock = &key->keyblock;

    /* Compute the MD5 value of the input. */
    ms_usage = krb5int_arcfour_translate_usage(usage);
    store_32_le(ms_usage, t);
    hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret);
    if (hash_iov == NULL)
        goto cleanup;
    hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    hash_iov[0].data = make_data(t, 4);
    memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov));
    ret = alloc_data(&hashval, ctp->hash->hashsize);
    if (ret != 0)
        goto cleanup;
    ret = ctp->hash->hash(hash_iov, num_data + 1, &hashval);
    if (ret != 0)
        goto cleanup;

    /* Compute HMAC(ks, md5value). */
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = hashval;
    ret = krb5int_hmac_keyblock(ctp->hash, keyblock, &iov, 1, output);

cleanup:
    zapfree(ds.data, ds.length);
    zapfree(hashval.data, hashval.length);
    free(hash_iov);
    return ret;
}
Exemple #3
0
krb5_error_code
krb5_make_fulladdr(krb5_context context, krb5_address *kaddr,
                   krb5_address *kport, krb5_address *raddr)
{
    register krb5_octet * marshal;
    krb5_int32 tmp32;
    krb5_int16 tmp16;

    if (kaddr == NULL || kport == NULL)
        return EINVAL;

    raddr->length = kaddr->length + kport->length + (4 * sizeof(krb5_int32));
    if (!(raddr->contents = (krb5_octet *)malloc(raddr->length)))
        return ENOMEM;

    raddr->addrtype = ADDRTYPE_ADDRPORT;
    marshal = raddr->contents;

    tmp16 = kaddr->addrtype;
    *marshal++ = 0x00;
    *marshal++ = 0x00;
    store_16_le(tmp16, marshal);
    marshal += 2;

    tmp32 = kaddr->length;
    store_32_le(tmp32, marshal);
    marshal += 4;

    (void) memcpy(marshal, kaddr->contents, kaddr->length);
    marshal += kaddr->length;

    tmp16 = kport->addrtype;
    *marshal++ = 0x00;
    *marshal++ = 0x00;
    store_16_le(tmp16, marshal);
    marshal += 2;

    tmp32 = kport->length;
    store_32_le(tmp32, marshal);
    marshal += 4;

    (void) memcpy(marshal, kport->contents, kport->length);
    marshal += kport->length;
    return 0;
}
Exemple #4
0
/* in-place encoding of PAC header */
static krb5_error_code
k5_pac_encode_header(krb5_context context, krb5_pac pac)
{
    size_t i;
    unsigned char *p;
    size_t header_len;

    header_len = PACTYPE_LENGTH +
        (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
    assert(pac->data.length >= header_len);

    p = (unsigned char *)pac->data.data;

    store_32_le(pac->pac->cBuffers, p);
    p += 4;
    store_32_le(pac->pac->Version, p);
    p += 4;

    for (i = 0; i < pac->pac->cBuffers; i++) {
        PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];

        store_32_le(buffer->ulType, p);
        p += 4;
        store_32_le(buffer->cbBufferSize, p);
        p += 4;
        store_64_le(buffer->Offset, p);
        p += 8;

        assert((buffer->Offset % PAC_ALIGNMENT) == 0);
        assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
        assert(buffer->Offset >= header_len);

        if (buffer->Offset % PAC_ALIGNMENT ||
            buffer->Offset + buffer->cbBufferSize > pac->data.length ||
            buffer->Offset < header_len)
            return ERANGE;
    }

    return 0;
}
Exemple #5
0
static krb5_error_code
k5_insert_checksum(krb5_context context,
                   krb5_pac pac,
                   krb5_ui_4 type,
                   const krb5_keyblock *key,
                   krb5_cksumtype *cksumtype)
{
    krb5_error_code ret;
    size_t len;
    krb5_data cksumdata;

    ret = krb5int_c_mandatory_cksumtype(context, key->enctype, cksumtype);
    if (ret != 0)
        return ret;

    ret = krb5_c_checksum_length(context, *cksumtype, &len);
    if (ret != 0)
        return ret;

    ret = k5_pac_locate_buffer(context, pac, type, &cksumdata);
    if (ret == 0) {
        /*
         * If we're resigning PAC, make sure we can fit checksum
         * into existing buffer
         */
        if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len)
            return ERANGE;

        memset(cksumdata.data, 0, cksumdata.length);
    } else {
        /* Add a zero filled buffer */
        cksumdata.length = PAC_SIGNATURE_DATA_LENGTH + len;
        cksumdata.data = NULL;

        ret = k5_pac_add_buffer(context, pac,
                                type, &cksumdata,
                                TRUE, &cksumdata);
        if (ret != 0)
            return ret;
    }

    /* Encode checksum type into buffer */
    store_32_le((krb5_ui_4)*cksumtype, cksumdata.data);

    return 0;
}
Exemple #6
0
int main ()
{
    /* Test some low-level assumptions the Kerberos code depends
       on.  */

    union {
        uint64_t n64;
        uint32_t n32;
        uint16_t n16;
        unsigned char b[9];
    } u;
    static unsigned char buf[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };

    assert(load_64_be(buf+1) == 0x0102030405060708LL);
    assert(load_64_le(buf+1) == 0x0807060504030201LL);
    assert(load_32_le(buf+2) == 0x05040302);
    assert(load_32_be(buf+2) == 0x02030405);
    assert(load_16_be(buf+3) == 0x0304);
    assert(load_16_le(buf+3) == 0x0403);
    u.b[0] = 0;
    assert((store_64_be(0x0102030405060708LL, u.b+1), !memcmp(buf, u.b, 9)));
    u.b[1] = 9;
    assert((store_64_le(0x0807060504030201LL, u.b+1), !memcmp(buf, u.b, 9)));
    u.b[2] = 10;
    assert((store_32_be(0x02030405, u.b+2), !memcmp(buf, u.b, 9)));
    u.b[3] = 11;
    assert((store_32_le(0x05040302, u.b+2), !memcmp(buf, u.b, 9)));
    u.b[4] = 12;
    assert((store_16_be(0x0304, u.b+3), !memcmp(buf, u.b, 9)));
    u.b[4] = 13;
    assert((store_16_le(0x0403, u.b+3), !memcmp(buf, u.b, 9)));
    /* Verify that load_*_n properly does native format.  Assume
       the unaligned thing is okay.  */
    u.n64 = 0x090a0b0c0d0e0f00LL;
    assert(load_64_n((unsigned char *) &u.n64) == 0x090a0b0c0d0e0f00LL);
    u.n32 = 0x06070809;
    assert(load_32_n((unsigned char *) &u.n32) == 0x06070809);
    u.n16 = 0x0a0b;
    assert(load_16_n((unsigned char *) &u.n16) == 0x0a0b);

    return 0;
}
Exemple #7
0
static  krb5_error_code
k5_md5_hmac_hash (const krb5_keyblock *key, krb5_keyusage usage,
		  const krb5_data *iv,
		  const krb5_data *input, krb5_data *output)
{
  krb5_keyusage ms_usage;
  krb5_MD5_CTX ctx;
  unsigned char t[4];
  krb5_data ds;

  krb5_MD5Init(&ctx);

  ms_usage = krb5int_arcfour_translate_usage (usage);
  store_32_le(ms_usage, t);
  krb5_MD5Update(&ctx, t, sizeof(t));
  krb5_MD5Update(&ctx, (unsigned char *)input->data, input->length);
  krb5_MD5Final(&ctx);

  ds.magic = KV5M_DATA;
  ds.length = 16;
  ds.data = (char *)ctx.digest;

  return krb5_hmac ( &krb5int_hash_md5, key, 1, &ds, output);
}
static krb5_error_code
krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead,
			    const struct krb5_enc_provider *enc,
			    const struct krb5_hash_provider *hash,
			    const krb5_keyblock *key,
			    krb5_keyusage usage,
			    const krb5_data *ivec,
			    krb5_crypto_iov *data,
			    size_t num_data)
{
    krb5_error_code ret;
    krb5_crypto_iov *header, *trailer;
    krb5_keyblock k1, k2, k3;
    krb5_data d1, d2, d3;
    krb5_data checksum, confounder, header_data;
    krb5_keyusage ms_usage;
    char salt_data[14];
    krb5_data salt;
    size_t i;

    d1.length = d2.length = d3.length = 0;
    d1.data = d2.data = d3.data = NULL;

    /*
     * Caller must have provided space for the header, padding
     * and trailer; per RFC 4757 we will arrange it as:
     *
     *	    Checksum | E(Confounder | Plaintext)
     */

    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
    if (header == NULL ||
	header->data.length < hash->hashsize + CONFOUNDERLENGTH)
	return KRB5_BAD_MSIZE;

    header_data = header->data;

    /* Trailer may be absent */
    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
    if (trailer != NULL)
	trailer->data.length = 0;

    /* Ensure that there is no padding */
    for (i = 0; i < num_data; i++) {
	if (data[i].flags == KRB5_CRYPTO_TYPE_PADDING)
	    data[i].data.length = 0;
    }

    ret = alloc_derived_key(enc, &k1, &d1, key);
    if (ret != 0)
	goto cleanup;

    ret = alloc_derived_key(enc, &k2, &d2, key);
    if (ret != 0)
	goto cleanup;

    ret = alloc_derived_key(enc, &k3, &d3, key);
    if (ret != 0)
	goto cleanup;

    /* Begin the encryption, compute K1 */
    salt.data = salt_data;
    salt.length = sizeof(salt_data);

    ms_usage = krb5int_arcfour_translate_usage(usage);

    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
	strncpy(salt.data, krb5int_arcfour_l40, salt.length);
	store_32_le(ms_usage, salt.data + 10);
    } else {
	salt.length = 4;
	store_32_le(ms_usage, salt.data);
    }
    ret = krb5_hmac(hash, key, 1, &salt, &d1);
    if (ret != 0)
	goto cleanup;

    memcpy(k2.contents, k1.contents, k2.length);

    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
	memset(k1.contents + 7, 0xAB, 9);

    header->data.length = hash->hashsize + CONFOUNDERLENGTH;

    confounder.data = header->data.data + hash->hashsize;
    confounder.length = CONFOUNDERLENGTH;

    ret = krb5_c_random_make_octets(0, &confounder);
    if (ret != 0)
	goto cleanup;

    checksum.data = header->data.data;
    checksum.length = hash->hashsize;

    /* Adjust pointers so confounder is at start of header */
    header->data.length -= hash->hashsize;
    header->data.data   += hash->hashsize;

    ret = krb5int_hmac_iov(hash, &k2, data, num_data, &checksum);
    if (ret != 0)
	goto cleanup;

    ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
    if (ret != 0)
	goto cleanup;

    ret = enc->encrypt_iov(&k3, ivec, data, num_data);
    if (ret != 0)
	goto cleanup;

cleanup:
    header->data = header_data; /* restore header pointers */

    if (d1.data != NULL) {
	memset(d1.data, 0, d1.length);
	free(d1.data);
    }
    if (d2.data != NULL) {
	memset(d2.data, 0, d2.length);
	free(d2.data);
    }
    if (d3.data != NULL) {
	memset(d3.data, 0, d3.length);
	free(d3.data);
    }

    return ret;
}
static krb5_error_code
krb5int_arcfour_decrypt_iov(const struct krb5_aead_provider *aead,
			    const struct krb5_enc_provider *enc,
			    const struct krb5_hash_provider *hash,
			    const krb5_keyblock *key,
			    krb5_keyusage usage,
			    const krb5_data *ivec,
			    krb5_crypto_iov *data,
			    size_t num_data)
{
    krb5_error_code ret;
    krb5_crypto_iov *header, *trailer;
    krb5_keyblock k1, k2, k3;
    krb5_data d1, d2, d3;
    krb5_data checksum, header_data;
    krb5_keyusage ms_usage;
    char salt_data[14];
    krb5_data salt;

    d1.length = d2.length = d3.length = 0;
    d1.data = d2.data = d3.data = NULL;

    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
    if (header == NULL ||
        header->data.length != hash->hashsize + CONFOUNDERLENGTH)
	return KRB5_BAD_MSIZE;

    header_data = header->data;

    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
    if (trailer != NULL && trailer->data.length != 0)
	return KRB5_BAD_MSIZE;

    ret = alloc_derived_key(enc, &k1, &d1, key);
    if (ret != 0)
	goto cleanup;

    ret = alloc_derived_key(enc, &k2, &d2, key);
    if (ret != 0)
	goto cleanup;

    ret = alloc_derived_key(enc, &k3, &d3, key);
    if (ret != 0)
	goto cleanup;

    /* Begin the decryption, compute K1 */
    salt.data = salt_data;
    salt.length = sizeof(salt_data);

    ms_usage = krb5int_arcfour_translate_usage(usage);

    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
	strncpy(salt.data, krb5int_arcfour_l40, salt.length);
	store_32_le(ms_usage, (unsigned char *)salt.data + 10);
    } else {
	salt.length = 4;
	store_32_le(ms_usage, (unsigned char *)salt.data);
    }
    ret = krb5_hmac(hash, key, 1, &salt, &d1);
    if (ret != 0)
	goto cleanup;

    memcpy(k2.contents, k1.contents, k2.length);

    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
	memset(k1.contents + 7, 0xAB, 9);

    checksum.data = header->data.data;
    checksum.length = hash->hashsize;

    /* Adjust pointers so confounder is at start of header */
    header->data.length -= hash->hashsize;
    header->data.data   += hash->hashsize;

    ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
    if (ret != 0)
	goto cleanup;

    ret = enc->decrypt_iov(&k3, ivec, data, num_data);
    if (ret != 0)
	goto cleanup;

    ret = krb5int_hmac_iov(hash, &k2, data, num_data, &d1);
    if (ret != 0)
	goto cleanup;

    if (memcmp(checksum.data, d1.data, hash->hashsize) != 0) {
	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	goto cleanup;
    }

cleanup:
    header->data = header_data; /* restore header pointers */

    if (d1.data != NULL) {
	memset(d1.data, 0, d1.length);
	free(d1.data);
    }
    if (d2.data != NULL) {
	memset(d2.data, 0, d2.length);
	free(d2.data);
    }
    if (d3.data != NULL) {
	memset(d3.data, 0, d3.length);
	free(d3.data);
    }

    return ret;
}