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