Line data Source code
1 : /*
2 : * Copyright (c) 2016 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * 3. Neither the name of the Institute nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : */
35 :
36 : #include <config.h>
37 : #include <roken.h>
38 :
39 : #ifdef PKINIT
40 :
41 : /*
42 : * As with the other *-ec.c files in Heimdal, this is a bit of a hack.
43 : *
44 : * The idea is to use OpenSSL for EC because hcrypto doesn't have the
45 : * required functionality at this time. To do this we segregate
46 : * EC-using code into separate source files and then we arrange for them
47 : * to get the OpenSSL headers and not the conflicting hcrypto ones.
48 : *
49 : * Because of auto-generated *-private.h headers, we end up needing to
50 : * make sure various types are defined before we include them, thus the
51 : * strange header include order here.
52 : */
53 :
54 : #ifdef HAVE_HCRYPTO_W_OPENSSL
55 : #include <openssl/ec.h>
56 : #include <openssl/ecdh.h>
57 : #include <openssl/evp.h>
58 : #include <openssl/bn.h>
59 : #define HEIM_NO_CRYPTO_HDRS
60 : #endif
61 :
62 : /*
63 : * NO_HCRYPTO_POLLUTION -> don't refer to hcrypto type/function names
64 : * that we don't need in this file and which would clash with OpenSSL's
65 : * in ways that are difficult to address in cleaner ways.
66 : *
67 : * In the medium- to long-term what we should do is move all PK in
68 : * Heimdal to the newer EVP interfaces for PK and then nothing outside
69 : * lib/hcrypto should ever have to include OpenSSL headers, and -more
70 : * specifically- the only thing that should ever have to include OpenSSL
71 : * headers is the OpenSSL backend to hcrypto.
72 : */
73 : #define NO_HCRYPTO_POLLUTION
74 :
75 : #include "krb5_locl.h"
76 : #include <hcrypto/des.h>
77 : #include <cms_asn1.h>
78 : #include <pkcs8_asn1.h>
79 : #include <pkcs9_asn1.h>
80 : #include <pkcs12_asn1.h>
81 : #include <pkinit_asn1.h>
82 : #include <asn1_err.h>
83 :
84 : #include <der.h>
85 :
86 : krb5_error_code
87 0 : _krb5_build_authpack_subjectPK_EC(krb5_context context,
88 : krb5_pk_init_ctx ctx,
89 : AuthPack *a)
90 : {
91 : #ifdef HAVE_HCRYPTO_W_OPENSSL
92 : krb5_error_code ret;
93 : ECParameters ecp;
94 : unsigned char *p;
95 : size_t size;
96 : int xlen;
97 :
98 : /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
99 :
100 : ecp.element = choice_ECParameters_namedCurve;
101 : ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
102 : &ecp.u.namedCurve);
103 : if (ret)
104 : return ret;
105 :
106 : ALLOC(a->clientPublicValue->algorithm.parameters, 1);
107 : if (a->clientPublicValue->algorithm.parameters == NULL) {
108 : free_ECParameters(&ecp);
109 : return krb5_enomem(context);
110 : }
111 : ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret);
112 : free_ECParameters(&ecp);
113 : if (ret)
114 : return ret;
115 : if ((int)size != xlen)
116 : krb5_abortx(context, "asn1 internal error");
117 :
118 : a->clientPublicValue->algorithm.parameters->data = p;
119 : a->clientPublicValue->algorithm.parameters->length = size;
120 :
121 : /* copy in public key */
122 :
123 : ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
124 : &a->clientPublicValue->algorithm.algorithm);
125 : if (ret)
126 : return ret;
127 :
128 : ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
129 : if (ctx->u.eckey == NULL)
130 : return krb5_enomem(context);
131 :
132 : ret = EC_KEY_generate_key(ctx->u.eckey);
133 : if (ret != 1)
134 : return EINVAL;
135 :
136 : xlen = i2o_ECPublicKey(ctx->u.eckey, NULL);
137 : if (xlen <= 0)
138 : return EINVAL;
139 :
140 : p = malloc(xlen);
141 : if (p == NULL)
142 : return krb5_enomem(context);
143 :
144 : a->clientPublicValue->subjectPublicKey.data = p;
145 :
146 : xlen = i2o_ECPublicKey(ctx->u.eckey, &p);
147 : if (xlen <= 0) {
148 : a->clientPublicValue->subjectPublicKey.data = NULL;
149 : free(p);
150 : return EINVAL;
151 : }
152 :
153 : a->clientPublicValue->subjectPublicKey.length = xlen * 8;
154 :
155 : return 0;
156 :
157 : /* XXX verify that this is right with RFC3279 */
158 : #else
159 0 : krb5_set_error_message(context, ENOTSUP,
160 0 : N_("PKINIT: ECDH not supported", ""));
161 0 : return ENOTSUP;
162 : #endif
163 : }
164 :
165 : krb5_error_code
166 0 : _krb5_pk_rd_pa_reply_ecdh_compute_key(krb5_context context,
167 : krb5_pk_init_ctx ctx,
168 : const unsigned char *in,
169 : size_t in_sz,
170 : unsigned char **out,
171 : int *out_sz)
172 : {
173 : #ifdef HAVE_HCRYPTO_W_OPENSSL
174 : krb5_error_code ret = 0;
175 : int dh_gen_keylen;
176 :
177 : const EC_GROUP *group;
178 : EC_KEY *public = NULL;
179 :
180 : group = EC_KEY_get0_group(ctx->u.eckey);
181 :
182 : public = EC_KEY_new();
183 : if (public == NULL)
184 : return krb5_enomem(context);
185 : if (EC_KEY_set_group(public, group) != 1) {
186 : EC_KEY_free(public);
187 : return krb5_enomem(context);
188 : }
189 :
190 : if (o2i_ECPublicKey(&public, &in, in_sz) == NULL) {
191 : EC_KEY_free(public);
192 : ret = KRB5KRB_ERR_GENERIC;
193 : krb5_set_error_message(context, ret,
194 : N_("PKINIT: Can't parse ECDH public key", ""));
195 : return ret;
196 : }
197 :
198 : *out_sz = (EC_GROUP_get_degree(group) + 7) / 8;
199 : if (*out_sz < 0)
200 : return EOVERFLOW;
201 : *out = malloc(*out_sz);
202 : if (*out == NULL) {
203 : EC_KEY_free(public);
204 : return krb5_enomem(context);
205 : }
206 : dh_gen_keylen = ECDH_compute_key(*out, *out_sz,
207 : EC_KEY_get0_public_key(public),
208 : ctx->u.eckey, NULL);
209 : EC_KEY_free(public);
210 : if (dh_gen_keylen <= 0) {
211 : ret = KRB5KRB_ERR_GENERIC;
212 : dh_gen_keylen = 0;
213 : krb5_set_error_message(context, ret,
214 : N_("PKINIT: Can't compute ECDH public key", ""));
215 : free(*out);
216 : *out = NULL;
217 : *out_sz = 0;
218 : }
219 : *out_sz = dh_gen_keylen;
220 :
221 : return ret;
222 : #else
223 0 : krb5_set_error_message(context, ENOTSUP,
224 0 : N_("PKINIT: ECDH not supported", ""));
225 0 : return ENOTSUP;
226 : #endif
227 : }
228 :
229 : void
230 0 : _krb5_pk_eckey_free(void *eckey)
231 : {
232 : #ifdef HAVE_HCRYPTO_W_OPENSSL
233 : EC_KEY_free(eckey);
234 : #endif
235 0 : }
236 :
237 : #else
238 :
239 : static char lib_krb5_pkinit_ec_c = '\0';
240 :
241 : #endif
|