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