/src/samba/third_party/heimdal/lib/krb5/crypto-pk.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan |
3 | | * (Royal Institute of Technology, Stockholm, Sweden). |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in the |
15 | | * documentation and/or other materials provided with the distribution. |
16 | | * |
17 | | * 3. Neither the name of the Institute nor the names of its contributors |
18 | | * may be used to endorse or promote products derived from this software |
19 | | * without specific prior written permission. |
20 | | * |
21 | | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND |
22 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE |
25 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | | * SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | #include "krb5_locl.h" |
35 | | |
36 | | #include <pkinit_asn1.h> |
37 | | |
38 | | KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL |
39 | | _krb5_pk_octetstring2key(krb5_context context, |
40 | | krb5_enctype type, |
41 | | const void *dhdata, |
42 | | size_t dhsize, |
43 | | const heim_octet_string *c_n, |
44 | | const heim_octet_string *k_n, |
45 | | krb5_keyblock *key) |
46 | 0 | { |
47 | 0 | struct _krb5_encryption_type *et = _krb5_find_enctype(type); |
48 | 0 | krb5_error_code ret; |
49 | 0 | size_t keylen, offset; |
50 | 0 | void *keydata; |
51 | 0 | unsigned char counter; |
52 | 0 | unsigned char shaoutput[SHA_DIGEST_LENGTH]; |
53 | 0 | EVP_MD_CTX *m; |
54 | |
|
55 | 0 | if(et == NULL) { |
56 | 0 | krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, |
57 | 0 | N_("encryption type %d not supported", ""), |
58 | 0 | type); |
59 | 0 | return KRB5_PROG_ETYPE_NOSUPP; |
60 | 0 | } |
61 | 0 | keylen = (et->keytype->bits + 7) / 8; |
62 | |
|
63 | 0 | keydata = malloc(keylen); |
64 | 0 | if (keydata == NULL) |
65 | 0 | return krb5_enomem(context); |
66 | | |
67 | 0 | m = EVP_MD_CTX_create(); |
68 | 0 | if (m == NULL) { |
69 | 0 | free(keydata); |
70 | 0 | return krb5_enomem(context); |
71 | 0 | } |
72 | | |
73 | 0 | counter = 0; |
74 | 0 | offset = 0; |
75 | 0 | do { |
76 | |
|
77 | 0 | EVP_DigestInit_ex(m, EVP_sha1(), NULL); |
78 | 0 | EVP_DigestUpdate(m, &counter, 1); |
79 | 0 | EVP_DigestUpdate(m, dhdata, dhsize); |
80 | |
|
81 | 0 | if (c_n) |
82 | 0 | EVP_DigestUpdate(m, c_n->data, c_n->length); |
83 | 0 | if (k_n) |
84 | 0 | EVP_DigestUpdate(m, k_n->data, k_n->length); |
85 | |
|
86 | 0 | EVP_DigestFinal_ex(m, shaoutput, NULL); |
87 | |
|
88 | 0 | memcpy((unsigned char *)keydata + offset, |
89 | 0 | shaoutput, |
90 | 0 | min(keylen - offset, sizeof(shaoutput))); |
91 | |
|
92 | 0 | offset += sizeof(shaoutput); |
93 | 0 | counter++; |
94 | 0 | } while(offset < keylen); |
95 | 0 | memset_s(shaoutput, sizeof(shaoutput), 0, sizeof(shaoutput)); |
96 | |
|
97 | 0 | EVP_MD_CTX_destroy(m); |
98 | |
|
99 | 0 | ret = krb5_random_to_key(context, type, keydata, keylen, key); |
100 | 0 | memset_s(keydata, sizeof(keylen), 0, sizeof(keylen)); |
101 | 0 | free(keydata); |
102 | 0 | return ret; |
103 | 0 | } |
104 | | |
105 | | static krb5_error_code |
106 | | encode_uvinfo(krb5_context context, krb5_const_principal p, krb5_data *data) |
107 | 0 | { |
108 | 0 | KRB5PrincipalName pn; |
109 | 0 | krb5_error_code ret; |
110 | 0 | size_t size = 0; |
111 | |
|
112 | 0 | pn.principalName = p->name; |
113 | 0 | pn.realm = p->realm; |
114 | |
|
115 | 0 | ASN1_MALLOC_ENCODE(KRB5PrincipalName, data->data, data->length, |
116 | 0 | &pn, &size, ret); |
117 | 0 | if (ret) { |
118 | 0 | krb5_data_zero(data); |
119 | 0 | krb5_set_error_message(context, ret, |
120 | 0 | N_("Failed to encode KRB5PrincipalName", "")); |
121 | 0 | return ret; |
122 | 0 | } |
123 | 0 | if (data->length != size) |
124 | 0 | krb5_abortx(context, "asn1 compiler internal error"); |
125 | 0 | return 0; |
126 | 0 | } |
127 | | |
128 | | static krb5_error_code |
129 | | encode_otherinfo(krb5_context context, |
130 | | const AlgorithmIdentifier *ai, |
131 | | krb5_const_principal client, |
132 | | krb5_const_principal server, |
133 | | krb5_enctype enctype, |
134 | | const krb5_data *as_req, |
135 | | const krb5_data *pk_as_rep, |
136 | | const Ticket *ticket, |
137 | | krb5_data *other) |
138 | 0 | { |
139 | 0 | PkinitSP80056AOtherInfo otherinfo; |
140 | 0 | PkinitSuppPubInfo pubinfo; |
141 | 0 | krb5_error_code ret; |
142 | 0 | krb5_data pub; |
143 | 0 | size_t size = 0; |
144 | |
|
145 | 0 | krb5_data_zero(other); |
146 | 0 | memset(&otherinfo, 0, sizeof(otherinfo)); |
147 | 0 | memset(&pubinfo, 0, sizeof(pubinfo)); |
148 | |
|
149 | 0 | pubinfo.enctype = enctype; |
150 | 0 | pubinfo.as_REQ = *as_req; |
151 | 0 | pubinfo.pk_as_rep = *pk_as_rep; |
152 | 0 | pubinfo.ticket = *ticket; |
153 | 0 | ASN1_MALLOC_ENCODE(PkinitSuppPubInfo, pub.data, pub.length, |
154 | 0 | &pubinfo, &size, ret); |
155 | 0 | if (ret) { |
156 | 0 | krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); |
157 | 0 | return ret; |
158 | 0 | } |
159 | 0 | if (pub.length != size) |
160 | 0 | krb5_abortx(context, "asn1 compiler internal error"); |
161 | | |
162 | 0 | ret = encode_uvinfo(context, client, &otherinfo.partyUInfo); |
163 | 0 | if (ret) { |
164 | 0 | free(pub.data); |
165 | 0 | return ret; |
166 | 0 | } |
167 | 0 | ret = encode_uvinfo(context, server, &otherinfo.partyVInfo); |
168 | 0 | if (ret) { |
169 | 0 | free(otherinfo.partyUInfo.data); |
170 | 0 | free(pub.data); |
171 | 0 | return ret; |
172 | 0 | } |
173 | | |
174 | 0 | otherinfo.algorithmID = *ai; |
175 | 0 | otherinfo.suppPubInfo = &pub; |
176 | |
|
177 | 0 | ASN1_MALLOC_ENCODE(PkinitSP80056AOtherInfo, other->data, other->length, |
178 | 0 | &otherinfo, &size, ret); |
179 | 0 | free(otherinfo.partyUInfo.data); |
180 | 0 | free(otherinfo.partyVInfo.data); |
181 | 0 | free(pub.data); |
182 | 0 | if (ret) { |
183 | 0 | krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); |
184 | 0 | return ret; |
185 | 0 | } |
186 | 0 | if (other->length != size) |
187 | 0 | krb5_abortx(context, "asn1 compiler internal error"); |
188 | | |
189 | 0 | return 0; |
190 | 0 | } |
191 | | |
192 | | |
193 | | |
194 | | KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL |
195 | | _krb5_pk_kdf(krb5_context context, |
196 | | const struct AlgorithmIdentifier *ai, |
197 | | const void *dhdata, |
198 | | size_t dhsize, |
199 | | krb5_const_principal client, |
200 | | krb5_const_principal server, |
201 | | krb5_enctype enctype, |
202 | | const krb5_data *as_req, |
203 | | const krb5_data *pk_as_rep, |
204 | | const Ticket *ticket, |
205 | | krb5_keyblock *key) |
206 | 0 | { |
207 | 0 | struct _krb5_encryption_type *et; |
208 | 0 | krb5_error_code ret; |
209 | 0 | krb5_data other; |
210 | 0 | size_t keylen, offset; |
211 | 0 | uint32_t counter; |
212 | 0 | unsigned char *keydata; |
213 | 0 | unsigned char shaoutput[SHA512_DIGEST_LENGTH]; |
214 | 0 | const EVP_MD *md; |
215 | 0 | EVP_MD_CTX *m; |
216 | |
|
217 | 0 | if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) == 0) { |
218 | 0 | md = EVP_sha1(); |
219 | 0 | } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha256, &ai->algorithm) == 0) { |
220 | 0 | md = EVP_sha256(); |
221 | 0 | } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha512, &ai->algorithm) == 0) { |
222 | 0 | md = EVP_sha512(); |
223 | 0 | } else { |
224 | 0 | krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, |
225 | 0 | N_("KDF not supported", "")); |
226 | 0 | return KRB5_PROG_ETYPE_NOSUPP; |
227 | 0 | } |
228 | 0 | if (ai->parameters != NULL && |
229 | 0 | (ai->parameters->length != 2 || |
230 | 0 | memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) |
231 | 0 | { |
232 | 0 | krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, |
233 | 0 | N_("kdf params not NULL or the NULL-type", |
234 | 0 | "")); |
235 | 0 | return KRB5_PROG_ETYPE_NOSUPP; |
236 | 0 | } |
237 | | |
238 | 0 | et = _krb5_find_enctype(enctype); |
239 | 0 | if(et == NULL) { |
240 | 0 | krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, |
241 | 0 | N_("encryption type %d not supported", ""), |
242 | 0 | enctype); |
243 | 0 | return KRB5_PROG_ETYPE_NOSUPP; |
244 | 0 | } |
245 | 0 | keylen = (et->keytype->bits + 7) / 8; |
246 | |
|
247 | 0 | keydata = malloc(keylen); |
248 | 0 | if (keydata == NULL) |
249 | 0 | return krb5_enomem(context); |
250 | | |
251 | 0 | ret = encode_otherinfo(context, ai, client, server, |
252 | 0 | enctype, as_req, pk_as_rep, ticket, &other); |
253 | 0 | if (ret) { |
254 | 0 | free(keydata); |
255 | 0 | return ret; |
256 | 0 | } |
257 | | |
258 | 0 | m = EVP_MD_CTX_create(); |
259 | 0 | if (m == NULL) { |
260 | 0 | free(keydata); |
261 | 0 | free(other.data); |
262 | 0 | return krb5_enomem(context); |
263 | 0 | } |
264 | | |
265 | 0 | offset = 0; |
266 | 0 | counter = 1; |
267 | 0 | do { |
268 | 0 | unsigned char cdata[4]; |
269 | |
|
270 | 0 | EVP_DigestInit_ex(m, md, NULL); |
271 | 0 | _krb5_put_int(cdata, counter, 4); |
272 | 0 | EVP_DigestUpdate(m, cdata, 4); |
273 | 0 | EVP_DigestUpdate(m, dhdata, dhsize); |
274 | 0 | EVP_DigestUpdate(m, other.data, other.length); |
275 | |
|
276 | 0 | EVP_DigestFinal_ex(m, shaoutput, NULL); |
277 | |
|
278 | 0 | memcpy((unsigned char *)keydata + offset, |
279 | 0 | shaoutput, |
280 | 0 | min(keylen - offset, EVP_MD_CTX_size(m))); |
281 | |
|
282 | 0 | offset += EVP_MD_CTX_size(m); |
283 | 0 | counter++; |
284 | 0 | } while(offset < keylen); |
285 | 0 | memset_s(shaoutput, sizeof(shaoutput), 0, sizeof(shaoutput)); |
286 | |
|
287 | 0 | EVP_MD_CTX_destroy(m); |
288 | 0 | free(other.data); |
289 | |
|
290 | 0 | ret = krb5_random_to_key(context, enctype, keydata, keylen, key); |
291 | 0 | memset_s(keydata, sizeof(keylen), 0, sizeof(keylen)); |
292 | 0 | free(keydata); |
293 | |
|
294 | 0 | return ret; |
295 | 0 | } |