krb5_error_code KRB5_CALLCONV krb5_init_random_key(krb5_context context, const krb5_encrypt_block *eblock, const krb5_keyblock *keyblock, krb5_pointer *ptr) { krb5_data data; data.length = keyblock->length; data.data = (char *) keyblock->contents; return(krb5_c_random_seed(context, &data)); }
int main(int argc, char **argv) { int i; krb5_data notrandom; notrandom.data = "notrandom"; notrandom.length = 9; krb5_c_random_seed(NULL, ¬random); for (i = 0; interesting_enctypes[i]; i++) test_enctype(interesting_enctypes[i]); return 0; }
krb5_error_code KRB5_CALLCONV krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds) { krb5_octet result; krb5_creds creds; krb5_creds * credsp = NULL; krb5_creds * credspout = NULL; krb5_error_code retval = 0; krb5_data inbuf, outbuf; int len; krb5_ccache use_ccache = 0; if (error) *error = 0; /* * First, send over the length of the sendauth version string; * then, we send over the sendauth version. Next, we send * over the length of the application version strings followed * by the string itself. */ outbuf.length = strlen(sendauth_version) + 1; outbuf.data = (char *) sendauth_version; if ((retval = krb5_write_message(context, fd, &outbuf))) return(retval); outbuf.length = strlen(appl_version) + 1; outbuf.data = appl_version; if ((retval = krb5_write_message(context, fd, &outbuf))) return(retval); /* * Now, read back a byte: 0 means no error, 1 means bad sendauth * version, 2 means bad application version */ len = krb5_net_read(context, *((int *) fd), (char *)&result, 1); if (len != 1) return((len < 0) ? errno : ECONNABORTED); if (result == 1) return(KRB5_SENDAUTH_BADAUTHVERS); else if (result == 2) return(KRB5_SENDAUTH_BADAPPLVERS); else if (result != 0) return(KRB5_SENDAUTH_BADRESPONSE); /* * We're finished with the initial negotiations; let's get and * send over the authentication header. (The AP_REQ message) */ /* * If no credentials were provided, try getting it from the * credentials cache. */ memset((char *)&creds, 0, sizeof(creds)); /* * See if we need to access the credentials cache */ if (!in_creds || !in_creds->ticket.length) { if (ccache) use_ccache = ccache; /* Solaris Kerberos */ else if ((retval = krb5int_cc_default(context, &use_ccache)) != 0) goto error_return; } if (!in_creds) { if ((retval = krb5_copy_principal(context, server, &creds.server))) goto error_return; if (client) retval = krb5_copy_principal(context, client, &creds.client); else retval = krb5_cc_get_principal(context, use_ccache, &creds.client); if (retval) { krb5_free_principal(context, creds.server); goto error_return; } /* creds.times.endtime = 0; -- memset 0 takes care of this zero means "as long as possible" */ /* creds.keyblock.enctype = 0; -- as well as this. zero means no session enctype preference */ in_creds = &creds; } if (!in_creds->ticket.length) { /* Solaris Kerberos */ if ((retval = krb5_get_credentials(context, 0, use_ccache, in_creds, &credsp)) != 0) goto error_return; credspout = credsp; } else { credsp = in_creds; } if (ap_req_options & AP_OPTS_USE_SUBKEY) { /* Provide some more fodder for random number code. This isn't strong cryptographically; the point here is not to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ char rnd_data[1024]; GETPEERNAME_ARG3_TYPE len2; krb5_data d; d.length = sizeof (rnd_data); d.data = rnd_data; len2 = sizeof (rnd_data); if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, &len2) == 0) { d.length = len2; /* Solaris Kerberos */ (void) krb5_c_random_seed (context, &d); } len2 = sizeof (rnd_data); if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, &len2) == 0) { d.length = len2; /* Solaris Kerberos */ (void) krb5_c_random_seed (context, &d); } } /* Solaris Kerberos */ if ((retval = krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, credsp, &outbuf)) != 0) goto error_return; /* * First write the length of the AP_REQ message, then write * the message itself. */ retval = krb5_write_message(context, fd, &outbuf); free(outbuf.data); if (retval) goto error_return; /* * Now, read back a message. If it was a null message (the * length was zero) then there was no error. If not, we the * authentication was rejected, and we need to return the * error structure. */ /* Solaris Kerberos */ if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) goto error_return; if (inbuf.length) { if (error) { /* Solaris Kerberos */ if ((retval = krb5_rd_error(context, &inbuf, error)) != 0) { krb5_xfree(inbuf.data); goto error_return; } } retval = KRB5_SENDAUTH_REJECTED; krb5_xfree(inbuf.data); goto error_return; } /* * If we asked for mutual authentication, we should now get a * length field, followed by a AP_REP message */ if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) { krb5_ap_rep_enc_part *repl = 0; /* Solaris Kerberos */ if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) goto error_return; /* Solaris Kerberos */ if ((retval = krb5_rd_rep(context, *auth_context, &inbuf, &repl)) != 0) { if (repl) krb5_free_ap_rep_enc_part(context, repl); krb5_xfree(inbuf.data); goto error_return; } krb5_xfree(inbuf.data); /* * If the user wants to look at the AP_REP message, * copy it for them. */ if (rep_result) *rep_result = repl; else krb5_free_ap_rep_enc_part(context, repl); } retval = 0; /* Normal return */ if (out_creds) { *out_creds = credsp; credspout = NULL; } error_return: krb5_free_cred_contents(context, &creds); if (credspout != NULL) krb5_free_creds(context, credspout); /* Solaris Kerberos */ if (!ccache && use_ccache) (void) krb5_cc_close(context, use_ccache); return(retval); }
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; }
static krb5_error_code init_common (krb5_context *context, krb5_boolean secure, krb5_boolean kdc) { krb5_context ctx = 0; krb5_error_code retval; #ifndef _KERNEL struct { krb5_int32 now, now_usec; long pid; } seed_data; krb5_data seed; int tmp; /* Solaris Kerberos */ #if 0 /* Verify some assumptions. If the assumptions hold and the compiler is optimizing, this should result in no code being executed. If we're guessing "unsigned long long" instead of using uint64_t, the possibility does exist that we're wrong. */ { krb5_ui_8 i64; assert(sizeof(i64) == 8); i64 = 0, i64--, i64 >>= 62; assert(i64 == 3); i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1; assert(i64 != 0); i64 <<= 1; assert(i64 == 0); } #endif retval = krb5int_initialize_library(); if (retval) return retval; #endif #if (defined(_WIN32)) /* * Load the krbcc32.dll if necessary. We do this here so that * we know to use API: later on during initialization. * The context being NULL is ok. */ krb5_win_ccdll_load(ctx); /* * krb5_vercheck() is defined in win_glue.c, and this is * where we handle the timebomb and version server checks. */ retval = krb5_vercheck(); if (retval) return retval; #endif *context = 0; ctx = MALLOC(sizeof(struct _krb5_context)); if (!ctx) return ENOMEM; (void) memset(ctx, 0, sizeof(struct _krb5_context)); ctx->magic = KV5M_CONTEXT; ctx->profile_secure = secure; if ((retval = krb5_os_init_context(ctx, kdc))) goto cleanup; /* * Initialize the EF handle, its needed before doing * the random seed. */ if ((retval = krb5_init_ef_handle(ctx))) goto cleanup; #ifndef _KERNEL /* fork safety: set pid to current process ID for later checking */ ctx->pid = __krb5_current_pid; /* Set the default encryption types, possible defined in krb5/conf */ if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL))) goto cleanup; if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL))) goto cleanup; if (ctx->tgs_ktype_count != 0) { ctx->conf_tgs_ktypes = MALLOC(ctx->tgs_ktype_count * sizeof(krb5_enctype)); if (ctx->conf_tgs_ktypes == NULL) goto cleanup; (void) memcpy(ctx->conf_tgs_ktypes, ctx->tgs_ktypes, sizeof(krb5_enctype) * ctx->tgs_ktype_count); } ctx->conf_tgs_ktypes_count = ctx->tgs_ktype_count; /* initialize the prng (not well, but passable) */ if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec))) goto cleanup; seed_data.pid = getpid (); seed.length = sizeof(seed_data); seed.data = (char *) &seed_data; if ((retval = krb5_c_random_seed(ctx, &seed))) /* * Solaris Kerberos: we use /dev/urandom, which is * automatically seeded, so its OK if this fails. */ retval = 0; ctx->default_realm = 0; profile_get_integer(ctx->profile, "libdefaults", "clockskew", 0, 5 * 60, &tmp); ctx->clockskew = tmp; #if 0 /* Default ticket lifetime is currently not supported */ profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime", 0, 10 * 60 * 60, &tmp); ctx->tkt_lifetime = tmp; #endif /* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2) */ /* DCE add kdc_req_checksum_type = 2 to krb5.conf */ profile_get_integer(ctx->profile, "libdefaults", "kdc_req_checksum_type", 0, CKSUMTYPE_RSA_MD5, &tmp); ctx->kdc_req_sumtype = tmp; profile_get_integer(ctx->profile, "libdefaults", "ap_req_checksum_type", 0, CKSUMTYPE_RSA_MD5, &tmp); ctx->default_ap_req_sumtype = tmp; profile_get_integer(ctx->profile, "libdefaults", "safe_checksum_type", 0, CKSUMTYPE_RSA_MD5_DES, &tmp); ctx->default_safe_sumtype = tmp; profile_get_integer(ctx->profile, "libdefaults", "kdc_default_options", 0, KDC_OPT_RENEWABLE_OK, &tmp); ctx->kdc_default_options = tmp; #define DEFAULT_KDC_TIMESYNC 1 profile_get_integer(ctx->profile, "libdefaults", "kdc_timesync", 0, DEFAULT_KDC_TIMESYNC, &tmp); ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0; /* * We use a default file credentials cache of 3. See * lib/krb5/krb/ccache/file/fcc.h for a description of the * credentials cache types. * * Note: DCE 1.0.3a only supports a cache type of 1 * DCE 1.1 supports a cache type of 2. */ #define DEFAULT_CCACHE_TYPE 4 profile_get_integer(ctx->profile, "libdefaults", "ccache_type", 0, DEFAULT_CCACHE_TYPE, &tmp); ctx->fcc_default_format = tmp + 0x0500; ctx->scc_default_format = tmp + 0x0500; ctx->prompt_types = 0; ctx->use_conf_ktypes = 0; ctx->udp_pref_limit = -1; #endif /* !_KERNEL */ *context = ctx; return 0; cleanup: krb5_free_context(ctx); return retval; }