1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * lws-crypto-x509
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0
7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication.
8d4afb5ceSopenharmony_ci */
9d4afb5ceSopenharmony_ci
10d4afb5ceSopenharmony_ci#include <libwebsockets.h>
11d4afb5ceSopenharmony_ci#include <sys/types.h>
12d4afb5ceSopenharmony_ci#include <fcntl.h>
13d4afb5ceSopenharmony_ci#include <errno.h>
14d4afb5ceSopenharmony_ci
15d4afb5ceSopenharmony_cistatic int
16d4afb5ceSopenharmony_ciread_pem(const char *filename, char *pembuf, int pembuf_len)
17d4afb5ceSopenharmony_ci{
18d4afb5ceSopenharmony_ci	int n, fd = open(filename, LWS_O_RDONLY);
19d4afb5ceSopenharmony_ci	if (fd == -1)
20d4afb5ceSopenharmony_ci		return -1;
21d4afb5ceSopenharmony_ci
22d4afb5ceSopenharmony_ci	n = (int)read(fd, pembuf, (unsigned int)pembuf_len - 1);
23d4afb5ceSopenharmony_ci	close(fd);
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci	pembuf[n++] = '\0';
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci	return n;
28d4afb5ceSopenharmony_ci}
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_cistatic int
31d4afb5ceSopenharmony_ciread_pem_c509_cert(struct lws_x509_cert **x509, const char *filename,
32d4afb5ceSopenharmony_ci		   char *pembuf, int pembuf_len)
33d4afb5ceSopenharmony_ci{
34d4afb5ceSopenharmony_ci	int n;
35d4afb5ceSopenharmony_ci
36d4afb5ceSopenharmony_ci	n = read_pem(filename, pembuf, pembuf_len);
37d4afb5ceSopenharmony_ci	if (n < 0)
38d4afb5ceSopenharmony_ci		return -1;
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	if (lws_x509_create(x509)) {
41d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to create x509\n", __func__);
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_ci		return -1;
44d4afb5ceSopenharmony_ci	}
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	if (lws_x509_parse_from_pem(*x509, pembuf, (unsigned int)n) < 0) {
47d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to parse PEM %s\n", __func__, filename);
48d4afb5ceSopenharmony_ci		lws_x509_destroy(x509);
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci		return -1;
51d4afb5ceSopenharmony_ci	}
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci	return 0;
54d4afb5ceSopenharmony_ci}
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ciint main(int argc, const char **argv)
57d4afb5ceSopenharmony_ci{
58d4afb5ceSopenharmony_ci	int n, result = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
59d4afb5ceSopenharmony_ci	struct lws_x509_cert *x509 = NULL, *x509_trusted = NULL;
60d4afb5ceSopenharmony_ci	struct lws_context_creation_info info;
61d4afb5ceSopenharmony_ci	struct lws_context *context;
62d4afb5ceSopenharmony_ci	struct lws_jwk jwk;
63d4afb5ceSopenharmony_ci	char pembuf[6144];
64d4afb5ceSopenharmony_ci	const char *p;
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci	memset(&jwk, 0, sizeof(jwk));
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci	if ((p = lws_cmdline_option(argc, argv, "-d")))
69d4afb5ceSopenharmony_ci		logs = atoi(p);
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_ci	lws_set_log_level(logs, NULL);
72d4afb5ceSopenharmony_ci	lwsl_user("LWS X509 api example\n");
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
75d4afb5ceSopenharmony_ci#if defined(LWS_WITH_NETWORK)
76d4afb5ceSopenharmony_ci	info.port = CONTEXT_PORT_NO_LISTEN;
77d4afb5ceSopenharmony_ci#endif
78d4afb5ceSopenharmony_ci	info.options = 0;
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci	context = lws_create_context(&info);
81d4afb5ceSopenharmony_ci	if (!context) {
82d4afb5ceSopenharmony_ci		lwsl_err("lws init failed\n");
83d4afb5ceSopenharmony_ci		return 1;
84d4afb5ceSopenharmony_ci	}
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci	p = lws_cmdline_option(argc, argv, "-c");
88d4afb5ceSopenharmony_ci	if (!p) {
89d4afb5ceSopenharmony_ci		lwsl_err("%s: missing -c <cert pem file>\n", __func__);
90d4afb5ceSopenharmony_ci		goto bail;
91d4afb5ceSopenharmony_ci	}
92d4afb5ceSopenharmony_ci	if (read_pem_c509_cert(&x509, p, pembuf, sizeof(pembuf))) {
93d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to read \"%s\": errno %d\n",
94d4afb5ceSopenharmony_ci			 __func__, p, errno);
95d4afb5ceSopenharmony_ci		goto bail;
96d4afb5ceSopenharmony_ci	}
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	p = lws_cmdline_option(argc, argv, "-t");
99d4afb5ceSopenharmony_ci	if (p) {
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci		if (read_pem_c509_cert(&x509_trusted, p, pembuf,
102d4afb5ceSopenharmony_ci				       sizeof(pembuf))) {
103d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to read \"%s\": errno %d\n",
104d4afb5ceSopenharmony_ci				 __func__, p, errno);
105d4afb5ceSopenharmony_ci			goto bail1;
106d4afb5ceSopenharmony_ci		}
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci		lwsl_notice("%s: certs loaded OK\n", __func__);
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci		if (lws_x509_verify(x509, x509_trusted, NULL)) {
111d4afb5ceSopenharmony_ci			lwsl_err("%s: verify failed\n", __func__);
112d4afb5ceSopenharmony_ci			goto bail2;
113d4afb5ceSopenharmony_ci		}
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci		lwsl_notice("%s: verified OK\n", __func__);
116d4afb5ceSopenharmony_ci	}
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	if (x509_trusted) {
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci		/* show the trusted cert public key as a JWK */
121d4afb5ceSopenharmony_ci
122d4afb5ceSopenharmony_ci		if (lws_x509_public_to_jwk(&jwk, x509_trusted,
123d4afb5ceSopenharmony_ci					   "P-256,P-384,P-521", 4096)) {
124d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to get trusted cert pubkey as JWK\n",
125d4afb5ceSopenharmony_ci				 __func__);
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci			goto bail2;
128d4afb5ceSopenharmony_ci		}
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci		if ((p = lws_cmdline_option(argc, argv, "--alg")))
131d4afb5ceSopenharmony_ci			lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
132d4afb5ceSopenharmony_ci
133d4afb5ceSopenharmony_ci		lwsl_info("JWK version of trusted cert:\n");
134d4afb5ceSopenharmony_ci		lws_jwk_dump(&jwk);
135d4afb5ceSopenharmony_ci		lws_jwk_destroy(&jwk);
136d4afb5ceSopenharmony_ci	}
137d4afb5ceSopenharmony_ci
138d4afb5ceSopenharmony_ci	/* get the cert public key as a JWK */
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	if (lws_x509_public_to_jwk(&jwk, x509, "P-256,P-384,P-521", 4096)) {
141d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to get cert pubkey as JWK\n", __func__);
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci		goto bail3;
144d4afb5ceSopenharmony_ci	}
145d4afb5ceSopenharmony_ci	lwsl_info("JWK version of cert:\n");
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci	if ((p = lws_cmdline_option(argc, argv, "--alg")))
148d4afb5ceSopenharmony_ci		lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	lws_jwk_dump(&jwk);
151d4afb5ceSopenharmony_ci	/* only print public if he doesn't provide private */
152d4afb5ceSopenharmony_ci	if (!lws_cmdline_option(argc, argv, "-p")) {
153d4afb5ceSopenharmony_ci		lwsl_notice("Issuing Cert Public JWK on stdout\n");
154d4afb5ceSopenharmony_ci		n = sizeof(pembuf);
155d4afb5ceSopenharmony_ci		if (lws_jwk_export(&jwk, 0, pembuf, &n))
156d4afb5ceSopenharmony_ci			puts(pembuf);
157d4afb5ceSopenharmony_ci	}
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci	/* if we know where the cert private key is, add that to the cert JWK */
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci	p = lws_cmdline_option(argc, argv, "-p");
162d4afb5ceSopenharmony_ci	if (p) {
163d4afb5ceSopenharmony_ci		n = read_pem(p, pembuf, sizeof(pembuf));
164d4afb5ceSopenharmony_ci		if (n < 0) {
165d4afb5ceSopenharmony_ci			lwsl_err("%s: unable read privkey %s\n", __func__, p);
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci			goto bail3;
168d4afb5ceSopenharmony_ci		}
169d4afb5ceSopenharmony_ci		if (lws_x509_jwk_privkey_pem(context, &jwk, pembuf,
170d4afb5ceSopenharmony_ci						(unsigned int)n, NULL)) {
171d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to parse privkey %s\n",
172d4afb5ceSopenharmony_ci					__func__, p);
173d4afb5ceSopenharmony_ci
174d4afb5ceSopenharmony_ci			goto bail3;
175d4afb5ceSopenharmony_ci		}
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci		if ((p = lws_cmdline_option(argc, argv, "--alg")))
178d4afb5ceSopenharmony_ci			lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci		lwsl_info("JWK version of cert + privkey:\n");
181d4afb5ceSopenharmony_ci		lws_jwk_dump(&jwk);
182d4afb5ceSopenharmony_ci		lwsl_notice("Issuing Cert + Private JWK on stdout\n");
183d4afb5ceSopenharmony_ci		n = sizeof(pembuf);
184d4afb5ceSopenharmony_ci		if (lws_jwk_export(&jwk, LWSJWKF_EXPORT_PRIVATE, pembuf, &n))
185d4afb5ceSopenharmony_ci			puts(pembuf);
186d4afb5ceSopenharmony_ci	}
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci	result = 0;
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_cibail3:
191d4afb5ceSopenharmony_ci	lws_jwk_destroy(&jwk);
192d4afb5ceSopenharmony_cibail2:
193d4afb5ceSopenharmony_ci	lws_x509_destroy(&x509_trusted);
194d4afb5ceSopenharmony_cibail1:
195d4afb5ceSopenharmony_ci	lws_x509_destroy(&x509);
196d4afb5ceSopenharmony_cibail:
197d4afb5ceSopenharmony_ci	lws_context_destroy(context);
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci	if (result)
200d4afb5ceSopenharmony_ci		lwsl_err("%s: failed\n", __func__);
201d4afb5ceSopenharmony_ci	else
202d4afb5ceSopenharmony_ci		lwsl_notice("%s: OK\n", __func__);
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ci	return result;
205d4afb5ceSopenharmony_ci}
206