test_cert.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <errno.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <sys/queue.h> 7 8#include <openssl/pem.h> 9#include <openssl/x509.h> 10#include <openssl/ssl.h> 11 12#include "lsquic_types.h" 13#include "lsquic.h" 14#include "../src/liblsquic/lsquic_logger.h" 15#include "../src/liblsquic/lsquic_hash.h" 16 17#include "test_cert.h" 18 19 20static char s_alpn[0x100]; 21 22int 23add_alpn (const char *alpn) 24{ 25 size_t alpn_len, all_len; 26 27 alpn_len = strlen(alpn); 28 if (alpn_len > 255) 29 return -1; 30 31 all_len = strlen(s_alpn); 32 if (all_len + 1 + alpn_len + 1 > sizeof(s_alpn)) 33 return -1; 34 35 s_alpn[all_len] = alpn_len; 36 memcpy(&s_alpn[all_len + 1], alpn, alpn_len); 37 s_alpn[all_len + 1 + alpn_len] = '\0'; 38 return 0; 39} 40 41 42static int 43select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen, 44 const unsigned char *in, unsigned int inlen, void *arg) 45{ 46 int r; 47 48 r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen, 49 (unsigned char *) s_alpn, strlen(s_alpn)); 50 if (r == OPENSSL_NPN_NEGOTIATED) 51 return SSL_TLSEXT_ERR_OK; 52 else 53 { 54 LSQ_WARN("no supported protocol can be selected from %.*s", 55 (int) inlen, (char *) in); 56 return SSL_TLSEXT_ERR_ALERT_FATAL; 57 } 58} 59 60 61 62int 63load_cert (struct lsquic_hash *certs, const char *optarg) 64{ 65 int rv = -1; 66 char *sni, *cert_file, *key_file; 67 struct server_cert *cert = NULL; 68 EVP_PKEY *pkey = NULL; 69 FILE *f = NULL; 70 71 sni = strdup(optarg); 72 cert_file = strchr(sni, ','); 73 if (!cert_file) 74 goto end; 75 *cert_file = '\0'; 76 ++cert_file; 77 key_file = strchr(cert_file, ','); 78 if (!key_file) 79 goto end; 80 *key_file = '\0'; 81 ++key_file; 82 83 cert = calloc(1, sizeof(*cert)); 84 cert->ce_sni = strdup(sni); 85 86 cert->ce_ssl_ctx = SSL_CTX_new(TLS_method()); 87 if (!cert->ce_ssl_ctx) 88 { 89 LSQ_ERROR("SSL_CTX_new failed"); 90 goto end; 91 } 92 SSL_CTX_set_min_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION); 93 SSL_CTX_set_max_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION); 94 SSL_CTX_set_default_verify_paths(cert->ce_ssl_ctx); 95 SSL_CTX_set_alpn_select_cb(cert->ce_ssl_ctx, select_alpn, NULL); 96 { 97 const char *const s = getenv("LSQUIC_ENABLE_EARLY_DATA"); 98 if (!s || atoi(s)) 99 SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1); /* XXX */ 100 } 101 if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file)) 102 { 103 LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file); 104 goto end; 105 } 106 107 if (strstr(key_file, ".pkcs8")) 108 { 109 f = fopen(key_file, "r"); 110 if (!f) 111 { 112 LSQ_ERROR("fopen(%s) failed: %s", cert_file, strerror(errno)); 113 goto end; 114 } 115 pkey = d2i_PrivateKey_fp(f, NULL); 116 fclose(f); 117 f = NULL; 118 if (!pkey) 119 { 120 LSQ_ERROR("Reading private key from %s failed", key_file); 121 goto end; 122 } 123 if (!SSL_CTX_use_PrivateKey(cert->ce_ssl_ctx, pkey)) 124 { 125 LSQ_ERROR("SSL_CTX_use_PrivateKey failed"); 126 goto end; 127 } 128 } 129 else if (1 != SSL_CTX_use_PrivateKey_file(cert->ce_ssl_ctx, key_file, 130 SSL_FILETYPE_PEM)) 131 { 132 LSQ_ERROR("SSL_CTX_use_PrivateKey_file failed"); 133 goto end; 134 } 135 136 const int was = SSL_CTX_set_session_cache_mode(cert->ce_ssl_ctx, 1); 137 LSQ_DEBUG("set SSL session cache mode to 1 (was: %d)", was); 138 139 if (lsquic_hash_insert(certs, cert->ce_sni, strlen(cert->ce_sni), cert, 140 &cert->ce_hash_el)) 141 rv = 0; 142 else 143 LSQ_WARN("cannot insert cert for %s into hash table", cert->ce_sni); 144 145 end: 146 free(sni); 147 if (rv != 0) 148 { /* Error: free cert and its components */ 149 if (cert) 150 { 151 free(cert->ce_sni); 152 free(cert); 153 } 154 } 155 return rv; 156} 157 158struct ssl_ctx_st * 159lookup_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED, 160 const char *sni) 161{ 162 struct lsquic_hash_elem *el; 163 struct server_cert *server_cert; 164 165 if (!cert_lu_ctx) 166 return NULL; 167 168 if (sni) 169 el = lsquic_hash_find(cert_lu_ctx, sni, strlen(sni)); 170 else 171 { 172 LSQ_INFO("SNI is not set"); 173 el = lsquic_hash_first(cert_lu_ctx); 174 } 175 176 if (el) 177 { 178 server_cert = lsquic_hashelem_getdata(el); 179 if (server_cert) 180 return server_cert->ce_ssl_ctx; 181 } 182 183 return NULL; 184} 185 186 187void 188delete_certs (struct lsquic_hash *certs) 189{ 190 struct lsquic_hash_elem *el; 191 struct server_cert *cert; 192 193 for (el = lsquic_hash_first(certs); el; el = lsquic_hash_next(certs)) 194 { 195 cert = lsquic_hashelem_getdata(el); 196 SSL_CTX_free(cert->ce_ssl_ctx); 197 free(cert->ce_sni); 198 free(cert); 199 } 200 lsquic_hash_destroy(certs); 201} 202