1/*
2 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * lib/crypto/keyhash_provider/hmac_md5.c
8 *
9(I don't know)
10.
11 * Copyright2001 by the Massachusetts Institute of Technology.
12 * All Rights Reserved.
13 *
14 * Export of this software from the United States of America may
15 *   require a specific license from the United States Government.
16 *   It is the responsibility of any person or organization contemplating
17 *   export to obtain such a license before exporting.
18 *
19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20 * distribute this software and its documentation for any purpose and
21 * without fee is hereby granted, provided that the above copyright
22 * notice appear in all copies and that both that copyright notice and
23 * this permission notice appear in supporting documentation, and that
24 * the name of M.I.T. not be used in advertising or publicity pertaining
25 * to distribution of the software without specific, written prior
26 * permission.  Furthermore if you modify this software you must label
27 * your software as modified software and not distribute it in such a
28 * fashion that it might be confused with the original M.I.T. software.
29 * M.I.T. makes no representations about the suitability of
30 * this software for any purpose.  It is provided "as is" without express
31 * or implied warranty.
32 *
33 *
34* Implementation of the Microsoft hmac-md5 checksum type.
35* Implemented based on draft-brezak-win2k-krb-rc4-hmac-03
36 */
37
38#include "k5-int.h"
39#include "keyhash_provider.h"
40#include "arcfour.h"
41#include "hash_provider.h"
42
43static  krb5_error_code
44k5_hmac_md5_hash (krb5_context context,
45	const krb5_keyblock *key, krb5_keyusage usage,
46	const krb5_data *iv,
47	const krb5_data *input, krb5_data *output)
48{
49  krb5_keyusage ms_usage;
50  krb5_error_code ret;
51  krb5_keyblock ks;
52  krb5_data ds, ks_constant, md5tmp;
53  krb5_data hash_input[2];
54  char digest[MD5_CKSUM_LENGTH];
55  char t[4];
56  CK_MECHANISM mechanism;
57  CK_RV rv;
58  CK_ULONG hashlen;
59
60  bzero(&ks, sizeof(krb5_keyblock));
61
62  /*
63   * Solaris Kerberos: The digest length is that of MD5_CKSUM_LENGTH not the key
64   * length, as keys can be of varying lengths but should not affect the digest
65   * length.  The signing key is the digest and therefore is also the same
66   * length, MD5_CKSUM_LENGTH.
67   */
68  ds.length = MD5_CKSUM_LENGTH;
69  ks.length = MD5_CKSUM_LENGTH;
70  ds.data = malloc(ds.length);
71  if (ds.data == NULL)
72    return ENOMEM;
73  ks.contents = (void *) ds.data;
74
75  ks_constant.data = "signaturekey";
76  ks_constant.length = strlen(ks_constant.data)+1; /* Including null*/
77
78  /* Solaris Kerberos */
79  ret = krb5_hmac(context, &krb5int_hash_md5, key, 1,
80		   &ks_constant, &ds);
81  if (ret)
82    goto cleanup;
83
84  ms_usage = krb5int_arcfour_translate_usage (usage);
85  t[0] = (ms_usage) & 0xff;
86  t[1] = (ms_usage>>8) & 0xff;
87  t[2] = (ms_usage >>16) & 0xff;
88  t[3] = (ms_usage>>24) & 0XFF;
89
90  /* Solaris Kerberos */
91  mechanism.mechanism = CKM_MD5;
92  mechanism.pParameter = NULL_PTR;
93  mechanism.ulParameterLen = 0;
94
95  if ((rv = C_DigestInit(krb_ctx_hSession(context), &mechanism)) != CKR_OK) {
96	KRB5_LOG(KRB5_ERR, "C_DigestInit failed in k5_md5_hmac_hash: "
97	"rv = 0x%x.", rv);
98	ret = PKCS_ERR;
99	goto cleanup;
100  }
101  if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
102	(CK_BYTE_PTR)t, (CK_ULONG)sizeof(t))) != CKR_OK) {
103	KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5_hmac_hash: "
104            "rv = 0x%x", rv);
105	ret = PKCS_ERR;
106	goto cleanup;
107  }
108  if ((rv = C_DigestUpdate(krb_ctx_hSession(context),
109	(CK_BYTE_PTR)input->data, (CK_ULONG)input->length)) != CKR_OK) {
110	KRB5_LOG(KRB5_ERR, "C_DigestUpdate failed in k5_md5_hmac_hash: "
111            "rv = 0x%x", rv);
112	ret = PKCS_ERR;
113	goto cleanup;
114  }
115  hashlen = MD5_CKSUM_LENGTH;
116  if ((rv = C_DigestFinal(krb_ctx_hSession(context),
117	(CK_BYTE_PTR)digest, (CK_ULONG_PTR)&hashlen)) != CKR_OK) {
118	KRB5_LOG(KRB5_ERR, "C_DigestFinal failed in k5_md5_hmac_hash: "
119            "rv = 0x%x", rv);
120	ret = PKCS_ERR;
121	goto cleanup;
122  }
123
124  md5tmp.data = digest;
125  md5tmp.length = hashlen;
126
127  ret = krb5_hmac (context, &krb5int_hash_md5, &ks, 1, &md5tmp, output);
128
129cleanup:
130  bzero(ks.contents, ks.length);
131  bzero(md5tmp.data, md5tmp.length);
132  FREE (ks.contents, ks.length);
133  return (ret);
134}
135
136
137
138const struct krb5_keyhash_provider krb5int_keyhash_hmac_md5 = {
139  16,
140  k5_hmac_md5_hash,
141  NULL /*checksum  again*/
142};
143
144