MINOR: ssl: Export functions to manipulate generated certificates
Following functions are now available in the SSL public API:
* ssl_sock_create_cert
* ssl_sock_get_generated_cert
* ssl_sock_set_generated_cert
* ssl_sock_generated_cert_serial
These functions could be used to create a certificate by hand, set it in the
cache used to store generated certificates and retrieve it. Here is an example
(pseudo code):
X509 *cacert = ...;
EVP_PKEY *capkey = ...;
char *servername = ...;
unsigned int serial;
serial = ssl_sock_generated_cert_serial(servername, strlen(servername));
if (!ssl_sock_get_generated_cert(serial, cacert)) {
SSL_CTX *ctx = ssl_sock_create_cert(servername, serial, cacert, capkey);
ssl_sock_set_generated_cert(ctx, serial, cacert);
}
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 75876a2..dfc9925 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1003,7 +1003,9 @@
}
#endif
-static SSL_CTX *
+/* Create a X509 certificate with the specified servername and serial. This
+ * function returns a SSL_CTX object or NULL if an error occurs. */
+SSL_CTX *
ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert, EVP_PKEY *capkey)
{
SSL_CTX *ssl_ctx = NULL;
@@ -1107,6 +1109,44 @@
return NULL;
}
+/* Do a lookup for a certificate in the LRU cache used to store generated
+ * certificates. */
+SSL_CTX *
+ssl_sock_get_generated_cert(unsigned int serial, X509 *cacert)
+{
+ struct lru64 *lru = NULL;
+
+ if (ssl_ctx_lru_tree) {
+ lru = lru64_lookup(serial, ssl_ctx_lru_tree, cacert, 0);
+ if (lru && lru->domain)
+ return (SSL_CTX *)lru->data;
+ }
+ return NULL;
+}
+
+/* Set a certificate int the LRU cache used to store generated certificate. */
+void
+ssl_sock_set_generated_cert(SSL_CTX *ssl_ctx, unsigned int serial, X509 *cacert)
+{
+ struct lru64 *lru = NULL;
+
+ if (ssl_ctx_lru_tree) {
+ lru = lru64_get(serial, ssl_ctx_lru_tree, cacert, 0);
+ if (!lru)
+ return;
+ if (lru->domain && lru->data)
+ lru->free((SSL_CTX *)lru->data);
+ lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
+ }
+}
+
+/* Compute the serial that will be used to create/set/get a certificate. */
+unsigned int
+ssl_sock_generated_cert_serial(void *data, size_t len)
+{
+ return XXH32(data, len, ssl_ctx_lru_seed);
+}
+
static SSL_CTX *
ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf)
{
@@ -1146,6 +1186,21 @@
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (!servername) {
+ struct sockaddr to;
+ int fd;
+
+ if (s->generate_certs &&
+ (fd = SSL_get_fd(ssl)) != -1 &&
+ tcp_get_dst(fd, &to, sizeof(to), 0) != -1) {
+ unsigned int serial = ssl_sock_generated_cert_serial(&to, sizeof(to));
+ SSL_CTX *ctx = ssl_sock_get_generated_cert(serial, s->ca_sign_cert);
+ if (ctx) {
+ /* switch ctx */
+ SSL_set_SSL_CTX(ssl, ctx);
+ return SSL_TLSEXT_ERR_OK;
+ }
+ }
+
return (s->strict_sni ?
SSL_TLSEXT_ERR_ALERT_FATAL :
SSL_TLSEXT_ERR_NOACK);