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