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