krb5_error_code k5_ef_hash(krb5_context context, CK_MECHANISM *mechanism, unsigned int icount, krb5_const krb5_data *input, krb5_data *output) { CK_RV rv; int i; CK_ULONG outlen = output->length; if ((rv = C_DigestInit(krb_ctx_hSession(context), mechanism)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_ef_hash: " "rv = 0x%x.", rv); return (PKCS_ERR); } for (i = 0; i < icount; i++) { if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)input[i].data, (CK_ULONG)input[i].length)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_ef_hash: " "rv = 0x%x", rv); return (PKCS_ERR); } } if ((rv = C_DigestFinal(krb_ctx_hSession(context), (CK_BYTE_PTR)output->data, &outlen)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_ef_hash: " "rv = 0x%x", rv); return (PKCS_ERR); } /* Narrowing conversion OK because hashes are much smaller than 2^32 */ output->length = outlen; KRB5_LOG0(KRB5_INFO, "k5_ef_hash() end"); return (0); }
/*ARGSUSED*/ krb5_error_code KRB5_CALLCONV krb5_c_random_make_octets(krb5_context context, krb5_data *data) { /* * Solaris kerberos uses /dev/[u]random */ #ifndef _KERNEL /* User space code */ krb5_error_code err = 0; CK_RV rv; KRB5_LOG0(KRB5_INFO, "krb5_c_random_make_octets() start, user space using " "krb5_get_random_octets()\n"); rv = C_GenerateRandom(krb_ctx_hSession(context), (CK_BYTE_PTR)data->data, (CK_ULONG)data->length); if (rv != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_GenerateRandom failed in " "krb5_c_random_make_octets: rv = 0x%x.", rv); err = PKCS_ERR; } if (err != 0) { KRB5_LOG0(KRB5_ERR, "krb5_c_random_make_octets() end, error"); return (err); } #else /* Kernel code section */ /* * Solaris Kerberos: for kernel code we use the randomness generator native * to Solaris 9. We avoid global variables and other nastiness this way. * * Using random_get_pseudo_bytes() instead of random_get_bytes() because it * will not return an error code if there isn't enough entropy but will use * a pseudo random algorithm to produce randomness. Most of the time it * should be as good as random_get_bytes() and we don't have to worry about * dealing with a non-fatal error. */ KRB5_LOG0(KRB5_INFO, "krb5_c_random_make_octets() start, kernel using " "random_get_pseudo_bytes()\n "); if(random_get_pseudo_bytes((uint8_t *)data->data, data->length) != 0) { KRB5_LOG0(KRB5_ERR, "krb5_c_random_make_octets() end, " "random_get_pseudo_bytes() error.\n"); return(KRB5_CRYPTO_INTERNAL); } #endif /* !_KERNEL */ KRB5_LOG0(KRB5_INFO, "krb5_c_random_make_octets() end\n"); return(0); }
/*ARGSUSED*/ krb5_error_code KRB5_CALLCONV krb5_c_random_seed(krb5_context context, krb5_data *data) { /* * We can't do much if this fails, so ignore the * return code. /dev/urandom has its own entropy * source, so seeding it from here is of questionable * value in the first place. */ (void) C_SeedRandom(krb_ctx_hSession(context), (CK_BYTE_PTR)data->data, (CK_ULONG)data->length); return(0); }
/*ARGSUSED*/ krb5_error_code KRB5_CALLCONV krb5_c_decrypt(krb5_context context, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec, const krb5_enc_data *input, krb5_data *output) { int i; krb5_error_code ret = 0; for (i=0; i<krb5_enctypes_length; i++) { if (krb5_enctypes_list[i].etype == key->enctype) break; } if (i == krb5_enctypes_length) return(KRB5_BAD_ENCTYPE); if ((input->enctype != ENCTYPE_UNKNOWN) && (krb5_enctypes_list[i].etype != input->enctype)) return(KRB5_BAD_ENCTYPE); #ifdef _KERNEL context->kef_cipher_mt = krb5_enctypes_list[i].kef_cipher_mt; context->kef_hash_mt = krb5_enctypes_list[i].kef_hash_mt; if (key->kef_key.ck_data == NULL) ret = init_key_kef(context->kef_cipher_mt, (krb5_keyblock *)key); if (ret) return(ret); #else if ((ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key))) return (ret); #endif /* _KERNEL */ return((*(krb5_enctypes_list[i].decrypt)) (context, krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash, key, usage, ivec, &input->ciphertext, output)); }
/*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); }
/*ARGSUSED*/ static krb5_error_code k5_md5des_verify(krb5_context context, krb5_const krb5_keyblock *key, krb5_keyusage usage, krb5_const krb5_data *ivec, krb5_const krb5_data *input, krb5_const krb5_data *hash, krb5_boolean *valid) { krb5_error_code ret = 0; unsigned char plaintext[CONFLENGTH+MD5_CKSUM_LENGTH]; unsigned char digest[MD5_CKSUM_LENGTH]; krb5_keyblock xorkey; int i; int compathash = 0; 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 (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) { #ifdef KRB5_MD5DES_BETA5_COMPAT if (hash->length != MD5_CKSUM_LENGTH) return(KRB5_CRYPTO_INTERNAL); else compathash = 1; #else return(KRB5_CRYPTO_INTERNAL); #endif } /* create and the encryption key */ 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); if (!compathash) { 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; } /* decrypt it. this has a return value, but it's always zero. */ if (!compathash) { ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, &xorkey, (unsigned char*) mit_des_zeroblock, 0); } else { ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data, (krb5_pointer) plaintext, hash->length, &xorkey, xorkey.contents, 0); } if (ret) 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_verify: " "rv = 0x%x.", rv); ret = PKCS_ERR; goto cleanup; } if (!compathash) { if ((rv = C_DigestUpdate(krb_ctx_hSession(context), (CK_BYTE_PTR)plaintext, (CK_ULONG)CONFLENGTH)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5des_verify: " "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_verify: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } if ((rv = C_DigestFinal(krb_ctx_hSession(context), (CK_BYTE_PTR)digest, (CK_ULONG_PTR)&hashlen)) != CKR_OK) { KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5des_verify: " "rv = 0x%x", rv); ret = PKCS_ERR; goto cleanup; } /* compare the decrypted hash to the computed one */ if (!compathash) { *valid = (memcmp(plaintext+CONFLENGTH, digest, sizeof(digest)) == 0); } else { *valid = (memcmp(plaintext, digest, sizeof(digest)) == 0); } (void) memset(plaintext, 0, sizeof(plaintext)); cleanup: free(xorkey.contents); return(ret); }
krb5_error_code KRB5_CALLCONV krb5_c_make_checksum(krb5_context context, krb5_cksumtype cksumtype, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *input, krb5_checksum *cksum) { int i, e1, e2; krb5_data data; krb5_error_code ret = 0; size_t cksumlen; KRB5_LOG0(KRB5_INFO, "krb5_c_make_checksum() start."); for (i=0; i<krb5_cksumtypes_length; i++) { if (krb5_cksumtypes_list[i].ctype == cksumtype) break; } if (i == krb5_cksumtypes_length) return(KRB5_BAD_ENCTYPE); if (krb5_cksumtypes_list[i].keyhash) cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize; else cksumlen = krb5_cksumtypes_list[i].hash->hashsize; #ifdef _KERNEL context->kef_cksum_mt = krb5_cksumtypes_list[i].kef_cksum_mt; #endif cksum->length = cksumlen; if ((cksum->contents = (krb5_octet *) MALLOC(cksum->length)) == NULL) return(ENOMEM); data.length = cksum->length; data.data = (char *) cksum->contents; if (krb5_cksumtypes_list[i].keyhash) { /* check if key is compatible */ if (krb5_cksumtypes_list[i].keyed_etype) { for (e1=0; e1<krb5_enctypes_length; e1++) if (krb5_enctypes_list[e1].etype == krb5_cksumtypes_list[i].keyed_etype) break; for (e2=0; e2<krb5_enctypes_length; e2++) if (krb5_enctypes_list[e2].etype == key->enctype) break; if ((e1 == krb5_enctypes_length) || (e2 == krb5_enctypes_length) || (krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) { ret = KRB5_BAD_ENCTYPE; goto cleanup; } } #ifdef _KERNEL context->kef_cipher_mt = krb5_enctypes_list[e1].kef_cipher_mt; context->kef_hash_mt = krb5_enctypes_list[e1].kef_hash_mt; if (key->kef_key.ck_data == NULL) { if ((ret = init_key_kef(context->kef_cipher_mt, (krb5_keyblock *)key))) goto cleanup; } #else if ((ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key))) return (ret); #endif /* _KERNEL */ ret = (*(krb5_cksumtypes_list[i].keyhash->hash))(context, key, usage, 0, input, &data); } else if (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE) { #ifdef _KERNEL context->kef_cipher_mt = get_cipher_mech_type(context, (krb5_keyblock *)key); context->kef_hash_mt = get_hash_mech_type(context, (krb5_keyblock *)key); /* * If the hash_mt is invalid, try using the cksum_mt * because "hash" and "checksum" are overloaded terms * in some places. */ if (context->kef_hash_mt == CRYPTO_MECH_INVALID) context->kef_hash_mt = context->kef_cksum_mt; #else ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key); if (ret) return (ret); #endif /* _KERNEL */ ret = krb5_dk_make_checksum(context, krb5_cksumtypes_list[i].hash, key, usage, input, &data); } else { /* * No key is used, hash and cksum are synonymous * in this case */ #ifdef _KERNEL context->kef_hash_mt = context->kef_cksum_mt; #endif /* _KERNEL */ ret = (*(krb5_cksumtypes_list[i].hash->hash))(context, 1, input, &data); } if (!ret) { cksum->magic = KV5M_CHECKSUM; cksum->checksum_type = cksumtype; if (krb5_cksumtypes_list[i].trunc_size) { krb5_octet *trunc; size_t old_len = cksum->length; /* * Solaris Kerberos: * The Kernel does not like 'realloc' (which is what * MIT code does here), so we do our own "realloc". */ cksum->length = krb5_cksumtypes_list[i].trunc_size; trunc = (krb5_octet *) MALLOC(cksum->length); if (trunc) { (void) memcpy(trunc, cksum->contents, cksum->length); FREE(cksum->contents, old_len); cksum->contents = trunc; } else { ret = ENOMEM; } } } cleanup: if (ret) { (void) memset(cksum->contents, 0, cksum->length); FREE(cksum->contents, cksum->length); cksum->length = 0; cksum->contents = NULL; } KRB5_LOG(KRB5_INFO, "krb5_c_make_checksum() end ret = %d\n", ret); return(ret); }