test_cert.c revision b1a7c3f9
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 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 SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1); /* XXX */ 97 if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file)) 98 { 99 LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file); 100 goto end; 101 } 102 103 if (strstr(key_file, ".pkcs8")) 104 { 105 f = fopen(key_file, "r"); 106 if (!f) 107 { 108 LSQ_ERROR("fopen(%s) failed: %s", cert_file, strerror(errno)); 109 goto end; 110 } 111 pkey = d2i_PrivateKey_fp(f, NULL); 112 fclose(f); 113 f = NULL; 114 if (!pkey) 115 { 116 LSQ_ERROR("Reading private key from %s failed", key_file); 117 goto end; 118 } 119 if (!SSL_CTX_use_PrivateKey(cert->ce_ssl_ctx, pkey)) 120 { 121 LSQ_ERROR("SSL_CTX_use_PrivateKey failed"); 122 goto end; 123 } 124 } 125 else if (1 != SSL_CTX_use_PrivateKey_file(cert->ce_ssl_ctx, key_file, 126 SSL_FILETYPE_PEM)) 127 { 128 LSQ_ERROR("SSL_CTX_use_PrivateKey_file failed"); 129 goto end; 130 } 131 132 const int was = SSL_CTX_set_session_cache_mode(cert->ce_ssl_ctx, 1); 133 LSQ_DEBUG("set SSL session cache mode to 1 (was: %d)", was); 134 135 if (lsquic_hash_insert(certs, cert->ce_sni, strlen(cert->ce_sni), cert, 136 &cert->ce_hash_el)) 137 rv = 0; 138 else 139 LSQ_WARN("cannot insert cert for %s into hash table", cert->ce_sni); 140 141 end: 142 free(sni); 143 if (rv != 0) 144 { /* Error: free cert and its components */ 145 if (cert) 146 { 147 free(cert->ce_sni); 148 free(cert); 149 } 150 } 151 return rv; 152} 153 154struct ssl_ctx_st * 155lookup_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED, 156 const char *sni) 157{ 158 struct lsquic_hash_elem *el; 159 struct server_cert *server_cert; 160 161 if (!cert_lu_ctx) 162 return NULL; 163 164 if (sni) 165 el = lsquic_hash_find(cert_lu_ctx, sni, strlen(sni)); 166 else 167 { 168 LSQ_INFO("SNI is not set"); 169 el = lsquic_hash_first(cert_lu_ctx); 170 } 171 172 if (el) 173 { 174 server_cert = lsquic_hashelem_getdata(el); 175 if (server_cert) 176 return server_cert->ce_ssl_ctx; 177 } 178 179 return NULL; 180} 181 182 183void 184delete_certs (struct lsquic_hash *certs) 185{ 186 struct lsquic_hash_elem *el; 187 struct server_cert *cert; 188 189 for (el = lsquic_hash_first(certs); el; el = lsquic_hash_next(certs)) 190 { 191 cert = lsquic_hashelem_getdata(el); 192 SSL_CTX_free(cert->ce_ssl_ctx); 193 free(cert->ce_sni); 194 free(cert); 195 } 196 lsquic_hash_destroy(certs); 197} 198