/src/libwebsockets/lib/tls/openssl/openssl-x509.c
Line | Count | Source |
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 | | #define WIN32_LEAN_AND_MEAN |
26 | | #include "private-lib-core.h" |
27 | | #include "private-lib-tls-openssl.h" |
28 | | |
29 | | #if !defined(LWS_PLAT_OPTEE) |
30 | | static int |
31 | | dec(char c) |
32 | 0 | { |
33 | 0 | return c - '0'; |
34 | 0 | } |
35 | | #endif |
36 | | |
37 | | static time_t |
38 | | lws_tls_openssl_asn1time_to_unix(ASN1_TIME *as) |
39 | 0 | { |
40 | 0 | #if !defined(LWS_PLAT_OPTEE) |
41 | |
|
42 | 0 | const char *p = (const char *)as->data; |
43 | 0 | struct tm t; |
44 | | |
45 | | /* [YY]YYMMDDHHMMSSZ */ |
46 | |
|
47 | 0 | memset(&t, 0, sizeof(t)); |
48 | |
|
49 | 0 | if (strlen(p) == 13) { |
50 | 0 | t.tm_year = (dec(p[0]) * 10) + dec(p[1]); |
51 | 0 | if (t.tm_year < 50) /* RFC5280: 13 char dates will break after 2049 */ |
52 | 0 | t.tm_year += 100; /* struct tm year is -1900, this gives 2000..2049 */ |
53 | 0 | p += 2; |
54 | 0 | } else { |
55 | 0 | t.tm_year = ((dec(p[0]) * 1000) + (dec(p[1]) * 100) + |
56 | 0 | (dec(p[2]) * 10) + dec(p[3])) - 1900; /* struct tm year is -1900 */ |
57 | 0 | p += 4; |
58 | 0 | } |
59 | 0 | t.tm_mon = (dec(p[0]) * 10) + dec(p[1]) - 1; |
60 | 0 | p += 2; |
61 | 0 | t.tm_mday = (dec(p[0]) * 10) + dec(p[1]) - 1; |
62 | 0 | p += 2; |
63 | 0 | t.tm_hour = (dec(p[0]) * 10) + dec(p[1]); |
64 | 0 | p += 2; |
65 | 0 | t.tm_min = (dec(p[0]) * 10) + dec(p[1]); |
66 | 0 | p += 2; |
67 | 0 | t.tm_sec = (dec(p[0]) * 10) + dec(p[1]); |
68 | 0 | t.tm_isdst = 0; |
69 | |
|
70 | 0 | return mktime(&t); |
71 | | #else |
72 | | return (time_t)-1; |
73 | | #endif |
74 | 0 | } |
75 | | |
76 | | #if defined(USE_WOLFSSL) |
77 | | #define AUTHORITY_KEYID WOLFSSL_AUTHORITY_KEYID |
78 | | #endif |
79 | | |
80 | | int |
81 | | lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type, |
82 | | union lws_tls_cert_info_results *buf, size_t len) |
83 | 0 | { |
84 | 0 | #ifndef USE_WOLFSSL |
85 | 0 | const unsigned char *dp; |
86 | 0 | ASN1_OCTET_STRING *val; |
87 | 0 | AUTHORITY_KEYID *akid; |
88 | 0 | X509_EXTENSION *ext; |
89 | 0 | int tag, xclass, r = 1; |
90 | 0 | long xlen, loc; |
91 | 0 | #endif |
92 | 0 | X509_NAME *xn; |
93 | 0 | #if !defined(LWS_PLAT_OPTEE) |
94 | 0 | char *p, *p1; |
95 | 0 | size_t rl; |
96 | 0 | #endif |
97 | |
|
98 | 0 | buf->ns.len = 0; |
99 | |
|
100 | 0 | if (!x509) |
101 | 0 | return -1; |
102 | 0 | if (!len) |
103 | 0 | len = sizeof(buf->ns.name); |
104 | |
|
105 | | #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(X509_get_notBefore) |
106 | | #define X509_get_notBefore(x) X509_getm_notBefore(x) |
107 | | #define X509_get_notAfter(x) X509_getm_notAfter(x) |
108 | | #endif |
109 | |
|
110 | 0 | switch (type) { |
111 | 0 | case LWS_TLS_CERT_INFO_VALIDITY_FROM: |
112 | 0 | buf->time = lws_tls_openssl_asn1time_to_unix( |
113 | 0 | X509_get_notBefore(x509)); |
114 | 0 | if (buf->time == (time_t)-1) |
115 | 0 | return -1; |
116 | 0 | break; |
117 | | |
118 | 0 | case LWS_TLS_CERT_INFO_VALIDITY_TO: |
119 | 0 | buf->time = lws_tls_openssl_asn1time_to_unix( |
120 | 0 | X509_get_notAfter(x509)); |
121 | 0 | if (buf->time == (time_t)-1) |
122 | 0 | return -1; |
123 | 0 | break; |
124 | | |
125 | 0 | case LWS_TLS_CERT_INFO_COMMON_NAME: |
126 | | #if defined(LWS_PLAT_OPTEE) |
127 | | return -1; |
128 | | #else |
129 | 0 | xn = X509_get_subject_name(x509); |
130 | 0 | if (!xn) |
131 | 0 | return -1; |
132 | 0 | X509_NAME_oneline(xn, buf->ns.name, (int)len - 2); |
133 | 0 | p = strstr(buf->ns.name, "/CN="); |
134 | 0 | if (p) { |
135 | 0 | p += 4; |
136 | 0 | p1 = strchr(p, '/'); |
137 | 0 | if (p1) |
138 | 0 | rl = lws_ptr_diff_size_t(p1, p); |
139 | 0 | else |
140 | 0 | rl = strlen(p); |
141 | 0 | memmove(buf->ns.name, p, rl); |
142 | 0 | buf->ns.name[rl] = '\0'; |
143 | 0 | } |
144 | 0 | buf->ns.len = (int)strlen(buf->ns.name); |
145 | 0 | return 0; |
146 | 0 | #endif |
147 | 0 | case LWS_TLS_CERT_INFO_ISSUER_NAME: |
148 | 0 | xn = X509_get_issuer_name(x509); |
149 | 0 | if (!xn) |
150 | 0 | return -1; |
151 | 0 | X509_NAME_oneline(xn, buf->ns.name, (int)len - 1); |
152 | 0 | buf->ns.len = (int)strlen(buf->ns.name); |
153 | 0 | return 0; |
154 | | |
155 | 0 | case LWS_TLS_CERT_INFO_USAGE: |
156 | 0 | #if defined(LWS_HAVE_X509_get_key_usage) |
157 | 0 | buf->usage = X509_get_key_usage(x509); |
158 | 0 | break; |
159 | | #else |
160 | | return -1; |
161 | | #endif |
162 | | |
163 | 0 | case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY: |
164 | 0 | { |
165 | 0 | #ifndef USE_WOLFSSL |
166 | 0 | size_t klen = (unsigned int)i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), NULL); |
167 | 0 | uint8_t *tmp, *ptmp; |
168 | |
|
169 | 0 | if (!klen || klen > len) |
170 | 0 | return -1; |
171 | | |
172 | 0 | tmp = (uint8_t *)OPENSSL_malloc(klen); |
173 | 0 | if (!tmp) |
174 | 0 | return -1; |
175 | | |
176 | 0 | ptmp = tmp; |
177 | 0 | if (i2d_X509_PUBKEY( |
178 | 0 | X509_get_X509_PUBKEY(x509), &ptmp) != (int)klen || |
179 | 0 | !ptmp || lws_ptr_diff(ptmp, tmp) != (int)klen) { |
180 | 0 | lwsl_info("%s: cert public key extraction failed\n", |
181 | 0 | __func__); |
182 | 0 | if (ptmp) |
183 | 0 | OPENSSL_free(tmp); |
184 | |
|
185 | 0 | return -1; |
186 | 0 | } |
187 | | |
188 | 0 | buf->ns.len = (int)klen; |
189 | 0 | memcpy(buf->ns.name, tmp, klen); |
190 | 0 | OPENSSL_free(tmp); |
191 | 0 | #endif |
192 | 0 | return 0; |
193 | 0 | } |
194 | 0 | case LWS_TLS_CERT_INFO_DER_RAW: |
195 | 0 | { |
196 | 0 | int der_len = i2d_X509(x509, NULL); |
197 | 0 | uint8_t *tmp = (uint8_t *)buf->ns.name; |
198 | |
|
199 | 0 | buf->ns.len = der_len < 0 ? 0 : der_len; |
200 | |
|
201 | 0 | if (der_len < 0 || (size_t)der_len > len) |
202 | 0 | return -1; |
203 | | |
204 | 0 | der_len = i2d_X509(x509, &tmp); |
205 | 0 | if (der_len < 0) |
206 | 0 | return -1; |
207 | | |
208 | 0 | return 0; |
209 | 0 | } |
210 | | |
211 | 0 | #ifndef USE_WOLFSSL |
212 | | |
213 | 0 | case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID: |
214 | 0 | loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); |
215 | 0 | if (loc < 0) |
216 | 0 | return 1; |
217 | | |
218 | 0 | ext = X509_get_ext(x509, (int)loc); |
219 | 0 | if (!ext) |
220 | 0 | return 1; |
221 | 0 | #ifndef USE_WOLFSSL |
222 | 0 | akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); |
223 | | #else |
224 | | akid = (AUTHORITY_KEYID *)wolfSSL_X509V3_EXT_d2i(ext); |
225 | | #endif |
226 | 0 | if (!akid || !akid->keyid) |
227 | 0 | return 1; |
228 | 0 | val = akid->keyid; |
229 | 0 | dp = (const unsigned char *)val->data; |
230 | 0 | xlen = val->length; |
231 | |
|
232 | 0 | buf->ns.len = (int)xlen; |
233 | 0 | if (len < (size_t)buf->ns.len) |
234 | 0 | return -1; |
235 | | |
236 | 0 | memcpy(buf->ns.name, dp, (size_t)buf->ns.len); |
237 | |
|
238 | 0 | AUTHORITY_KEYID_free(akid); |
239 | 0 | break; |
240 | | |
241 | 0 | case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER: |
242 | 0 | loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); |
243 | 0 | if (loc < 0) |
244 | 0 | return 1; |
245 | | |
246 | 0 | ext = X509_get_ext(x509, (int)loc); |
247 | 0 | if (!ext) |
248 | 0 | return 1; |
249 | | |
250 | 0 | #ifndef USE_WOLFSSL |
251 | 0 | akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); |
252 | | #else |
253 | | akid = (AUTHORITY_KEYID *)wolfSSL_X509V3_EXT_d2i(ext); |
254 | | #endif |
255 | 0 | if (!akid || !akid->issuer) |
256 | 0 | return 1; |
257 | | |
258 | 0 | #if defined(LWS_HAVE_OPENSSL_STACK) |
259 | 0 | { |
260 | 0 | const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext); |
261 | 0 | STACK_OF(CONF_VALUE) *cv; |
262 | | #if defined(LWS_WITH_BORINGSSL) || defined(LWS_WITH_AWSLC) |
263 | | size_t j; |
264 | | #else |
265 | 0 | int j; |
266 | 0 | #endif |
267 | |
|
268 | 0 | cv = i2v_GENERAL_NAMES((X509V3_EXT_METHOD*)method, akid->issuer, NULL); |
269 | 0 | if (!cv) |
270 | 0 | goto bail_ak; |
271 | | |
272 | 0 | for (j = 0; j < OPENSSL_sk_num((const OPENSSL_STACK *)&cv); j++) { |
273 | 0 | CONF_VALUE *nval = OPENSSL_sk_value((const OPENSSL_STACK *)&cv, j); |
274 | 0 | size_t ln = (nval->name ? strlen(nval->name) : 0), |
275 | 0 | lv = (nval->value ? strlen(nval->value) : 0), |
276 | 0 | l = ln + lv; |
277 | |
|
278 | 0 | if (len > l) { |
279 | 0 | if (nval->name) |
280 | 0 | memcpy(buf->ns.name + buf->ns.len, nval->name, ln); |
281 | 0 | if (nval->value) |
282 | 0 | memcpy(buf->ns.name + buf->ns.len + ln, nval->value, lv); |
283 | 0 | buf->ns.len = (int)((size_t)buf->ns.len + l); |
284 | 0 | len -= l; |
285 | 0 | buf->ns.name[buf->ns.len] = '\0'; |
286 | |
|
287 | 0 | r = 0; |
288 | 0 | } |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | 0 | bail_ak: |
293 | 0 | #endif |
294 | 0 | AUTHORITY_KEYID_free(akid); |
295 | |
|
296 | 0 | return r; |
297 | | |
298 | 0 | case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL: |
299 | 0 | loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); |
300 | 0 | if (loc < 0) |
301 | 0 | return 1; |
302 | | |
303 | 0 | ext = X509_get_ext(x509, (int)loc); |
304 | 0 | if (!ext) |
305 | 0 | return 1; |
306 | 0 | akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); |
307 | 0 | if (!akid || !akid->serial) |
308 | 0 | return 1; |
309 | | |
310 | | #if 0 |
311 | | // need to handle blobs, and ASN1_INTEGER_get_uint64 not |
312 | | // available on older openssl |
313 | | { |
314 | | uint64_t res; |
315 | | if (ASN1_INTEGER_get_uint64(&res, akid->serial) != 1) |
316 | | break; |
317 | | buf->ns.len = lws_snprintf(buf->ns.name, len, "%llu", |
318 | | (unsigned long long)res); |
319 | | } |
320 | | #endif |
321 | 0 | break; |
322 | | |
323 | 0 | case LWS_TLS_CERT_INFO_SUBJECT_KEY_ID: |
324 | |
|
325 | 0 | loc = X509_get_ext_by_NID(x509, NID_subject_key_identifier, -1); |
326 | 0 | if (loc < 0) |
327 | 0 | return 1; |
328 | | |
329 | 0 | ext = X509_get_ext(x509, (int)loc); |
330 | 0 | if (!ext) |
331 | 0 | return 1; |
332 | | |
333 | 0 | val = X509_EXTENSION_get_data(ext); |
334 | 0 | if (!val) |
335 | 0 | return 1; |
336 | | |
337 | | #if defined(USE_WOLFSSL) |
338 | | return 1; |
339 | | #else |
340 | 0 | dp = (const unsigned char *)val->data; |
341 | |
|
342 | 0 | if (ASN1_get_object(&dp, &xlen, |
343 | 0 | &tag, &xclass, val->length) & 0x80) |
344 | 0 | return -1; |
345 | | |
346 | 0 | if (tag != V_ASN1_OCTET_STRING) { |
347 | 0 | lwsl_notice("not octet string %d\n", (int)tag); |
348 | 0 | return 1; |
349 | 0 | } |
350 | 0 | #endif |
351 | 0 | buf->ns.len = (int)xlen; |
352 | 0 | if (len < (size_t)buf->ns.len) |
353 | 0 | return -1; |
354 | | |
355 | 0 | memcpy(buf->ns.name, dp, (size_t)buf->ns.len); |
356 | 0 | break; |
357 | 0 | #endif |
358 | | |
359 | 0 | default: |
360 | 0 | return -1; |
361 | 0 | } |
362 | | |
363 | 0 | return 0; |
364 | 0 | } |
365 | | |
366 | | int |
367 | | lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type, |
368 | | union lws_tls_cert_info_results *buf, size_t len) |
369 | 0 | { |
370 | 0 | return lws_tls_openssl_cert_info(x509->cert, type, buf, len); |
371 | 0 | } |
372 | | |
373 | | #if defined(LWS_WITH_NETWORK) |
374 | | int |
375 | | lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type, |
376 | | union lws_tls_cert_info_results *buf, size_t len) |
377 | 0 | { |
378 | 0 | #if defined(LWS_HAVE_SSL_CTX_get0_certificate) |
379 | 0 | X509 *x509 = SSL_CTX_get0_certificate(vhost->tls.ssl_ctx); |
380 | |
|
381 | 0 | return lws_tls_openssl_cert_info(x509, type, buf, len); |
382 | | #else |
383 | | lwsl_notice("openssl is too old to support %s\n", __func__); |
384 | | |
385 | | return -1; |
386 | | #endif |
387 | 0 | } |
388 | | |
389 | | |
390 | | |
391 | | int |
392 | | lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type, |
393 | | union lws_tls_cert_info_results *buf, size_t len) |
394 | 0 | { |
395 | 0 | int rc = 0; |
396 | 0 | X509 *x509; |
397 | |
|
398 | 0 | wsi = lws_get_network_wsi(wsi); |
399 | |
|
400 | 0 | x509 = SSL_get_peer_certificate(wsi->tls.ssl); |
401 | |
|
402 | 0 | if (!x509) { |
403 | 0 | lwsl_debug("no peer cert\n"); |
404 | |
|
405 | 0 | return -1; |
406 | 0 | } |
407 | | |
408 | 0 | switch (type) { |
409 | 0 | case LWS_TLS_CERT_INFO_VERIFIED: |
410 | 0 | buf->verified = SSL_get_verify_result(wsi->tls.ssl) == |
411 | 0 | X509_V_OK; |
412 | 0 | break; |
413 | 0 | default: |
414 | 0 | rc = lws_tls_openssl_cert_info(x509, type, buf, len); |
415 | 0 | } |
416 | | |
417 | 0 | X509_free(x509); |
418 | |
|
419 | 0 | return rc; |
420 | 0 | } |
421 | | #endif |
422 | | |
423 | | int |
424 | | lws_x509_create(struct lws_x509_cert **x509) |
425 | 0 | { |
426 | 0 | *x509 = lws_malloc(sizeof(**x509), __func__); |
427 | 0 | if (*x509) |
428 | 0 | (*x509)->cert = NULL; |
429 | |
|
430 | 0 | return !(*x509); |
431 | 0 | } |
432 | | |
433 | | int |
434 | | lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len) |
435 | 0 | { |
436 | 0 | BIO* bio = BIO_new(BIO_s_mem()); |
437 | |
|
438 | 0 | BIO_write(bio, pem, (int)len); |
439 | 0 | x509->cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); |
440 | 0 | BIO_free(bio); |
441 | 0 | if (!x509->cert) { |
442 | 0 | lwsl_err("%s: unable to parse PEM cert\n", __func__); |
443 | 0 | lws_tls_err_describe_clear(); |
444 | |
|
445 | 0 | return -1; |
446 | 0 | } |
447 | | |
448 | 0 | return 0; |
449 | 0 | } |
450 | | |
451 | | int |
452 | | lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted, |
453 | | const char *common_name) |
454 | 0 | { |
455 | 0 | char c[32], *p; |
456 | 0 | int ret; |
457 | |
|
458 | 0 | if (common_name) { |
459 | 0 | X509_NAME *xn = X509_get_subject_name(x509->cert); |
460 | 0 | if (!xn) |
461 | 0 | return -1; |
462 | 0 | X509_NAME_oneline(xn, c, (int)sizeof(c) - 2); |
463 | 0 | p = strstr(c, "/CN="); |
464 | 0 | if (p) |
465 | 0 | p = p + 4; |
466 | 0 | else |
467 | 0 | p = c; |
468 | |
|
469 | 0 | if (strcmp(p, common_name)) { |
470 | 0 | lwsl_err("%s: common name mismatch\n", __func__); |
471 | 0 | return -1; |
472 | 0 | } |
473 | 0 | } |
474 | | |
475 | 0 | ret = X509_check_issued(trusted->cert, x509->cert); |
476 | 0 | if (ret != X509_V_OK) { |
477 | 0 | lwsl_err("%s: unable to verify cert relationship\n", __func__); |
478 | 0 | lws_tls_err_describe_clear(); |
479 | |
|
480 | 0 | return -1; |
481 | 0 | } |
482 | | |
483 | 0 | return 0; |
484 | 0 | } |
485 | | |
486 | | #if defined(LWS_WITH_JOSE) |
487 | | int |
488 | | lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509, |
489 | | const char *curves, int rsa_min_bits) |
490 | | { |
491 | | int id, n, ret = -1, count; |
492 | | ASN1_OBJECT *obj = NULL; |
493 | | const EC_POINT *ecpoint; |
494 | | const EC_GROUP *ecgroup; |
495 | | EC_KEY *ecpub = NULL; |
496 | | X509_PUBKEY *pubkey; |
497 | | RSA *rsapub = NULL; |
498 | | BIGNUM *mpi[4]; |
499 | | EVP_PKEY *pkey; |
500 | | |
501 | | memset(jwk, 0, sizeof(*jwk)); |
502 | | |
503 | | pubkey = X509_get_X509_PUBKEY(x509->cert); |
504 | | if (!pubkey) { |
505 | | lwsl_err("%s: missing pubkey alg in cert\n", __func__); |
506 | | |
507 | | goto bail; |
508 | | } |
509 | | |
510 | | if (X509_PUBKEY_get0_param(&obj, NULL, NULL, NULL, pubkey) != 1) { |
511 | | lwsl_err("%s: missing pubkey alg in cert\n", __func__); |
512 | | |
513 | | goto bail; |
514 | | } |
515 | | |
516 | | id = OBJ_obj2nid(obj); |
517 | | if (id == NID_undef) { |
518 | | lwsl_err("%s: missing pubkey alg in cert\n", __func__); |
519 | | |
520 | | goto bail; |
521 | | } |
522 | | |
523 | | lwsl_debug("%s: key type %d \"%s\"\n", __func__, id, OBJ_nid2ln(id)); |
524 | | |
525 | | pkey = X509_get_pubkey(x509->cert); |
526 | | if (!pkey) { |
527 | | lwsl_notice("%s: unable to extract pubkey", __func__); |
528 | | |
529 | | goto bail; |
530 | | } |
531 | | |
532 | | switch (id) { |
533 | | case NID_X9_62_id_ecPublicKey: |
534 | | lwsl_debug("%s: EC key\n", __func__); |
535 | | jwk->kty = LWS_GENCRYPTO_KTY_EC; |
536 | | |
537 | | if (!curves) { |
538 | | lwsl_err("%s: ec curves not allowed\n", __func__); |
539 | | |
540 | | goto bail1; |
541 | | } |
542 | | |
543 | | ecpub = EVP_PKEY_get1_EC_KEY(pkey); |
544 | | if (!ecpub) { |
545 | | lwsl_notice("%s: missing EC pubkey\n", __func__); |
546 | | |
547 | | goto bail1; |
548 | | } |
549 | | |
550 | | ecpoint = EC_KEY_get0_public_key(ecpub); |
551 | | if (!ecpoint) { |
552 | | lwsl_err("%s: EC_KEY_get0_public_key failed\n", __func__); |
553 | | goto bail2; |
554 | | } |
555 | | |
556 | | ecgroup = EC_KEY_get0_group(ecpub); |
557 | | if (!ecgroup) { |
558 | | lwsl_err("%s: EC_KEY_get0_group failed\n", __func__); |
559 | | goto bail2; |
560 | | } |
561 | | |
562 | | /* validate the curve against ones we allow */ |
563 | | |
564 | | if (lws_genec_confirm_curve_allowed_by_tls_id(curves, |
565 | | EC_GROUP_get_curve_name(ecgroup), jwk)) |
566 | | /* already logged */ |
567 | | goto bail2; |
568 | | |
569 | | mpi[LWS_GENCRYPTO_EC_KEYEL_CRV] = NULL; |
570 | | mpi[LWS_GENCRYPTO_EC_KEYEL_X] = BN_new(); /* X */ |
571 | | mpi[LWS_GENCRYPTO_EC_KEYEL_D] = NULL; |
572 | | mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = BN_new(); /* Y */ |
573 | | |
574 | | #if defined(LWS_HAVE_EC_POINT_get_affine_coordinates) |
575 | | if (EC_POINT_get_affine_coordinates(ecgroup, ecpoint, |
576 | | #else |
577 | | if (EC_POINT_get_affine_coordinates_GFp(ecgroup, ecpoint, |
578 | | #endif |
579 | | mpi[LWS_GENCRYPTO_EC_KEYEL_X], |
580 | | mpi[LWS_GENCRYPTO_EC_KEYEL_Y], |
581 | | NULL) != 1) { |
582 | | BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]); |
583 | | BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]); |
584 | | lwsl_err("%s: EC_POINT_get_aff failed\n", __func__); |
585 | | goto bail2; |
586 | | } |
587 | | count = LWS_GENCRYPTO_EC_KEYEL_COUNT; |
588 | | n = LWS_GENCRYPTO_EC_KEYEL_X; |
589 | | break; |
590 | | |
591 | | case NID_rsaEncryption: |
592 | | lwsl_debug("%s: rsa key\n", __func__); |
593 | | jwk->kty = LWS_GENCRYPTO_KTY_RSA; |
594 | | |
595 | | rsapub = EVP_PKEY_get1_RSA(pkey); |
596 | | if (!rsapub) { |
597 | | lwsl_notice("%s: missing RSA pubkey\n", __func__); |
598 | | |
599 | | goto bail1; |
600 | | } |
601 | | |
602 | | if ((size_t)RSA_size(rsapub) * 8 < (size_t)rsa_min_bits) { |
603 | | lwsl_err("%s: key bits %d less than minimum %d\n", |
604 | | __func__, RSA_size(rsapub) * 8, rsa_min_bits); |
605 | | |
606 | | goto bail2; |
607 | | } |
608 | | |
609 | | #if defined(LWS_HAVE_RSA_SET0_KEY) |
610 | | /* we don't need d... but the api wants to write it */ |
611 | | RSA_get0_key(rsapub, |
612 | | (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_N], |
613 | | (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_E], |
614 | | (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_D]); |
615 | | #else |
616 | | mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = rsapub->e; |
617 | | mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = rsapub->n; |
618 | | mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = NULL; |
619 | | #endif |
620 | | count = LWS_GENCRYPTO_RSA_KEYEL_D; |
621 | | n = LWS_GENCRYPTO_RSA_KEYEL_E; |
622 | | break; |
623 | | default: |
624 | | lwsl_err("%s: unknown NID\n", __func__); |
625 | | goto bail2; |
626 | | } |
627 | | |
628 | | for (; n < count; n++) { |
629 | | if (!mpi[n]) |
630 | | continue; |
631 | | jwk->e[n].len = (unsigned int)BN_num_bytes(mpi[n]); |
632 | | jwk->e[n].buf = lws_malloc(jwk->e[n].len, "certkeyimp"); |
633 | | if (!jwk->e[n].buf) { |
634 | | if (id == NID_X9_62_id_ecPublicKey) { |
635 | | BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]); |
636 | | BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]); |
637 | | } |
638 | | goto bail2; |
639 | | } |
640 | | BN_bn2bin(mpi[n], jwk->e[n].buf); |
641 | | } |
642 | | |
643 | | if (id == NID_X9_62_id_ecPublicKey) { |
644 | | BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]); |
645 | | BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]); |
646 | | } |
647 | | |
648 | | ret = 0; |
649 | | |
650 | | bail2: |
651 | | if (id == NID_X9_62_id_ecPublicKey) |
652 | | EC_KEY_free(ecpub); |
653 | | else |
654 | | RSA_free(rsapub); |
655 | | |
656 | | bail1: |
657 | | EVP_PKEY_free(pkey); |
658 | | bail: |
659 | | /* jwk destroy will clean any partial state */ |
660 | | if (ret) |
661 | | lws_jwk_destroy(jwk); |
662 | | |
663 | | return ret; |
664 | | } |
665 | | |
666 | | static int |
667 | | lws_x509_jwk_privkey_pem_pp_cb(char *buf, int size, int rwflag, void *u) |
668 | | { |
669 | | const char *pp = (const char *)u; |
670 | | size_t n = strlen(pp); |
671 | | |
672 | | if ((int)n > size - 1) |
673 | | return -1; |
674 | | |
675 | | memcpy(buf, pp, n + 1); |
676 | | |
677 | | return (int)n; |
678 | | } |
679 | | |
680 | | int |
681 | | lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk, |
682 | | void *pem, size_t len, const char *passphrase) |
683 | | { |
684 | | BIO* bio = BIO_new(BIO_s_mem()); |
685 | | BIGNUM *mpi, *dummy[6]; |
686 | | EVP_PKEY *pkey = NULL; |
687 | | EC_KEY *ecpriv = NULL; |
688 | | RSA *rsapriv = NULL; |
689 | | const BIGNUM *cmpi; |
690 | | int n, m, ret = -1; |
691 | | |
692 | | BIO_write(bio, pem, (int)len); |
693 | | PEM_read_bio_PrivateKey(bio, &pkey, lws_x509_jwk_privkey_pem_pp_cb, |
694 | | (void *)passphrase); |
695 | | BIO_free(bio); |
696 | | lws_explicit_bzero((void *)pem, len); |
697 | | if (!pkey) { |
698 | | lwsl_err("%s: unable to parse PEM privkey\n", __func__); |
699 | | lws_tls_err_describe_clear(); |
700 | | |
701 | | return -1; |
702 | | } |
703 | | |
704 | | /* confirm the key type matches the existing jwk situation */ |
705 | | |
706 | | switch (jwk->kty) { |
707 | | case LWS_GENCRYPTO_KTY_EC: |
708 | | if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) { |
709 | | lwsl_err("%s: jwk is EC but privkey isn't\n", __func__); |
710 | | |
711 | | goto bail; |
712 | | } |
713 | | ecpriv = EVP_PKEY_get1_EC_KEY(pkey); |
714 | | if (!ecpriv) { |
715 | | lwsl_notice("%s: missing EC key\n", __func__); |
716 | | |
717 | | goto bail; |
718 | | } |
719 | | |
720 | | cmpi = EC_KEY_get0_private_key(ecpriv); |
721 | | |
722 | | /* quick size check first */ |
723 | | |
724 | | n = BN_num_bytes(cmpi); |
725 | | if (jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != (uint32_t)n) { |
726 | | lwsl_err("%s: jwk key size doesn't match\n", __func__); |
727 | | |
728 | | goto bail1; |
729 | | } |
730 | | |
731 | | /* TODO.. check public curve / group + point */ |
732 | | |
733 | | jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len = (unsigned int)n; |
734 | | jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf = lws_malloc((unsigned int)n, "ec"); |
735 | | if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf) |
736 | | goto bail1; |
737 | | |
738 | | m = BN_bn2binpad(cmpi, jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, |
739 | | (int32_t)jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len); |
740 | | if ((unsigned int)m != (unsigned int)BN_num_bytes(cmpi)) |
741 | | goto bail1; |
742 | | |
743 | | break; |
744 | | |
745 | | case LWS_GENCRYPTO_KTY_RSA: |
746 | | if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_RSA) { |
747 | | lwsl_err("%s: RSA jwk, non-RSA privkey\n", __func__); |
748 | | |
749 | | goto bail; |
750 | | } |
751 | | rsapriv = EVP_PKEY_get1_RSA(pkey); |
752 | | if (!rsapriv) { |
753 | | lwsl_notice("%s: missing RSA key\n", __func__); |
754 | | |
755 | | goto bail; |
756 | | } |
757 | | |
758 | | #if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL) |
759 | | RSA_get0_key(rsapriv, (const BIGNUM **)&dummy[0], /* n */ |
760 | | (const BIGNUM **)&dummy[1], /* e */ |
761 | | (const BIGNUM **)&mpi); /* d */ |
762 | | RSA_get0_factors(rsapriv, (const BIGNUM **)&dummy[4], /* p */ |
763 | | (const BIGNUM **)&dummy[5]); /* q */ |
764 | | #else |
765 | | dummy[0] = rsapriv->n; |
766 | | dummy[1] = rsapriv->e; |
767 | | dummy[4] = rsapriv->p; |
768 | | dummy[5] = rsapriv->q; |
769 | | mpi = rsapriv->d; |
770 | | #endif |
771 | | |
772 | | /* quick size check first */ |
773 | | |
774 | | n = BN_num_bytes(mpi); |
775 | | if (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len != (uint32_t)n) { |
776 | | lwsl_err("%s: jwk key size doesn't match\n", __func__); |
777 | | |
778 | | goto bail1; |
779 | | } |
780 | | |
781 | | /* then check that n & e match what we got from the cert */ |
782 | | |
783 | | dummy[2] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].buf, |
784 | | SSL_SIZE_CAST(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len), |
785 | | NULL); |
786 | | dummy[3] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf, |
787 | | SSL_SIZE_CAST(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len), |
788 | | NULL); |
789 | | |
790 | | m = BN_cmp(dummy[2], dummy[0]) | BN_cmp(dummy[3], dummy[1]); |
791 | | BN_clear_free(dummy[2]); |
792 | | BN_clear_free(dummy[3]); |
793 | | if (m) { |
794 | | lwsl_err("%s: privkey doesn't match jwk pubkey\n", |
795 | | __func__); |
796 | | |
797 | | goto bail1; |
798 | | } |
799 | | |
800 | | /* accept d from the PEM privkey into the JWK */ |
801 | | |
802 | | jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].len = (unsigned int)n; |
803 | | jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf = lws_malloc((unsigned int)n, "privjk"); |
804 | | if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) |
805 | | goto bail1; |
806 | | |
807 | | BN_bn2bin(mpi, jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf); |
808 | | |
809 | | /* accept p and q from the PEM privkey into the JWK */ |
810 | | |
811 | | jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].len = (unsigned int)BN_num_bytes(dummy[4]); |
812 | | jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf = lws_malloc((unsigned int)n, "privjk"); |
813 | | if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) { |
814 | | lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf); |
815 | | goto bail1; |
816 | | } |
817 | | BN_bn2bin(dummy[4], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf); |
818 | | |
819 | | jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].len = (unsigned int)BN_num_bytes(dummy[5]); |
820 | | jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf = lws_malloc((unsigned int)n, "privjk"); |
821 | | if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf) { |
822 | | lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf); |
823 | | lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf); |
824 | | goto bail1; |
825 | | } |
826 | | BN_bn2bin(dummy[5], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf); |
827 | | break; |
828 | | default: |
829 | | lwsl_err("%s: JWK has unknown kty %d\n", __func__, jwk->kty); |
830 | | return -1; |
831 | | } |
832 | | |
833 | | ret = 0; |
834 | | |
835 | | bail1: |
836 | | if (jwk->kty == LWS_GENCRYPTO_KTY_EC) |
837 | | EC_KEY_free(ecpriv); |
838 | | else |
839 | | RSA_free(rsapriv); |
840 | | |
841 | | bail: |
842 | | EVP_PKEY_free(pkey); |
843 | | |
844 | | return ret; |
845 | | } |
846 | | #endif |
847 | | |
848 | | void |
849 | | lws_x509_destroy(struct lws_x509_cert **x509) |
850 | 0 | { |
851 | 0 | if (!*x509) |
852 | 0 | return; |
853 | | |
854 | 0 | if ((*x509)->cert) { |
855 | 0 | X509_free((*x509)->cert); |
856 | 0 | (*x509)->cert = NULL; |
857 | 0 | } |
858 | |
|
859 | | lws_free_set_NULL(*x509); |
860 | 0 | } |