test_cert.c revision 4051ae3a
1/* Copyright (c) 2017 - 2020 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 int 21select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen, 22 const unsigned char *in, unsigned int inlen, void *arg) 23{ 24 const unsigned char alpn[] = "\x5h3-27\x5h3-28\x5h3-29"; 25 int r; 26 27 r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen, 28 alpn, sizeof(alpn)); 29 if (r == OPENSSL_NPN_NEGOTIATED) 30 return SSL_TLSEXT_ERR_OK; 31 else 32 { 33 LSQ_WARN("no supported protocol can be selected from %.*s", 34 (int) inlen, (char *) in); 35 return SSL_TLSEXT_ERR_ALERT_FATAL; 36 } 37} 38 39 40 41int 42load_cert (struct lsquic_hash *certs, const char *optarg) 43{ 44 int rv = -1; 45 char *sni, *cert_file, *key_file; 46 struct server_cert *cert = NULL; 47 EVP_PKEY *pkey = NULL; 48 FILE *f = NULL; 49 50 sni = strdup(optarg); 51 cert_file = strchr(sni, ','); 52 if (!cert_file) 53 goto end; 54 *cert_file = '\0'; 55 ++cert_file; 56 key_file = strchr(cert_file, ','); 57 if (!key_file) 58 goto end; 59 *key_file = '\0'; 60 ++key_file; 61 62 cert = calloc(1, sizeof(*cert)); 63 cert->ce_sni = strdup(sni); 64 65 cert->ce_ssl_ctx = SSL_CTX_new(TLS_method()); 66 if (!cert->ce_ssl_ctx) 67 { 68 LSQ_ERROR("SSL_CTX_new failed"); 69 goto end; 70 } 71 SSL_CTX_set_min_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION); 72 SSL_CTX_set_max_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION); 73 SSL_CTX_set_default_verify_paths(cert->ce_ssl_ctx); 74 SSL_CTX_set_alpn_select_cb(cert->ce_ssl_ctx, select_alpn, NULL); 75 SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1); /* XXX */ 76 if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file)) 77 { 78 LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file); 79 goto end; 80 } 81 82 if (strstr(key_file, ".pkcs8")) 83 { 84 f = fopen(key_file, "r"); 85 if (!f) 86 { 87 LSQ_ERROR("fopen(%s) failed: %s", cert_file, strerror(errno)); 88 goto end; 89 } 90 pkey = d2i_PrivateKey_fp(f, NULL); 91 fclose(f); 92 f = NULL; 93 if (!pkey) 94 { 95 LSQ_ERROR("Reading private key from %s failed", key_file); 96 goto end; 97 } 98 if (!SSL_CTX_use_PrivateKey(cert->ce_ssl_ctx, pkey)) 99 { 100 LSQ_ERROR("SSL_CTX_use_PrivateKey failed"); 101 goto end; 102 } 103 } 104 else if (1 != SSL_CTX_use_PrivateKey_file(cert->ce_ssl_ctx, key_file, 105 SSL_FILETYPE_PEM)) 106 { 107 LSQ_ERROR("SSL_CTX_use_PrivateKey_file failed"); 108 goto end; 109 } 110 111 const int was = SSL_CTX_set_session_cache_mode(cert->ce_ssl_ctx, 1); 112 LSQ_DEBUG("set SSL session cache mode to 1 (was: %d)", was); 113 114 if (lsquic_hash_insert(certs, cert->ce_sni, strlen(cert->ce_sni), cert, 115 &cert->ce_hash_el)) 116 rv = 0; 117 else 118 LSQ_WARN("cannot insert cert for %s into hash table", cert->ce_sni); 119 120 end: 121 free(sni); 122 if (rv != 0) 123 { /* Error: free cert and its components */ 124 if (cert) 125 { 126 free(cert->ce_sni); 127 free(cert); 128 } 129 } 130 return rv; 131} 132 133struct ssl_ctx_st * 134lookup_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED, 135 const char *sni) 136{ 137 struct lsquic_hash_elem *el; 138 struct server_cert *server_cert; 139 140 if (!cert_lu_ctx) 141 return NULL; 142 143 if (sni) 144 el = lsquic_hash_find(cert_lu_ctx, sni, strlen(sni)); 145 else 146 { 147 LSQ_INFO("SNI is not set"); 148 el = lsquic_hash_first(cert_lu_ctx); 149 } 150 151 if (el) 152 { 153 server_cert = lsquic_hashelem_getdata(el); 154 if (server_cert) 155 return server_cert->ce_ssl_ctx; 156 } 157 158 return NULL; 159} 160 161 162void 163delete_certs (struct lsquic_hash *certs) 164{ 165 struct lsquic_hash_elem *el; 166 struct server_cert *cert; 167 168 for (el = lsquic_hash_first(certs); el; el = lsquic_hash_next(certs)) 169 { 170 cert = lsquic_hashelem_getdata(el); 171 SSL_CTX_free(cert->ce_ssl_ctx); 172 free(cert->ce_sni); 173 free(cert); 174 } 175 lsquic_hash_destroy(certs); 176} 177