• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 #include "private-lib-tls-mbedtls.h"
27 #include <mbedtls/oid.h>
28 
29 #if defined(LWS_PLAT_OPTEE) || defined(OPTEE_DEV_KIT)
30 struct tm {
31 int    tm_sec; //   seconds [0,61]
32 int    tm_min; //   minutes [0,59]
33 int    tm_hour; //  hour [0,23]
34 int    tm_mday; //  day of month [1,31]
35 int    tm_mon; //   month of year [0,11]
36 int    tm_year; //  years since 1900
37 int    tm_wday; //  day of week [0,6] (Sunday = 0)
38 int    tm_yday; //  day of year [0,365]
39 int    tm_isdst; // daylight savings flag
40 };
mktime(struct tm * t)41 time_t mktime(struct tm *t)
42 {
43 	return (time_t)0;
44 }
45 #endif
46 
47 static time_t
lws_tls_mbedtls_time_to_unix(mbedtls_x509_time * xtime)48 lws_tls_mbedtls_time_to_unix(mbedtls_x509_time *xtime)
49 {
50 	struct tm t;
51 
52 	if (!xtime || !xtime->MBEDTLS_PRIVATE(year) || xtime->MBEDTLS_PRIVATE(year) < 0)
53 		return (time_t)(long long)-1;
54 
55 	memset(&t, 0, sizeof(t));
56 
57 	t.tm_year = xtime->MBEDTLS_PRIVATE(year) - 1900;
58 	t.tm_mon = xtime->MBEDTLS_PRIVATE(mon) - 1; /* mbedtls months are 1+, tm are 0+ */
59 	t.tm_mday = xtime->MBEDTLS_PRIVATE(day) - 1; /* mbedtls days are 1+, tm are 0+ */
60 	t.tm_hour = xtime->MBEDTLS_PRIVATE(hour);
61 	t.tm_min = xtime->MBEDTLS_PRIVATE(min);
62 	t.tm_sec = xtime->MBEDTLS_PRIVATE(sec);
63 	t.tm_isdst = -1;
64 
65 	return mktime(&t);
66 }
67 
68 static int
lws_tls_mbedtls_get_x509_name(mbedtls_x509_name * name,union lws_tls_cert_info_results * buf,size_t len)69 lws_tls_mbedtls_get_x509_name(mbedtls_x509_name *name,
70 			      union lws_tls_cert_info_results *buf, size_t len)
71 {
72 	int r = -1;
73 
74 	buf->ns.len = 0;
75 
76 	while (name) {
77 		/*
78 		if (MBEDTLS_OID_CMP(type, &name->oid)) {
79 			name = name->next;
80 			continue;
81 		}
82 */
83 		lws_strnncpy(&buf->ns.name[buf->ns.len],
84 			     (const char *)name->MBEDTLS_PRIVATE(val).MBEDTLS_PRIVATE(p),
85 			     name->MBEDTLS_PRIVATE(val).MBEDTLS_PRIVATE(len),
86 			     len - (size_t)buf->ns.len);
87 		buf->ns.len = (int)strlen(buf->ns.name);
88 
89 		r = 0;
90 		name = name->MBEDTLS_PRIVATE(next);
91 	}
92 
93 	return r;
94 }
95 
96 
97 int
lws_tls_mbedtls_cert_info(mbedtls_x509_crt * x509,enum lws_tls_cert_info type,union lws_tls_cert_info_results * buf,size_t len)98 lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type,
99 			  union lws_tls_cert_info_results *buf, size_t len)
100 {
101 	mbedtls_x509_buf skid;
102 	lws_mbedtls_x509_authority akid;
103 
104 	if (!x509)
105 		return -1;
106 
107 	if (!len)
108 		len = sizeof(buf->ns.name);
109 
110 	switch (type) {
111 	case LWS_TLS_CERT_INFO_VALIDITY_FROM:
112 		buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE(valid_from));
113 		if (buf->time == (time_t)(long long)-1)
114 			return -1;
115 		break;
116 
117 	case LWS_TLS_CERT_INFO_VALIDITY_TO:
118 		buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE(valid_to));
119 		if (buf->time == (time_t)(long long)-1)
120 			return -1;
121 		break;
122 
123 	case LWS_TLS_CERT_INFO_COMMON_NAME:
124 		return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE(subject), buf, len);
125 
126 	case LWS_TLS_CERT_INFO_ISSUER_NAME:
127 		return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE(issuer), buf, len);
128 
129 	case LWS_TLS_CERT_INFO_USAGE:
130 		buf->usage = x509->MBEDTLS_PRIVATE(key_usage);
131 		break;
132 
133 	case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY:
134 	{
135 		char *p = buf->ns.name;
136 		size_t r = len, u;
137 
138 		switch (mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE(pk))) {
139 		case MBEDTLS_PK_RSA:
140 		{
141 			mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509->MBEDTLS_PRIVATE(pk));
142 
143 			if (mbedtls_mpi_write_string(&rsa->MBEDTLS_PRIVATE(N), 16, p, r, &u))
144 				return -1;
145 			r -= u;
146 			p += u;
147 			if (mbedtls_mpi_write_string(&rsa->MBEDTLS_PRIVATE(E), 16, p, r, &u))
148 				return -1;
149 
150 			p += u;
151 			buf->ns.len = lws_ptr_diff(p, buf->ns.name);
152 			break;
153 		}
154 		case MBEDTLS_PK_ECKEY:
155 		{
156 			mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(x509->MBEDTLS_PRIVATE(pk));
157 
158 			if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), 16, p, r, &u))
159 				 return -1;
160 			r -= u;
161 			p += u;
162 			if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), 16, p, r, &u))
163 				 return -1;
164 			r -= u;
165 			p += u;
166 			if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 16, p, r, &u))
167 				 return -1;
168 			p += u;
169 			buf->ns.len = lws_ptr_diff(p, buf->ns.name);
170 			break;
171 		}
172 		default:
173 			lwsl_notice("%s: x509 has unsupported pubkey type %d\n",
174 				    __func__,
175 				    mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE(pk)));
176 
177 			return -1;
178 		}
179 		break;
180 	}
181 	case LWS_TLS_CERT_INFO_DER_RAW:
182 
183 		buf->ns.len = (int)x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len);
184 
185 		if (len < x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))
186 			/*
187 			 * The buffer is too small and the attempt failed, but
188 			 * the required object length is in buf->ns.len
189 			 */
190 			return -1;
191 
192 		memcpy(buf->ns.name, x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
193 				x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len));
194 		break;
195 
196 	case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID:
197 
198 		memset(&akid, 0, sizeof(akid));
199 		memset(&skid, 0, sizeof(skid));
200 
201 		lws_x509_get_crt_ext(x509, &skid, &akid);
202 		if (akid.keyIdentifier.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING)
203 			return 1;
204 		buf->ns.len = (int)akid.keyIdentifier.MBEDTLS_PRIVATE(len);
205 		if (!akid.keyIdentifier.MBEDTLS_PRIVATE(p) ||
206 		    len < (size_t)buf->ns.len)
207 			return -1;
208 		memcpy(buf->ns.name, akid.keyIdentifier.MBEDTLS_PRIVATE(p), (size_t)buf->ns.len);
209 		break;
210 
211 	case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER: {
212 		mbedtls_x509_sequence * ip;
213 
214 		memset(&akid, 0, sizeof(akid));
215 		memset(&skid, 0, sizeof(skid));
216 
217 		lws_x509_get_crt_ext(x509, &skid, &akid);
218 
219 		ip = &akid.authorityCertIssuer;
220 
221 		buf->ns.len = 0;
222 
223 		while (ip) {
224 			if (akid.keyIdentifier.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING ||
225 			    !ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p) ||
226 			    ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) < 9 ||
227 			    len < (size_t)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9u)
228 			break;
229 
230 			memcpy(buf->ns.name + buf->ns.len, ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p),
231 					(size_t)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9);
232 			buf->ns.len = buf->ns.len + (int)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9;
233 
234 			ip = ip->MBEDTLS_PRIVATE(next);
235 		}
236 		break;
237 	}
238 	case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL:
239 
240 		memset(&akid, 0, sizeof(akid));
241 		memset(&skid, 0, sizeof(skid));
242 
243 		lws_x509_get_crt_ext(x509, &skid, &akid);
244 
245 		if (akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING)
246 			return 1;
247 		buf->ns.len = (int)akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(len);
248 		if (!akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(p) ||
249 		    len < (size_t)buf->ns.len)
250 			return -1;
251 		memcpy(buf->ns.name, akid.authorityCertSerialNumber.
252 					MBEDTLS_PRIVATE(p), (size_t)buf->ns.len);
253 		break;
254 
255 	case LWS_TLS_CERT_INFO_SUBJECT_KEY_ID:
256 
257 		memset(&akid, 0, sizeof(akid));
258 		memset(&skid, 0, sizeof(skid));
259 
260 		lws_x509_get_crt_ext(x509, &skid, &akid);
261 
262 		if (skid.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING)
263 			return 1;
264 		buf->ns.len = (int)skid.MBEDTLS_PRIVATE(len);
265 		if (len < (size_t)buf->ns.len)
266 			return -1;
267 		memcpy(buf->ns.name, skid.MBEDTLS_PRIVATE(p), (size_t)buf->ns.len);
268 		break;
269 	default:
270 		return -1;
271 	}
272 
273 	return 0;
274 }
275 
276 #if defined(LWS_WITH_NETWORK)
277 int
lws_tls_vhost_cert_info(struct lws_vhost * vhost,enum lws_tls_cert_info type,union lws_tls_cert_info_results * buf,size_t len)278 lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
279 		        union lws_tls_cert_info_results *buf, size_t len)
280 {
281 	mbedtls_x509_crt *x509;
282 
283 	x509 = ssl_ctx_get_mbedtls_x509_crt(vhost->tls.ssl_ctx);
284 
285 	return lws_tls_mbedtls_cert_info(x509, type, buf, len);
286 }
287 
288 int
lws_tls_peer_cert_info(struct lws * wsi,enum lws_tls_cert_info type,union lws_tls_cert_info_results * buf,size_t len)289 lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
290 		       union lws_tls_cert_info_results *buf, size_t len)
291 {
292 	mbedtls_x509_crt *x509;
293 
294 	wsi = lws_get_network_wsi(wsi);
295 
296 	x509 = ssl_get_peer_mbedtls_x509_crt(wsi->tls.ssl);
297 
298 	if (!x509)
299 		return -1;
300 
301 	switch (type) {
302 	case LWS_TLS_CERT_INFO_VERIFIED:
303 		buf->verified = SSL_get_verify_result(wsi->tls.ssl) == X509_V_OK;
304 		return 0;
305 	default:
306 		return lws_tls_mbedtls_cert_info(x509, type, buf, len);
307 	}
308 
309 	return -1;
310 }
311 #endif
312 
313 int
lws_x509_info(struct lws_x509_cert * x509,enum lws_tls_cert_info type,union lws_tls_cert_info_results * buf,size_t len)314 lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
315 	      union lws_tls_cert_info_results *buf, size_t len)
316 {
317 	return lws_tls_mbedtls_cert_info(&x509->cert, type, buf, len);
318 }
319 
320 int
lws_x509_create(struct lws_x509_cert ** x509)321 lws_x509_create(struct lws_x509_cert **x509)
322 {
323 	*x509 = lws_malloc(sizeof(**x509), __func__);
324 
325 	return !(*x509);
326 }
327 
328 /*
329  * Parse one DER-encoded or one or more concatenated PEM-encoded certificates
330  * and add them to the chained list.
331  */
332 
333 int
lws_x509_parse_from_pem(struct lws_x509_cert * x509,const void * pem,size_t len)334 lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len)
335 {
336 	int ret;
337 
338 	mbedtls_x509_crt_init(&x509->cert);
339 
340 	ret = mbedtls_x509_crt_parse(&x509->cert, pem, len);
341 	if (ret) {
342 		if (ret > 0)
343 			mbedtls_x509_crt_free(&x509->cert);
344 		lwsl_err("%s: unable to parse PEM cert: -0x%x\n",
345 			 __func__, -ret);
346 
347 		return -1;
348 	}
349 
350 	return 0;
351 }
352 
353 int
lws_x509_verify(struct lws_x509_cert * x509,struct lws_x509_cert * trusted,const char * common_name)354 lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted,
355 		const char *common_name)
356 {
357 	uint32_t flags = 0;
358 	int ret;
359 
360 	ret = mbedtls_x509_crt_verify_with_profile(&x509->cert, &trusted->cert,
361 						   NULL,
362 						   &mbedtls_x509_crt_profile_next,
363 						   common_name, &flags, NULL,
364 						   NULL);
365 
366 	if (ret) {
367 		lwsl_err("%s: unable to parse PEM cert: -0x%x\n",
368 			 __func__, -ret);
369 
370 		return -1;
371 	}
372 
373 	return 0;
374 }
375 
376 #if defined(LWS_WITH_JOSE)
377 
378 int
lws_x509_public_to_jwk(struct lws_jwk * jwk,struct lws_x509_cert * x509,const char * curves,int rsa_min_bits)379 lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
380 		       const char *curves, int rsa_min_bits)
381 {
382 	int kt = (int)mbedtls_pk_get_type(&x509->cert.MBEDTLS_PRIVATE(pk)),
383 			n, count = 0, ret = -1;
384 	mbedtls_rsa_context *rsactx;
385 	mbedtls_ecp_keypair *ecpctx;
386 	mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
387 
388 	memset(jwk, 0, sizeof(*jwk));
389 
390 	switch (kt) {
391 	case MBEDTLS_PK_RSA:
392 		lwsl_notice("%s: RSA key\n", __func__);
393 		jwk->kty = LWS_GENCRYPTO_KTY_RSA;
394 		rsactx = mbedtls_pk_rsa(x509->cert.MBEDTLS_PRIVATE(pk));
395 
396 		mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = &rsactx->MBEDTLS_PRIVATE(E);
397 		mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = &rsactx->MBEDTLS_PRIVATE(N);
398 		mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = &rsactx->MBEDTLS_PRIVATE(D);
399 		mpi[LWS_GENCRYPTO_RSA_KEYEL_P] = &rsactx->MBEDTLS_PRIVATE(P);
400 		mpi[LWS_GENCRYPTO_RSA_KEYEL_Q] = &rsactx->MBEDTLS_PRIVATE(Q);
401 		mpi[LWS_GENCRYPTO_RSA_KEYEL_DP] = &rsactx->MBEDTLS_PRIVATE(DP);
402 		mpi[LWS_GENCRYPTO_RSA_KEYEL_DQ] = &rsactx->MBEDTLS_PRIVATE(DQ);
403 		mpi[LWS_GENCRYPTO_RSA_KEYEL_QI] = &rsactx->MBEDTLS_PRIVATE(QP);
404 
405 		count = LWS_GENCRYPTO_RSA_KEYEL_QI + 1;
406 		n = LWS_GENCRYPTO_RSA_KEYEL_E;
407 		break;
408 
409 	case MBEDTLS_PK_ECKEY:
410 		lwsl_notice("%s: EC key\n", __func__);
411 		jwk->kty = LWS_GENCRYPTO_KTY_EC;
412 		ecpctx = mbedtls_pk_ec(x509->cert.MBEDTLS_PRIVATE(pk));
413 		mpi[LWS_GENCRYPTO_EC_KEYEL_X] = &ecpctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X);
414 		mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->MBEDTLS_PRIVATE(d);
415 		mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = &ecpctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y);
416 
417 		if (lws_genec_confirm_curve_allowed_by_tls_id(curves,
418 				(int)ecpctx->MBEDTLS_PRIVATE(grp).id, jwk))
419 			/* already logged */
420 			goto bail;
421 
422 		count = LWS_GENCRYPTO_EC_KEYEL_COUNT;
423 		n = LWS_GENCRYPTO_EC_KEYEL_X;
424 		break;
425 	default:
426 		lwsl_err("%s: key type %d not supported\n", __func__, kt);
427 
428 		return -1;
429 	}
430 
431 	for (; n < count; n++) {
432 		if (!mbedtls_mpi_size(mpi[n]))
433 			continue;
434 
435 		jwk->e[n].buf = lws_malloc(mbedtls_mpi_size(mpi[n]), "certjwk");
436 		if (!jwk->e[n].buf)
437 			goto bail;
438 		jwk->e[n].len = (uint32_t)mbedtls_mpi_size(mpi[n]);
439 		mbedtls_mpi_write_binary(mpi[n], jwk->e[n].buf, jwk->e[n].len);
440 	}
441 
442 	ret = 0;
443 
444 bail:
445 	/* jwk destroy will clean up partials */
446 	if (ret)
447 		lws_jwk_destroy(jwk);
448 
449 	return ret;
450 }
451 
452 int
lws_x509_jwk_privkey_pem(struct lws_context * cx,struct lws_jwk * jwk,void * pem,size_t len,const char * passphrase)453 lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk,
454 			 void *pem, size_t len, const char *passphrase)
455 {
456 	mbedtls_rsa_context *rsactx;
457 	mbedtls_ecp_keypair *ecpctx;
458 	mbedtls_pk_context pk;
459 	mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
460 	int n, ret = -1, count = 0;
461 
462 	mbedtls_pk_init(&pk);
463 
464 	n = 0;
465 	if (passphrase)
466 		n = (int)strlen(passphrase);
467 	n = mbedtls_pk_parse_key(&pk, pem, len, (uint8_t *)passphrase, (unsigned int)n
468 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
469 					, mbedtls_ctr_drbg_random, &cx->mcdc
470 #endif
471 			);
472 	if (n) {
473 		lwsl_err("%s: parse PEM key failed: -0x%x\n", __func__, -n);
474 
475 		return -1;
476 	}
477 
478 	/* the incoming private key type */
479 	switch (mbedtls_pk_get_type(&pk)) {
480 	case MBEDTLS_PK_RSA:
481 		if (jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
482 			lwsl_err("%s: RSA privkey, non-RSA jwk\n", __func__);
483 			goto bail;
484 		}
485 		rsactx = mbedtls_pk_rsa(pk);
486 		mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = &rsactx->MBEDTLS_PRIVATE(D);
487 		mpi[LWS_GENCRYPTO_RSA_KEYEL_P] = &rsactx->MBEDTLS_PRIVATE(P);
488 		mpi[LWS_GENCRYPTO_RSA_KEYEL_Q] = &rsactx->MBEDTLS_PRIVATE(Q);
489 		n = LWS_GENCRYPTO_RSA_KEYEL_D;
490 		count = LWS_GENCRYPTO_RSA_KEYEL_Q + 1;
491 		break;
492 	case MBEDTLS_PK_ECKEY:
493 		if (jwk->kty != LWS_GENCRYPTO_KTY_EC) {
494 			lwsl_err("%s: EC privkey, non-EC jwk\n", __func__);
495 			goto bail;
496 		}
497 		ecpctx = mbedtls_pk_ec(pk);
498 		mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->MBEDTLS_PRIVATE(d);
499 		n = LWS_GENCRYPTO_EC_KEYEL_D;
500 		count = n + 1;
501 		break;
502 	default:
503 		lwsl_err("%s: unusable key type %d\n", __func__,
504 				mbedtls_pk_get_type(&pk));
505 		goto bail;
506 	}
507 
508 	for (; n < count; n++) {
509 		if (!mbedtls_mpi_size(mpi[n])) {
510 			lwsl_err("%s: empty privkey\n", __func__);
511 			goto bail;
512 		}
513 
514 		jwk->e[n].buf = lws_malloc(mbedtls_mpi_size(mpi[n]), "certjwk");
515 		if (!jwk->e[n].buf)
516 			goto bail;
517 		jwk->e[n].len = (uint32_t)mbedtls_mpi_size(mpi[n]);
518 		mbedtls_mpi_write_binary(mpi[n], jwk->e[n].buf, jwk->e[n].len);
519 	}
520 
521 	ret = 0;
522 
523 bail:
524 	mbedtls_pk_free(&pk);
525 
526 	return ret;
527 }
528 #endif
529 
530 void
lws_x509_destroy(struct lws_x509_cert ** x509)531 lws_x509_destroy(struct lws_x509_cert **x509)
532 {
533 	if (!*x509)
534 		return;
535 
536 	mbedtls_x509_crt_free(&(*x509)->cert);
537 
538 	lws_free_set_NULL(*x509);
539 }
540