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