static int ntlm2_makechal(krb5_context context, struct kcrap_chal_req_data *req, krb5_data *chal, int *errnum, krb5_data *error_data) { int retval; chal->length = 8; chal->data = malloc(chal->length); if (chal->data == 0) { perror("malloc"); *errnum = errno; error_data->data = strdup(error_message(errno)); error_data->length = strlen(error_data->data); return errno; } else { if ((retval = krb5_c_random_make_octets(context, chal))) { *errnum = retval; error_data->data = strdup(error_message(retval)); error_data->length = strlen(error_data->data); free(chal->data); return retval; } } *errnum = 0; return 0; }
static krb5_error_code nonce_generate(krb5_context ctx, unsigned int length, krb5_data *nonce_out) { krb5_data nonce; krb5_error_code retval; krb5_timestamp now; retval = krb5_timeofday(ctx, &now); if (retval != 0) return retval; retval = alloc_data(&nonce, sizeof(now) + length); if (retval != 0) return retval; retval = krb5_c_random_make_octets(ctx, &nonce); if (retval != 0) { free(nonce.data); return retval; } store_32_be(now, nonce.data); *nonce_out = nonce; return 0; }
krb5_error_code krb5int_random_string (krb5_context context, char *string, unsigned int length) { static const unsigned char charlist[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; krb5_error_code err = 0; unsigned char *bytes = NULL; unsigned int bytecount = length - 1; if (!err) { bytes = malloc (bytecount); if (bytes == NULL) { err = ENOMEM; } } if (!err) { krb5_data data; data.length = bytecount; data.data = (char *) bytes; err = krb5_c_random_make_octets (context, &data); } if (!err) { unsigned int i; for (i = 0; i < bytecount; i++) { string [i] = charlist[bytes[i] % (sizeof (charlist) - 1)]; } string[length - 1] = '\0'; } if (bytes != NULL) { free (bytes); } return err; }
static krb5_error_code ipa_get_random_salt(krb5_context krbctx, krb5_data *salt) { krb5_error_code kerr; int i, v; /* make random salt */ salt->length = KRB5P_SALT_SIZE; salt->data = malloc(KRB5P_SALT_SIZE); if (!salt->data) { return ENOMEM; } kerr = krb5_c_random_make_octets(krbctx, salt); if (kerr) { return kerr; } /* Windows treats the salt as a string. * To avoid any compatibility issue, limits octects only to * the ASCII printable range, or 0x20 <= val <= 0x7E */ for (i = 0; i < salt->length; i++) { v = (unsigned char)salt->data[i]; v %= 0x5E; /* 7E - 20 */ v += 0x20; /* add base */ salt->data[i] = v; } return 0; }
krb5_error_code KRB5_CALLCONV krb5_random_confounder(size_t size, krb5_pointer ptr) { krb5_data random_data; random_data.length = size; random_data.data = ptr; return(krb5_c_random_make_octets(/* XXX */ 0, &random_data)); }
krb5_error_code krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { const struct krb5_enc_provider *enc = ktp->enc; krb5_error_code ret; krb5_crypto_iov *header, *trailer, *padding; krb5_data cksum = empty_data(); krb5_key ke = NULL, ki = NULL; /* E(Confounder | Plaintext | Pad) | Checksum */ /* Validate header and trailer lengths, and zero out padding length. */ header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); if (header == NULL || header->data.length < enc->block_size) return KRB5_BAD_MSIZE; trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); if (trailer == NULL || trailer->data.length < enc->block_size) return KRB5_BAD_MSIZE; padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING); if (padding != NULL) padding->data.length = 0; /* Derive the encryption and integrity keys. */ ret = derive_keys(enc, key, usage, &ke, &ki); if (ret != 0) goto cleanup; /* Generate confounder. */ header->data.length = enc->block_size; ret = krb5_c_random_make_octets(NULL, &header->data); if (ret != 0) goto cleanup; /* Checksum the plaintext. */ ret = krb5int_cmac_checksum(enc, ki, data, num_data, &trailer->data); if (ret != 0) goto cleanup; /* Encrypt the plaintext (header | data | padding) */ ret = enc->encrypt(ke, ivec, data, num_data); if (ret != 0) goto cleanup; cleanup: krb5_k_free_key(NULL, ke); krb5_k_free_key(NULL, ki); zapfree(cksum.data, cksum.length); return ret; }
/* Ensure that mcc_hashtab is initialized. Call with krb5int_mcc_mutex * locked. */ static krb5_error_code init_table(krb5_context context) { krb5_error_code ret; uint8_t seed[K5_HASH_SEED_LEN]; krb5_data d = make_data(seed, sizeof(seed)); if (mcc_hashtab != NULL) return 0; ret = krb5_c_random_make_octets(context, &d); if (ret) return ret; return k5_hashtab_create(seed, 64, &mcc_hashtab); }
krb5_error_code kg_make_confounder(krb5_context context, krb5_enctype enctype, unsigned char *buf) { int confsize; krb5_data lrandom; confsize = kg_confounder_size(context, enctype); if (confsize < 0) return KRB5_BAD_MSIZE; lrandom.length = confsize; lrandom.data = (char *)buf; return(krb5_c_random_make_octets(context, &lrandom)); }
krb5_error_code krb5int_confounder_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_error_code ret; krb5_data conf, hashval; krb5_key xorkey = NULL; krb5_crypto_iov *hash_iov, iov; size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize; /* Partition the output buffer into confounder and hash. */ conf = make_data(output->data, blocksize); hashval = make_data(output->data + blocksize, hashsize); /* Create the confounder. */ ret = krb5_c_random_make_octets(NULL, &conf); if (ret != 0) return ret; ret = mk_xorkey(key, &xorkey); if (ret) return ret; /* Hash the confounder, then the input data. */ 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 = conf; memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov)); ret = ctp->hash->hash(hash_iov, num_data + 1, &hashval); if (ret != 0) goto cleanup; /* Confounder and hash are in output buffer; encrypt them in place. */ iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = *output; ret = ctp->enc->encrypt(xorkey, NULL, &iov, 1); cleanup: free(hash_iov); krb5_k_free_key(NULL, xorkey); return ret; }
krb5_error_code krb5_generate_seq_number(krb5_context context, const krb5_keyblock *key, krb5_ui_4 *seqno) { krb5_data seed; krb5_error_code retval; #if 0 /* * Solaris Kerberos: Don't bother with this PRNG stuff, * we have /dev/random and PKCS#11 to handle Random Numbers. */ seed.length = key->length; seed.data = key->contents; if ((retval = krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed))) return(retval); #endif /* 0 */ seed.length = sizeof(*seqno); seed.data = (char *) seqno; retval = krb5_c_random_make_octets(context, &seed); if (retval) return retval; /* * Work around implementation incompatibilities by not generating * initial sequence numbers greater than 2^30. Previous MIT * implementations use signed sequence numbers, so initial * sequence numbers 2^31 to 2^32-1 inclusive will be rejected. * Letting the maximum initial sequence number be 2^30-1 allows * for about 2^30 messages to be sent before wrapping into * "negative" numbers. */ *seqno &= 0x3fffffff; if (*seqno == 0) *seqno = 1; return 0; }
krb5_error_code verify_securid_data_2(krb5_context context, krb5_db_entry *client, krb5_sam_response_2 *sr2, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa, krb5_sam_challenge_2 **sc2_out) { krb5_error_code retval; int new_pin = 0; krb5_key_data *client_key_data = NULL; krb5_keyblock client_key; krb5_data scratch; krb5_enc_sam_response_enc_2 *esre2 = NULL; struct securid_track_data sid_track_data, *trackp = NULL; krb5_data tmp_data; SDI_HANDLE sd_handle = SDI_HANDLE_NONE; krb5_sam_challenge_2 *sc2p = NULL; char *cp, *user = NULL; char *securid_user = NULL; char passcode[LENPRNST+1]; char max_pin_len, min_pin_len, alpha_pin; memset(&client_key, 0, sizeof(client_key)); memset(&scratch, 0, sizeof(scratch)); *sc2_out = NULL; retval = krb5_unparse_name(context, client->princ, &user); if (retval != 0) { com_err("krb5kdc", retval, "while unparsing client name in verify_securid_data_2"); return retval; } if ((sr2->sam_enc_nonce_or_sad.ciphertext.data == NULL) || (sr2->sam_enc_nonce_or_sad.ciphertext.length <= 0)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(context, retval, "No preauth data supplied in " "verify_securid_data_2 (%s)", user); goto cleanup; } retval = krb5_dbe_find_enctype(context, client, sr2->sam_enc_nonce_or_sad.enctype, KRB5_KDB_SALTTYPE_NORMAL, sr2->sam_enc_nonce_or_sad.kvno, &client_key_data); if (retval) { com_err("krb5kdc", retval, "while getting client key in verify_securid_data_2 (%s)", user); goto cleanup; } retval = krb5_dbe_decrypt_key_data(context, NULL, client_key_data, &client_key, NULL); if (retval != 0) { com_err("krb5kdc", retval, "while decrypting client key in verify_securid_data_2 (%s)", user); goto cleanup; } scratch.length = sr2->sam_enc_nonce_or_sad.ciphertext.length; scratch.data = k5alloc(scratch.length, &retval); if (retval) goto cleanup; retval = krb5_c_decrypt(context, &client_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE, 0, &sr2->sam_enc_nonce_or_sad, &scratch); if (retval) { com_err("krb5kdc", retval, "while decrypting SAD in verify_securid_data_2 (%s)", user); goto cleanup; } retval = decode_krb5_enc_sam_response_enc_2(&scratch, &esre2); if (retval) { com_err("krb5kdc", retval, "while decoding SAD in verify_securid_data_2 (%s)", user); esre2 = NULL; goto cleanup; } if (sr2->sam_nonce != esre2->sam_nonce) { com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "while checking nonce in verify_securid_data_2 (%s)", user); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } if (esre2->sam_sad.length == 0 || esre2->sam_sad.data == NULL) { com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "No SecurID passcode in verify_securid_data_2 (%s)", user); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } /* Copy out SAD to null-terminated buffer */ memset(passcode, 0, sizeof(passcode)); if (esre2->sam_sad.length > (sizeof(passcode) - 1)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; com_err("krb5kdc", retval, "SecurID passcode/PIN too long (%d bytes) in " "verify_securid_data_2 (%s)", esre2->sam_sad.length, user); goto cleanup; } memcpy(passcode, esre2->sam_sad.data, esre2->sam_sad.length); securid_user = strdup(user); if (!securid_user) { retval = ENOMEM; com_err("krb5kdc", ENOMEM, "while copying user name in verify_securid_data_2 (%s)", user); goto cleanup; } cp = strchr(securid_user, '@'); if (cp != NULL) *cp = '\0'; /* Check for any track_id data that may have state from a previous attempt * at SecurID authentication. */ if (sr2->sam_track_id.data && (sr2->sam_track_id.length > 0)) { krb5_data track_id_data; memset(&track_id_data, 0, sizeof(track_id_data)); retval = securid_decrypt_track_data_2(context, client, &sr2->sam_track_id, &track_id_data); if (retval) { com_err("krb5kdc", retval, "while decrypting SecurID trackID in " "verify_securid_data_2 (%s)", user); goto cleanup; } if (track_id_data.length < sizeof (struct securid_track_data)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; com_err("krb5kdc", retval, "Length of track data incorrect"); goto cleanup; } trackp = (struct securid_track_data *)track_id_data.data; if(trackp->hostid != gethostid()) { krb5_klog_syslog(LOG_INFO, "Unexpected challenge response"); retval = KRB5KDC_ERR_DISCARD; goto cleanup; } switch(trackp->state) { case SECURID_STATE_INITIAL: goto initial; break; case SECURID_STATE_NEW_PIN_AGAIN: { int pin1_len, pin2_len; trackp->handle = ntohl(trackp->handle); pin2_len = strlen(passcode); pin1_len = strlen(trackp->passcode); if ((pin1_len != pin2_len) || (memcmp(passcode, trackp->passcode, pin1_len) != 0)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "New SecurID PIN Failed for user " "%s: PIN mis-match", user); break; } retval = SD_Pin(trackp->handle, passcode); SD_Close(trackp->handle); if (retval == ACM_NEW_PIN_ACCEPTED) { enc_tkt_reply->flags|= TKT_FLG_HW_AUTH; enc_tkt_reply->flags|= TKT_FLG_PRE_AUTH; krb5_klog_syslog(LOG_INFO, "SecurID PIN Accepted for %s in " "verify_securid_data_2", securid_user); retval = 0; } else { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "SecurID PIN Failed for user %s (AceServer " "returns %d) in verify_securid_data_2", user, retval); } break; } case SECURID_STATE_NEW_PIN: { krb5_sam_challenge_2_body sc2b; sc2p = k5alloc(sizeof *sc2p, &retval); if (retval) goto cleanup; memset(sc2p, 0, sizeof(*sc2p)); memset(&sc2b, 0, sizeof(sc2b)); sc2b.sam_type = PA_SAM_TYPE_SECURID; sc2b.sam_response_prompt.data = NEW_PIN_AGAIN_message; sc2b.sam_response_prompt.length = strlen(sc2b.sam_response_prompt.data); sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD; sc2b.sam_etype = client_key.enctype; tmp_data.data = (char *)&sc2b.sam_nonce; tmp_data.length = sizeof(sc2b.sam_nonce); if ((retval = krb5_c_random_make_octets(context, &tmp_data))) { com_err("krb5kdc", retval, "while making nonce for SecurID new " "PIN2 SAM_CHALLENGE_2 (%s)", user); goto cleanup; } sid_track_data.state = SECURID_STATE_NEW_PIN_AGAIN; sid_track_data.handle = trackp->handle; sid_track_data.hostid = gethostid(); /* Should we complain if sizes don't work ?? */ memcpy(sid_track_data.passcode, passcode, sizeof(sid_track_data.passcode)); tmp_data.data = (char *)&sid_track_data; tmp_data.length = sizeof(sid_track_data); if ((retval = securid_encrypt_track_data_2(context, client, &tmp_data, &sc2b.sam_track_id))) { com_err("krb5kdc", retval, "while encrypting NEW PIN2 SecurID " "track data for SAM_CHALLENGE_2 (%s)", securid_user); goto cleanup; } retval = securid_make_sam_challenge_2_and_cksum(context, sc2p, &sc2b, &client_key); if (retval) { com_err("krb5kdc", retval, "while making cksum for " "SAM_CHALLENGE_2 (new PIN2) (%s)", securid_user); goto cleanup; } krb5_klog_syslog(LOG_INFO, "Requesting verification of new PIN for user %s", securid_user); *sc2_out = sc2p; sc2p = NULL; /*sc2_out may be set even on error path*/ retval = KRB5KDC_ERR_PREAUTH_REQUIRED; goto cleanup; } case SECURID_STATE_NEXT_CODE: trackp->handle = ntohl(trackp->handle); retval = SD_Next(trackp->handle, passcode); SD_Close(trackp->handle); if (retval == ACM_OK) { enc_tkt_reply->flags |= TKT_FLG_HW_AUTH | TKT_FLG_PRE_AUTH; krb5_klog_syslog(LOG_INFO, "Next SecurID Code Accepted for " "user %s", securid_user); retval = 0; } else { krb5_klog_syslog(LOG_INFO, "Next SecurID Code Failed for user " "%s (AceServer returns %d) in " "verify_securid_data_2", user, retval); retval = KRB5KDC_ERR_PREAUTH_FAILED; } break; } } else { /* No track data, this is first of N attempts */ initial: retval = SD_Init(&sd_handle); if (retval) { com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "SD_Init() returns error %d in verify_securid_data_2 (%s)", retval, securid_user); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } retval = SD_Lock(sd_handle, securid_user); if (retval != ACM_OK) { SD_Close(sd_handle); retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "SD_Lock() failed (AceServer returns %d) for %s", retval, securid_user); goto cleanup; } retval = SD_Check(sd_handle, passcode, securid_user); switch (retval) { case ACM_OK: SD_Close(sd_handle); enc_tkt_reply->flags|= TKT_FLG_HW_AUTH; enc_tkt_reply->flags|= TKT_FLG_PRE_AUTH; krb5_klog_syslog(LOG_INFO, "SecurID passcode accepted for user %s", user); retval = 0; break; case ACM_ACCESS_DENIED: SD_Close(sd_handle); retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "AceServer returns Access Denied for " "user %s (SAM2)", user); goto cleanup; case ACM_NEW_PIN_REQUIRED: new_pin = 1; /*fall through*/ case ACM_NEXT_CODE_REQUIRED: { krb5_sam_challenge_2_body sc2b; sc2p = k5alloc(sizeof *sc2p, &retval); if (retval) goto cleanup; memset(sc2p, 0, sizeof(*sc2p)); memset(&sc2b, 0, sizeof(sc2b)); sc2b.sam_type = PA_SAM_TYPE_SECURID; sc2b.sam_response_prompt.data = NEXT_PASSCODE_message; sc2b.sam_response_prompt.length = strlen(sc2b.sam_response_prompt.data); sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD; sc2b.sam_etype = client_key.enctype; if (new_pin) { if ((AceGetMaxPinLen(sd_handle, &max_pin_len) == ACE_SUCCESS) && (AceGetMinPinLen(sd_handle, &min_pin_len) == ACE_SUCCESS) && (AceGetAlphanumeric(sd_handle, &alpha_pin) == ACE_SUCCESS)) { sprintf(PIN_message, "New PIN must contain %d to %d %sdigits", min_pin_len, max_pin_len, (alpha_pin == 0) ? "" : "alphanumeric "); sc2b.sam_challenge_label.data = PIN_message; sc2b.sam_challenge_label.length = strlen(sc2b.sam_challenge_label.data); } else { sc2b.sam_challenge_label.length = 0; } } tmp_data.data = (char *)&sc2b.sam_nonce; tmp_data.length = sizeof(sc2b.sam_nonce); if ((retval = krb5_c_random_make_octets(context, &tmp_data))) { com_err("krb5kdc", retval, "while making nonce for SecurID SAM_CHALLENGE_2 (%s)", user); goto cleanup; } if (new_pin) sid_track_data.state = SECURID_STATE_NEW_PIN; else sid_track_data.state = SECURID_STATE_NEXT_CODE; sid_track_data.handle = htonl(sd_handle); sid_track_data.hostid = gethostid(); tmp_data.data = (char *)&sid_track_data; tmp_data.length = sizeof(sid_track_data); retval = securid_encrypt_track_data_2(context, client, &tmp_data, &sc2b.sam_track_id); if (retval) { com_err("krb5kdc", retval, "while encrypting SecurID track " "data for SAM_CHALLENGE_2 (%s)", securid_user); goto cleanup; } retval = securid_make_sam_challenge_2_and_cksum(context, sc2p, &sc2b, &client_key); if (retval) { com_err("krb5kdc", retval, "while making cksum for SAM_CHALLENGE_2 (%s)", securid_user); } if (new_pin) krb5_klog_syslog(LOG_INFO, "New SecurID PIN required for " "user %s", securid_user); else krb5_klog_syslog(LOG_INFO, "Next SecurID passcode required " "for user %s", securid_user); *sc2_out = sc2p; sc2p = NULL; retval = KRB5KDC_ERR_PREAUTH_REQUIRED; /*sc2_out is permitted as an output on error path*/ goto cleanup; } default: com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "AceServer returns unknown error code %d " "in verify_securid_data_2\n", retval); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } } /* no track_id data */ cleanup: krb5_free_keyblock_contents(context, &client_key); free(scratch.data); krb5_free_enc_sam_response_enc_2(context, esre2); free(user); free(securid_user); free(trackp); krb5_free_sam_challenge_2(context, sc2p); return retval; }
krb5_error_code get_securid_edata_2(krb5_context context, krb5_db_entry *client, krb5_keyblock *client_key, krb5_sam_challenge_2_body *sc2b, krb5_sam_challenge_2 *sc2) { krb5_error_code retval; krb5_data scratch; char *user = NULL; char *def_user = "******"; struct securid_track_data sid_track_data; krb5_data tmp_data; scratch.data = NULL; sc2b->sam_track_id.data = NULL; retval = krb5_unparse_name(context, client->princ, &user); if (retval) goto cleanup; sc2b->sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD; sc2b->sam_type_name.length = 0; sc2b->sam_challenge_label.length = 0; sc2b->sam_challenge.length = 0; sc2b->sam_response_prompt.data = PASSCODE_message; sc2b->sam_response_prompt.length = strlen(sc2b->sam_response_prompt.data); sc2b->sam_pk_for_sad.length = 0; sc2b->sam_type = PA_SAM_TYPE_SECURID; sid_track_data.state = SECURID_STATE_INITIAL; sid_track_data.hostid = gethostid(); tmp_data.data = (char *)&sid_track_data; tmp_data.length = sizeof(sid_track_data); retval = securid_encrypt_track_data_2(context, client, &tmp_data, &sc2b->sam_track_id); if (retval != 0) { com_err("krb5kdc", retval, "while encrypting nonce track data"); goto cleanup; } scratch.data = (char *)&sc2b->sam_nonce; scratch.length = sizeof(sc2b->sam_nonce); retval = krb5_c_random_make_octets(context, &scratch); if (retval) { com_err("krb5kdc", retval, "while generating nonce data in get_securid_edata_2 (%s)", user ? user : def_user); goto cleanup; } /* Get the client's key */ sc2b->sam_etype = client_key->enctype; retval = securid_make_sam_challenge_2_and_cksum(context, sc2, sc2b, client_key); if (retval) { com_err("krb5kdc", retval, "while making SAM_CHALLENGE_2 checksum (%s)", user ? user : def_user); } cleanup: free(user); if (retval) { krb5_free_data_contents(context, &sc2b->sam_track_id); sc2b->sam_track_id.data = NULL; } return retval; }
krb5_error_code krb5int_fast_prep_req(krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_req *request, const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder, krb5_data **encoded_request) { krb5_error_code retval = 0; krb5_pa_data *pa_array[2]; krb5_pa_data pa[2]; krb5_fast_req fast_req; krb5_fast_armored_req *armored_req = NULL; krb5_data *encoded_fast_req = NULL; krb5_data *encoded_armored_req = NULL; krb5_data *local_encoded_result = NULL; krb5_data random_data; char random_buf[4]; assert(state != NULL); assert(state->fast_outer_request.padata == NULL); memset(pa_array, 0, sizeof pa_array); if (state->armor_key == NULL) { return encoder(request, encoded_request); } TRACE_FAST_ENCODE(context); /* Fill in a fresh random nonce for each inner request*/ random_data.length = 4; random_data.data = (char *)random_buf; retval = krb5_c_random_make_octets(context, &random_data); if (retval == 0) { request->nonce = 0x7fffffff & load_32_n(random_buf); state->nonce = request->nonce; } fast_req.req_body = request; if (fast_req.req_body->padata == NULL) { fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *)); if (fast_req.req_body->padata == NULL) retval = ENOMEM; } fast_req.fast_options = state->fast_options; if (retval == 0) retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req); if (retval == 0) { armored_req = calloc(1, sizeof(krb5_fast_armored_req)); if (armored_req == NULL) retval = ENOMEM; } if (retval == 0) armored_req->armor = state->armor; if (retval ==0) retval = krb5_c_make_checksum(context, 0, state->armor_key, KRB5_KEYUSAGE_FAST_REQ_CHKSUM, to_be_checksummed, &armored_req->req_checksum); if (retval == 0) retval = krb5_encrypt_helper(context, state->armor_key, KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req, &armored_req->enc_part); if (retval == 0) retval = encode_krb5_pa_fx_fast_request(armored_req, &encoded_armored_req); if (retval==0) { pa[0].pa_type = KRB5_PADATA_FX_FAST; pa[0].contents = (unsigned char *) encoded_armored_req->data; pa[0].length = encoded_armored_req->length; pa_array[0] = &pa[0]; } state->fast_outer_request.padata = pa_array; if(retval == 0) retval = encoder(&state->fast_outer_request, &local_encoded_result); if (retval == 0) { *encoded_request = local_encoded_result; local_encoded_result = NULL; } if (encoded_armored_req) krb5_free_data(context, encoded_armored_req); if (armored_req) { armored_req->armor = NULL; /*owned by state*/ krb5_free_fast_armored_req(context, armored_req); } if (encoded_fast_req) krb5_free_data(context, encoded_fast_req); if (local_encoded_result) krb5_free_data(context, local_encoded_result); state->fast_outer_request.padata = NULL; return retval; }
/*ARGSUSED*/ static krb5_error_code k5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_data *input, krb5_data *output) { krb5_error_code ret = 0; krb5_data data; unsigned char conf[CONFLENGTH]; krb5_keyblock xorkey; int i; CK_MECHANISM mechanism; CK_RV rv; CK_ULONG hashlen = MD5_CKSUM_LENGTH; if (key->length != 8) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (output->length != (CONFLENGTH+MD5_CKSUM_LENGTH)) return(KRB5_CRYPTO_INTERNAL); /* create the confouder */ data.length = CONFLENGTH; data.data = (char *) conf; if ((ret = krb5_c_random_make_octets(context, &data))) return(ret); xorkey.magic = key->magic; xorkey.enctype = key->enctype; xorkey.length = key->length; xorkey.contents = (krb5_octet *)malloc(key->length); if (xorkey.contents == NULL) return(KRB5_CRYPTO_INTERNAL); (void) memcpy(xorkey.contents, key->contents, xorkey.length); for (i=0; i<xorkey.length; i++) xorkey.contents[i] ^= 0xf0; if (!mit_des_check_key_parity(xorkey.contents)) { ret = KRB5DES_BAD_KEYPAR; goto cleanup; } if (mit_des_is_weak_key(xorkey.contents)) { ret = KRB5DES_WEAK_KEY; goto cleanup; } /* hash the confounder, then the input data */ mechanism.mechanism = CKM_MD5; mechanism.pParameter = NULL_PTR; mechanism.ulParameterLen = 0; if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5des_hash: " "rv = 0x%x.", rv); ret = PKCS_ERR; goto cleanup; } if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)conf, (CK_ULONG)sizeof(conf))) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_hash: " "rv = 0x%x", rv); return(PKCS_ERR); } if ((rv = C_DigestFinal(krb_ctx_hSession(context), (CK_BYTE_PTR)(output->data + CONFLENGTH), (CK_ULONG_PTR)&hashlen)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_hash: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } /* construct the buffer to be encrypted */ (void) memcpy(output->data, conf, CONFLENGTH); /* encrypt it, in place. this has a return value, but it's always zero. */ ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data, (krb5_pointer) output->data, output->length, &xorkey, (unsigned char*) mit_des_zeroblock, 1); cleanup: free(xorkey.contents); return(ret); }
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; }
krb5_error_code krb5int_arcfour_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { const struct krb5_enc_provider *enc = ktp->enc; const struct krb5_hash_provider *hash = ktp->hash; krb5_error_code ret; krb5_crypto_iov *header, *trailer; krb5_keyblock *usage_keyblock = NULL, *enc_keyblock = NULL; krb5_data checksum, confounder, header_data; size_t i; /* * 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 = krb5int_c_init_keyblock(NULL, key->keyblock.enctype, enc->keybytes, &usage_keyblock); if (ret != 0) goto cleanup; ret = krb5int_c_init_keyblock(NULL, key->keyblock.enctype, enc->keybytes, &enc_keyblock); if (ret != 0) goto cleanup; /* Derive a usage key from the session key and usage. */ ret = usage_key(enc, hash, &key->keyblock, usage, usage_keyblock); if (ret != 0) goto cleanup; /* Generate a confounder in the header block, after the checksum. */ header->data.length = hash->hashsize + CONFOUNDERLENGTH; confounder = make_data(header->data.data + hash->hashsize, CONFOUNDERLENGTH); ret = krb5_c_random_make_octets(0, &confounder); if (ret != 0) goto cleanup; checksum = make_data(header->data.data, hash->hashsize); /* Adjust pointers so confounder is at start of header. */ header->data.length -= hash->hashsize; header->data.data += hash->hashsize; /* Compute the checksum using the usage key. */ ret = krb5int_hmac_keyblock(hash, usage_keyblock, data, num_data, &checksum); if (ret != 0) goto cleanup; /* Derive the encryption key from the usage key and checksum. */ ret = enc_key(enc, hash, usage_keyblock, &checksum, enc_keyblock); if (ret) goto cleanup; ret = keyblock_crypt(enc, enc_keyblock, ivec, data, num_data); cleanup: header->data = header_data; /* Restore header pointers. */ krb5int_c_free_keyblock(NULL, usage_keyblock); krb5int_c_free_keyblock(NULL, enc_keyblock); return ret; }
/* Generate size bytes of random data into the buffer. */ static inline krb5_error_code randomize(krb5_context ctx, void *buffer, unsigned int size) { krb5_data rdata = make_data(buffer, size); return krb5_c_random_make_octets(ctx, &rdata); }
krb5_error_code krb5_old_encrypt(const struct krb5_enc_provider *enc, const struct krb5_hash_provider *hash, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_data *input, krb5_data *output) { krb5_error_code ret; size_t blocksize, hashsize, enclen; krb5_data datain, crcivec; int real_ivec; blocksize = enc->block_size; hashsize = hash->hashsize; krb5_old_encrypt_length(enc, hash, input->length, &enclen); if (output->length < enclen) return(KRB5_BAD_MSIZE); output->length = enclen; /* fill in confounded, padded, plaintext buffer with zero checksum */ memset(output->data, 0, output->length); datain.length = blocksize; datain.data = output->data; if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &datain))) return(ret); memcpy(output->data+blocksize+hashsize, input->data, input->length); /* compute the checksum */ datain.length = hashsize; datain.data = output->data+blocksize; if ((ret = ((*(hash->hash))(1, output, &datain)))) goto cleanup; /* encrypt it */ /* XXX this is gross, but I don't have much choice */ if ((key->enctype == ENCTYPE_DES_CBC_CRC) && (ivec == 0)) { crcivec.length = key->length; crcivec.data = (char *) key->contents; ivec = &crcivec; real_ivec = 0; } else real_ivec = 1; if ((ret = ((*(enc->encrypt))(key, ivec, output, output)))) goto cleanup; /* update ivec */ if (real_ivec && ivec != NULL && ivec->length == blocksize) memcpy(ivec->data, output->data + output->length - blocksize, blocksize); cleanup: if (ret) memset(output->data, 0, output->length); return(ret); }
static krb5_error_code k5_md4des_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_data *input, krb5_data *output) { krb5_error_code ret; krb5_data data; krb5_MD4_CTX ctx; unsigned char conf[CONFLENGTH]; unsigned char xorkey[8]; unsigned int i; mit_des_key_schedule schedule; if (key->length != 8) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (output->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH)) return(KRB5_CRYPTO_INTERNAL); /* create the confouder */ data.length = CONFLENGTH; data.data = (char *) conf; if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &data))) return(ret); /* create and schedule the encryption key */ memcpy(xorkey, key->contents, sizeof(xorkey)); for (i=0; i<sizeof(xorkey); i++) xorkey[i] ^= 0xf0; switch (ret = mit_des_key_sched(xorkey, schedule)) { case -1: return(KRB5DES_BAD_KEYPAR); case -2: return(KRB5DES_WEAK_KEY); } /* hash the confounder, then the input data */ krb5_MD4Init(&ctx); krb5_MD4Update(&ctx, conf, CONFLENGTH); krb5_MD4Update(&ctx, (unsigned char *) input->data, (unsigned int) input->length); krb5_MD4Final(&ctx); /* construct the buffer to be encrypted */ memcpy(output->data, conf, CONFLENGTH); memcpy(output->data+CONFLENGTH, ctx.digest, RSA_MD4_CKSUM_LENGTH); /* encrypt it, in place. this has a return value, but it's always zero. */ mit_des_cbc_encrypt((krb5_pointer) output->data, (krb5_pointer) output->data, output->length, schedule, (const unsigned char *) mit_des_zeroblock, 1); return(0); }
/*ARGSUSED*/ static krb5_error_code k5_md5des_hash(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, krb5_const krb5_data *ivec, krb5_const krb5_data *input, krb5_data *output) { krb5_error_code ret = 0; krb5_data data; unsigned char conf[CONFLENGTH]; unsigned char xorkey[MIT_DES_KEYSIZE]; int i; krb5_data *hash_input; char *outptr; krb5_keyblock newkey; if (key->length != MIT_DES_KEYSIZE) return(KRB5_BAD_KEYSIZE); if (ivec) return(KRB5_CRYPTO_INTERNAL); if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) return(KRB5_CRYPTO_INTERNAL); /* create the confounder */ data.length = CONFLENGTH; data.data = (char *) conf; if ((ret = krb5_c_random_make_octets(context, &data))) return(ret); /* hash the confounder, then the input data */ hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2); if (hash_input == NULL) return(KRB5_RC_MALLOC); hash_input[0].data = (char *)conf; hash_input[0].length = CONFLENGTH; hash_input[1].data = input->data; hash_input[1].length = input->length; /* Save the pointer to the beginning of the output buffer */ outptr = (char *)output->data; /* * Move the output ptr ahead so we can write the hash * digest directly into the buffer. */ output->data = output->data + CONFLENGTH; /* Use generic hash function that calls to kEF */ if (k5_ef_hash(context, 2, hash_input, output)) { FREE(hash_input, sizeof(krb5_data) * 2); return(KRB5_KEF_ERROR); } /* restore the original ptr to the output data */ output->data = outptr; /* * Put the confounder in the beginning of the buffer to be * encrypted. */ bcopy(conf, output->data, CONFLENGTH); bcopy(key->contents, xorkey, sizeof(xorkey)); for (i=0; i<sizeof(xorkey); i++) xorkey[i] ^= 0xf0; /* * Solaris Kerberos: * Encryption Framework checks for parity and weak keys. */ bzero(&newkey, sizeof(krb5_keyblock)); newkey.enctype = key->enctype; newkey.contents = xorkey; newkey.length = sizeof(xorkey); newkey.dk_list = NULL; newkey.kef_key.ck_data = NULL; ret = init_key_kef(context->kef_cipher_mt, &newkey); if (ret) { FREE(hash_input, sizeof(krb5_data) * 2); return (ret); } /* encrypt it, in place. this has a return value, but it's always zero. */ ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data, (krb5_pointer) output->data, output->length, &newkey, (unsigned char*) mit_des_zeroblock, 1); FREE(hash_input, sizeof(krb5_data) * 2); (void)crypto_destroy_ctx_template(newkey.key_tmpl); return(ret); }