]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: Add support for EC for the CA used to sign generated certificates
authorChristopher Faulet <cfaulet@qualys.com>
Fri, 9 Oct 2015 09:15:03 +0000 (11:15 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 9 Oct 2015 10:13:12 +0000 (12:13 +0200)
This is done by adding EVP_PKEY_EC type in supported types for the CA private
key when we get the message digest used to sign a generated X509 certificate.
So now, we support DSA, RSA and EC private keys.

And to be sure, when the type of the private key is not directly supported, we
get its default message digest using the function
'EVP_PKEY_get_default_digest_nid'.

We also use the key of the default certificate instead of generated it. So we
are sure to use the same key type instead of always using a RSA key.

include/proto/ssl_sock.h
src/ssl_sock.c

index b87758091f375884855ffb6c5c2012620363e015..24b433092089f9159cf27e5382a4a8b6a7d3cfa3 100644 (file)
@@ -71,9 +71,9 @@ void tlskeys_finalize_config(void);
 int ssl_sock_load_global_dh_param_from_file(const char *filename);
 #endif
 
-SSL_CTX *ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert, EVP_PKEY *capkey);
-SSL_CTX *ssl_sock_get_generated_cert(unsigned int serial, X509 *cacert);
-int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int serial, X509 *cacert);
+SSL_CTX *ssl_sock_create_cert(struct connection *conn, const char *servername, unsigned int serial);
+SSL_CTX *ssl_sock_get_generated_cert(unsigned int serial, struct bind_conf *bind_conf);
+int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int serial, struct bind_conf *bind_conf);
 unsigned int ssl_sock_generated_cert_serial(const void *data, size_t len);
 
 #endif /* _PROTO_SSL_SOCK_H */
index 397e46b33225cbdd5fed340680ec6f8d8e992605..e57be110b034080769617a0ed886194b0f4252f7 100644 (file)
@@ -1008,24 +1008,22 @@ static int ssl_sock_advertise_alpn_protos(SSL *s, const unsigned char **out,
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
 /* 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)
+static SSL_CTX *
+ssl_sock_do_create_cert(const char *servername, unsigned int serial,
+                       struct bind_conf *bind_conf, SSL *ssl)
 {
+       X509         *cacert  = bind_conf->ca_sign_cert;
+       EVP_PKEY     *capkey  = bind_conf->ca_sign_pkey;
        SSL_CTX      *ssl_ctx = NULL;
        X509         *newcrt  = NULL;
        EVP_PKEY     *pkey    = NULL;
-       RSA          *rsa;
        X509_NAME    *name;
        const EVP_MD *digest;
        X509V3_CTX    ctx;
        unsigned int  i;
 
-       /* Generate the public key */
-       if (!(rsa = RSA_generate_key(2048, 3, NULL, NULL)))
-               goto mkcert_error;
-       if (!(pkey = EVP_PKEY_new()))
-               goto mkcert_error;
-       if (EVP_PKEY_assign_RSA(pkey, rsa) != 1)
+       /* Get the private key of the defautl certificate and use it */
+       if (!(pkey = SSL_get_privatekey(ssl)))
                goto mkcert_error;
 
        /* Create the certificate */
@@ -1086,8 +1084,17 @@ ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert,
                digest = EVP_dss1();
        else if (EVP_PKEY_type (capkey->type) == EVP_PKEY_RSA)
                digest = EVP_sha256();
-       else
-               goto mkcert_error;
+       else if (EVP_PKEY_type (capkey->type) == EVP_PKEY_EC)
+               digest = EVP_sha256();
+       else {
+               int nid;
+
+               if (EVP_PKEY_get_default_digest_nid(capkey, &nid) <= 0)
+                       goto mkcert_error;
+               if (!(digest = EVP_get_digestbynid(nid)))
+                       goto mkcert_error;
+       }
+
        if (!(X509_sign(newcrt, capkey, digest)))
                goto mkcert_error;
 
@@ -1102,25 +1109,31 @@ ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert,
                goto mkcert_error;
 
        if (newcrt) X509_free(newcrt);
-       if (pkey)   EVP_PKEY_free(pkey);
+
        return ssl_ctx;
 
  mkcert_error:
        if (ssl_ctx) SSL_CTX_free(ssl_ctx);
        if (newcrt)  X509_free(newcrt);
-       if (pkey)    EVP_PKEY_free(pkey);
        return NULL;
 }
 
+SSL_CTX *
+ssl_sock_create_cert(struct connection *conn, const char *servername, unsigned int serial)
+{
+       struct bind_conf *bind_conf = objt_listener(conn->target)->bind_conf;
+       return ssl_sock_do_create_cert(servername, serial, bind_conf, conn->xprt_ctx);
+}
+
 /* 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)
+ssl_sock_get_generated_cert(unsigned int serial, struct bind_conf *bind_conf)
 {
        struct lru64 *lru = NULL;
 
        if (ssl_ctx_lru_tree) {
-               lru = lru64_lookup(serial, ssl_ctx_lru_tree, cacert, 0);
+               lru = lru64_lookup(serial, ssl_ctx_lru_tree, bind_conf->ca_sign_cert, 0);
                if (lru && lru->domain)
                        return (SSL_CTX *)lru->data;
        }
@@ -1130,17 +1143,17 @@ ssl_sock_get_generated_cert(unsigned int serial, X509 *cacert)
 /* Set a certificate int the LRU cache used to store generated
  * certificate. Return 0 on success, otherwise -1 */
 int
-ssl_sock_set_generated_cert(SSL_CTX *ssl_ctx, unsigned int serial, X509 *cacert)
+ssl_sock_set_generated_cert(SSL_CTX *ssl_ctx, unsigned int serial, struct bind_conf *bind_conf)
 {
        struct lru64 *lru = NULL;
 
        if (ssl_ctx_lru_tree) {
-               lru = lru64_get(serial, ssl_ctx_lru_tree, cacert, 0);
+               lru = lru64_get(serial, ssl_ctx_lru_tree, bind_conf->ca_sign_cert, 0);
                if (!lru)
                        return -1;
                if (lru->domain && lru->data)
                        lru->free((SSL_CTX *)lru->data);
-               lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
+               lru64_commit(lru, ssl_ctx, bind_conf->ca_sign_cert, 0, (void (*)(void *))SSL_CTX_free);
                return 0;
        }
        return -1;
@@ -1154,10 +1167,9 @@ ssl_sock_generated_cert_serial(const void *data, size_t len)
 }
 
 static SSL_CTX *
-ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf)
+ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf, SSL *ssl)
 {
        X509         *cacert  = bind_conf->ca_sign_cert;
-       EVP_PKEY     *capkey  = bind_conf->ca_sign_pkey;
        SSL_CTX      *ssl_ctx = NULL;
        struct lru64 *lru     = NULL;
        unsigned int  serial;
@@ -1168,12 +1180,12 @@ ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_con
                if (lru && lru->domain)
                        ssl_ctx = (SSL_CTX *)lru->data;
                if (!ssl_ctx && lru) {
-                       ssl_ctx = ssl_sock_create_cert(servername, serial, cacert, capkey);
+                       ssl_ctx = ssl_sock_do_create_cert(servername, serial, bind_conf, ssl);
                        lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
                }
        }
        else
-               ssl_ctx = ssl_sock_create_cert(servername, serial, cacert, capkey);
+               ssl_ctx = ssl_sock_do_create_cert(servername, serial, bind_conf, ssl);
        return ssl_ctx;
 }
 
@@ -1199,7 +1211,7 @@ static int ssl_sock_switchctx_cbk(SSL *ssl, int *al, struct bind_conf *s)
                        conn_get_to_addr(conn);
                        if (conn->flags & CO_FL_ADDR_TO_SET) {
                                serial = ssl_sock_generated_cert_serial(&conn->addr.to, get_addr_len(&conn->addr.to));
-                               ctx = ssl_sock_get_generated_cert(serial, s->ca_sign_cert);
+                               ctx = ssl_sock_get_generated_cert(serial, s);
                                if (ctx) {
                                        /* switch ctx */
                                        SSL_set_SSL_CTX(ssl, ctx);
@@ -1238,9 +1250,8 @@ static int ssl_sock_switchctx_cbk(SSL *ssl, int *al, struct bind_conf *s)
        }
        if (!node || container_of(node, struct sni_ctx, name)->neg) {
                SSL_CTX *ctx;
-
                if (s->generate_certs &&
-                   (ctx = ssl_sock_generate_certificate(servername, s))) {
+                   (ctx = ssl_sock_generate_certificate(servername, s, ssl))) {
                        /* switch ctx */
                        SSL_set_SSL_CTX(ssl, ctx);
                        return SSL_TLSEXT_ERR_OK;