• 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 = (int)read(fd, pembuf, (unsigned int)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, (unsigned int)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 #if defined(LWS_WITH_NETWORK)
76 	info.port = CONTEXT_PORT_NO_LISTEN;
77 #endif
78 	info.options = 0;
79 
80 	context = lws_create_context(&info);
81 	if (!context) {
82 		lwsl_err("lws init failed\n");
83 		return 1;
84 	}
85 
86 
87 	p = lws_cmdline_option(argc, argv, "-c");
88 	if (!p) {
89 		lwsl_err("%s: missing -c <cert pem file>\n", __func__);
90 		goto bail;
91 	}
92 	if (read_pem_c509_cert(&x509, p, pembuf, sizeof(pembuf))) {
93 		lwsl_err("%s: unable to read \"%s\": errno %d\n",
94 			 __func__, p, errno);
95 		goto bail;
96 	}
97 
98 	p = lws_cmdline_option(argc, argv, "-t");
99 	if (p) {
100 
101 		if (read_pem_c509_cert(&x509_trusted, p, pembuf,
102 				       sizeof(pembuf))) {
103 			lwsl_err("%s: unable to read \"%s\": errno %d\n",
104 				 __func__, p, errno);
105 			goto bail1;
106 		}
107 
108 		lwsl_notice("%s: certs loaded OK\n", __func__);
109 
110 		if (lws_x509_verify(x509, x509_trusted, NULL)) {
111 			lwsl_err("%s: verify failed\n", __func__);
112 			goto bail2;
113 		}
114 
115 		lwsl_notice("%s: verified OK\n", __func__);
116 	}
117 
118 	if (x509_trusted) {
119 
120 		/* show the trusted cert public key as a JWK */
121 
122 		if (lws_x509_public_to_jwk(&jwk, x509_trusted,
123 					   "P-256,P-384,P-521", 4096)) {
124 			lwsl_err("%s: unable to get trusted cert pubkey as JWK\n",
125 				 __func__);
126 
127 			goto bail2;
128 		}
129 
130 		if ((p = lws_cmdline_option(argc, argv, "--alg")))
131 			lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
132 
133 		lwsl_info("JWK version of trusted cert:\n");
134 		lws_jwk_dump(&jwk);
135 		lws_jwk_destroy(&jwk);
136 	}
137 
138 	/* get the cert public key as a JWK */
139 
140 	if (lws_x509_public_to_jwk(&jwk, x509, "P-256,P-384,P-521", 4096)) {
141 		lwsl_err("%s: unable to get cert pubkey as JWK\n", __func__);
142 
143 		goto bail3;
144 	}
145 	lwsl_info("JWK version of cert:\n");
146 
147 	if ((p = lws_cmdline_option(argc, argv, "--alg")))
148 		lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
149 
150 	lws_jwk_dump(&jwk);
151 	/* only print public if he doesn't provide private */
152 	if (!lws_cmdline_option(argc, argv, "-p")) {
153 		lwsl_notice("Issuing Cert Public JWK on stdout\n");
154 		n = sizeof(pembuf);
155 		if (lws_jwk_export(&jwk, 0, pembuf, &n))
156 			puts(pembuf);
157 	}
158 
159 	/* if we know where the cert private key is, add that to the cert JWK */
160 
161 	p = lws_cmdline_option(argc, argv, "-p");
162 	if (p) {
163 		n = read_pem(p, pembuf, sizeof(pembuf));
164 		if (n < 0) {
165 			lwsl_err("%s: unable read privkey %s\n", __func__, p);
166 
167 			goto bail3;
168 		}
169 		if (lws_x509_jwk_privkey_pem(context, &jwk, pembuf,
170 						(unsigned int)n, NULL)) {
171 			lwsl_err("%s: unable to parse privkey %s\n",
172 					__func__, p);
173 
174 			goto bail3;
175 		}
176 
177 		if ((p = lws_cmdline_option(argc, argv, "--alg")))
178 			lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
179 
180 		lwsl_info("JWK version of cert + privkey:\n");
181 		lws_jwk_dump(&jwk);
182 		lwsl_notice("Issuing Cert + Private JWK on stdout\n");
183 		n = sizeof(pembuf);
184 		if (lws_jwk_export(&jwk, LWSJWKF_EXPORT_PRIVATE, pembuf, &n))
185 			puts(pembuf);
186 	}
187 
188 	result = 0;
189 
190 bail3:
191 	lws_jwk_destroy(&jwk);
192 bail2:
193 	lws_x509_destroy(&x509_trusted);
194 bail1:
195 	lws_x509_destroy(&x509);
196 bail:
197 	lws_context_destroy(context);
198 
199 	if (result)
200 		lwsl_err("%s: failed\n", __func__);
201 	else
202 		lwsl_notice("%s: OK\n", __func__);
203 
204 	return result;
205 }
206