]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: ssl: move utility functions to src/ssl_utils.c
authorWilliam Lallemand <wlallemand@haproxy.com>
Fri, 15 May 2020 10:01:17 +0000 (12:01 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Fri, 15 May 2020 12:11:54 +0000 (14:11 +0200)
These functions are mainly used to extract information from
certificates.

Makefile
include/proto/ssl_sock.h
include/proto/ssl_utils.h [new file with mode: 0644]
src/ssl_ckch.c
src/ssl_sample.c
src/ssl_sock.c
src/ssl_utils.c [new file with mode: 0644]

index 846c0c3b7fdedf60c9328941b4f61514a5c6f606..33835a7aa919350948595110d2e04adf616dc65f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sample.o src/ssl_sock.o src/ssl_crtlist.o src/ssl_ckch.o src/cfgparse-ssl.o
+OPTIONS_OBJS  += src/ssl_sample.o src/ssl_sock.o src/ssl_crtlist.o src/ssl_ckch.o src/ssl_utils.o src/cfgparse-ssl.o
 endif
 
 # The private cache option affect the way the shctx is built
index 690199a12594f36797f78ddc0e4335e77db2a6df..101d86810fa6b766658ff66efb0517056709fe0f 100644 (file)
@@ -107,20 +107,12 @@ void ssl_async_fd_handler(int fd);
 void ssl_async_fd_free(int fd);
 #endif
 struct issuer_chain* ssl_get0_issuer_chain(X509 *cert);
-int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out);
-int ssl_sock_get_serial(X509 *crt, struct buffer *out);
-int cert_get_pkey_algo(X509 *crt, struct buffer *out);
 int ssl_load_global_issuer_from_BIO(BIO *in, char *fp, char **err);
 int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err);
 void ssl_free_global_issuers(void);
 int ssl_sock_load_cert_list_file(char *file, int dir, struct bind_conf *bind_conf, struct proxy *curproxy, char **err);
 int ssl_init_single_engine(const char *engine_id, const char *def_algorithms);
 int ssl_store_load_locations_file(char *path);
-int ssl_sock_crt2der(X509 *crt, struct buffer *out);
-int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
-int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out);
-int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
-                          struct buffer *out);
 
 /* ssl shctx macro */
 
diff --git a/include/proto/ssl_utils.h b/include/proto/ssl_utils.h
new file mode 100644 (file)
index 0000000..be14a0d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * include/proto/ssl_utils.h
+ *
+ * Utility functions for SSL:
+ * Mostly generic functions that retrieve information from certificates
+ *
+ * Copyright (C) 2012 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
+ * Copyright (C) 2020 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _TYPES_SSL_UTILS_H
+#define _TYPES_SSL_UTILS_H
+#ifdef USE_OPENSSL
+
+int cert_get_pkey_algo(X509 *crt, struct buffer *out);
+int ssl_sock_get_serial(X509 *crt, struct buffer *out);
+int ssl_sock_crt2der(X509 *crt, struct buffer *out);
+int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
+int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
+                          struct buffer *out);
+int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out);
+int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out);
+
+#endif /* _TYPES_SSL_UTILS_H */
+#endif /* USE_OPENSSL */
+
index 484997d7f5cb8a8433d7566eed31c8d99db82792..c59364930c309c0674ecfeba0b32bc7f738adb62 100644 (file)
@@ -35,6 +35,7 @@
 #include <proto/channel.h>
 #include <proto/ssl_ckch.h>
 #include <proto/ssl_sock.h>
+#include <proto/ssl_utils.h>
 #include <proto/stream_interface.h>
 
 /* Uncommitted CKCH transaction */
index 55eec78e926c5ec9bdd7c5797a95935cd27633d7..f3fd0b4b02958ff96b15cbb0fe32e825b29ea470 100644 (file)
@@ -32,6 +32,7 @@
 #include <proto/arg.h>
 #include <proto/obj_type.h>
 #include <proto/ssl_sock.h>
+#include <proto/ssl_utils.h>
 #include <proto/sample.h>
 
 
index 95db8f519571a5bb2197523a925681f1a0d3a0c0..9d6b8b1184eb89bac43b37ad228fe5e83e507dc2 100644 (file)
@@ -86,6 +86,7 @@
 #include <proto/ssl_ckch.h>
 #include <proto/ssl_crtlist.h>
 #include <proto/ssl_sock.h>
+#include <proto/ssl_utils.h>
 #include <proto/stream.h>
 #include <proto/task.h>
 #include <proto/vars.h>
@@ -5851,48 +5852,6 @@ static void ssl_sock_shutw(struct connection *conn, void *xprt_ctx, int clean)
        }
 }
 
-/* fill a buffer with the algorithm and size of a public key */
-int cert_get_pkey_algo(X509 *crt, struct buffer *out)
-{
-       int bits = 0;
-       int sig = TLSEXT_signature_anonymous;
-       int len = -1;
-       EVP_PKEY *pkey;
-
-       pkey = X509_get_pubkey(crt);
-       if (pkey) {
-               bits = EVP_PKEY_bits(pkey);
-               switch(EVP_PKEY_base_id(pkey)) {
-               case EVP_PKEY_RSA:
-                       sig = TLSEXT_signature_rsa;
-                       break;
-               case EVP_PKEY_EC:
-                       sig = TLSEXT_signature_ecdsa;
-                       break;
-               case EVP_PKEY_DSA:
-                       sig = TLSEXT_signature_dsa;
-                       break;
-               }
-               EVP_PKEY_free(pkey);
-       }
-
-       switch(sig) {
-       case TLSEXT_signature_rsa:
-               len = chunk_printf(out, "RSA%d", bits);
-               break;
-       case TLSEXT_signature_ecdsa:
-               len = chunk_printf(out, "EC%d", bits);
-               break;
-       case TLSEXT_signature_dsa:
-               len = chunk_printf(out, "DSA%d", bits);
-               break;
-       default:
-               return 0;
-       }
-       if (len < 0)
-               return 0;
-       return 1;
-}
 
 /* used for ppv2 pkey algo (can be used for logging) */
 int ssl_sock_get_pkey_algo(struct connection *conn, struct buffer *out)
@@ -5967,232 +5926,6 @@ const char *ssl_sock_get_proto_version(struct connection *conn)
        return SSL_get_version(ctx->ssl);
 }
 
-/* Extract a serial from a cert, and copy it to a chunk.
- * Returns 1 if serial is found and copied, 0 if no serial found and
- * -1 if output is not large enough.
- */
-int ssl_sock_get_serial(X509 *crt, struct buffer *out)
-{
-       ASN1_INTEGER *serial;
-
-       serial = X509_get_serialNumber(crt);
-       if (!serial)
-               return 0;
-
-       if (out->size < serial->length)
-               return -1;
-
-       memcpy(out->area, serial->data, serial->length);
-       out->data = serial->length;
-       return 1;
-}
-
-/* Extract a cert to der, and copy it to a chunk.
- * Returns 1 if the cert is found and copied, 0 on der conversion failure
- * and -1 if the output is not large enough.
- */
-int ssl_sock_crt2der(X509 *crt, struct buffer *out)
-{
-       int len;
-       unsigned char *p = (unsigned char *) out->area;;
-
-       len =i2d_X509(crt, NULL);
-       if (len <= 0)
-               return 1;
-
-       if (out->size < len)
-               return -1;
-
-       i2d_X509(crt,&p);
-       out->data = len;
-       return 1;
-}
-
-
-/* Copy Date in ASN1_UTCTIME format in struct buffer out.
- * Returns 1 if serial is found and copied, 0 if no valid time found
- * and -1 if output is not large enough.
- */
-int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out)
-{
-       if (tm->type == V_ASN1_GENERALIZEDTIME) {
-               ASN1_GENERALIZEDTIME *gentm = (ASN1_GENERALIZEDTIME *)tm;
-
-               if (gentm->length < 12)
-                       return 0;
-               if (gentm->data[0] != 0x32 || gentm->data[1] != 0x30)
-                       return 0;
-               if (out->size < gentm->length-2)
-                       return -1;
-
-               memcpy(out->area, gentm->data+2, gentm->length-2);
-               out->data = gentm->length-2;
-               return 1;
-       }
-       else if (tm->type == V_ASN1_UTCTIME) {
-               ASN1_UTCTIME *utctm = (ASN1_UTCTIME *)tm;
-
-               if (utctm->length < 10)
-                       return 0;
-               if (utctm->data[0] >= 0x35)
-                       return 0;
-               if (out->size < utctm->length)
-                       return -1;
-
-               memcpy(out->area, utctm->data, utctm->length);
-               out->data = utctm->length;
-               return 1;
-       }
-
-       return 0;
-}
-
-/* Extract an entry from a X509_NAME and copy its value to an output chunk.
- * Returns 1 if entry found, 0 if entry not found, or -1 if output not large enough.
- */
-int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
-                          struct buffer *out)
-{
-       X509_NAME_ENTRY *ne;
-       ASN1_OBJECT *obj;
-       ASN1_STRING *data;
-       const unsigned char *data_ptr;
-       int data_len;
-       int i, j, n;
-       int cur = 0;
-       const char *s;
-       char tmp[128];
-       int name_count;
-
-       name_count = X509_NAME_entry_count(a);
-
-       out->data = 0;
-       for (i = 0; i < name_count; i++) {
-               if (pos < 0)
-                       j = (name_count-1) - i;
-               else
-                       j = i;
-
-               ne = X509_NAME_get_entry(a, j);
-               obj = X509_NAME_ENTRY_get_object(ne);
-               data = X509_NAME_ENTRY_get_data(ne);
-               data_ptr = ASN1_STRING_get0_data(data);
-               data_len = ASN1_STRING_length(data);
-               n = OBJ_obj2nid(obj);
-               if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
-                       i2t_ASN1_OBJECT(tmp, sizeof(tmp), obj);
-                       s = tmp;
-               }
-
-               if (chunk_strcasecmp(entry, s) != 0)
-                       continue;
-
-               if (pos < 0)
-                       cur--;
-               else
-                       cur++;
-
-               if (cur != pos)
-                       continue;
-
-               if (data_len > out->size)
-                       return -1;
-
-               memcpy(out->area, data_ptr, data_len);
-               out->data = data_len;
-               return 1;
-       }
-
-       return 0;
-
-}
-
-/*
- * Extract the DN in the specified format from the X509_NAME and copy result to a chunk.
- * Currently supports rfc2253 for returning LDAP V3 DNs.
- * Returns 1 if dn entries exist, 0 if no dn entry was found.
- */
-int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out)
-{
-       BIO *bio = NULL;
-       int ret = 0;
-       int data_len = 0;
-
-       if (chunk_strcmp(format, "rfc2253") == 0) {
-               bio = BIO_new(BIO_s_mem());
-               if (bio == NULL)
-                       goto out;
-
-               if (X509_NAME_print_ex(bio, a, 0, XN_FLAG_RFC2253) < 0)
-                       goto out;
-
-               if ((data_len = BIO_read(bio, out->area, out->size)) <= 0)
-                       goto out;
-
-               out->data = data_len;
-
-               ret = 1;
-       }
-out:
-       if (bio)
-               BIO_free(bio);
-       return ret;
-}
-
-/* Extract and format full DN from a X509_NAME and copy result into a chunk
- * Returns 1 if dn entries exits, 0 if no dn entry found or -1 if output is not large enough.
- */
-int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out)
-{
-       X509_NAME_ENTRY *ne;
-       ASN1_OBJECT *obj;
-       ASN1_STRING *data;
-       const unsigned char *data_ptr;
-       int data_len;
-       int i, n, ln;
-       int l = 0;
-       const char *s;
-       char *p;
-       char tmp[128];
-       int name_count;
-
-
-       name_count = X509_NAME_entry_count(a);
-
-       out->data = 0;
-       p = out->area;
-       for (i = 0; i < name_count; i++) {
-               ne = X509_NAME_get_entry(a, i);
-               obj = X509_NAME_ENTRY_get_object(ne);
-               data = X509_NAME_ENTRY_get_data(ne);
-               data_ptr = ASN1_STRING_get0_data(data);
-               data_len = ASN1_STRING_length(data);
-               n = OBJ_obj2nid(obj);
-               if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
-                       i2t_ASN1_OBJECT(tmp, sizeof(tmp), obj);
-                       s = tmp;
-               }
-               ln = strlen(s);
-
-               l += 1 + ln + 1 + data_len;
-               if (l > out->size)
-                       return -1;
-               out->data = l;
-
-               *(p++)='/';
-               memcpy(p, s, ln);
-               p += ln;
-               *(p++)='=';
-               memcpy(p, data_ptr, data_len);
-               p += data_len;
-       }
-
-       if (!out->data)
-               return 0;
-
-       return 1;
-}
-
 void ssl_sock_set_alpn(struct connection *conn, const unsigned char *alpn, int len)
 {
 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
diff --git a/src/ssl_utils.c b/src/ssl_utils.c
new file mode 100644 (file)
index 0000000..76c5137
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Utility functions for SSL:
+ * Mostly generic functions that retrieve information from certificates
+ *
+ * Copyright (C) 2012 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
+ * Copyright (C) 2020 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <common/buffer.h>
+#include <common/openssl-compat.h>
+
+#include <proto/ssl_sock.h>
+
+#include <types/ssl_sock.h>
+
+/* fill a buffer with the algorithm and size of a public key */
+int cert_get_pkey_algo(X509 *crt, struct buffer *out)
+{
+       int bits = 0;
+       int sig = TLSEXT_signature_anonymous;
+       int len = -1;
+       EVP_PKEY *pkey;
+
+       pkey = X509_get_pubkey(crt);
+       if (pkey) {
+               bits = EVP_PKEY_bits(pkey);
+               switch(EVP_PKEY_base_id(pkey)) {
+               case EVP_PKEY_RSA:
+                       sig = TLSEXT_signature_rsa;
+                       break;
+               case EVP_PKEY_EC:
+                       sig = TLSEXT_signature_ecdsa;
+                       break;
+               case EVP_PKEY_DSA:
+                       sig = TLSEXT_signature_dsa;
+                       break;
+               }
+               EVP_PKEY_free(pkey);
+       }
+
+       switch(sig) {
+       case TLSEXT_signature_rsa:
+               len = chunk_printf(out, "RSA%d", bits);
+               break;
+       case TLSEXT_signature_ecdsa:
+               len = chunk_printf(out, "EC%d", bits);
+               break;
+       case TLSEXT_signature_dsa:
+               len = chunk_printf(out, "DSA%d", bits);
+               break;
+       default:
+               return 0;
+       }
+       if (len < 0)
+               return 0;
+       return 1;
+}
+
+/* Extract a serial from a cert, and copy it to a chunk.
+ * Returns 1 if serial is found and copied, 0 if no serial found and
+ * -1 if output is not large enough.
+ */
+int ssl_sock_get_serial(X509 *crt, struct buffer *out)
+{
+       ASN1_INTEGER *serial;
+
+       serial = X509_get_serialNumber(crt);
+       if (!serial)
+               return 0;
+
+       if (out->size < serial->length)
+               return -1;
+
+       memcpy(out->area, serial->data, serial->length);
+       out->data = serial->length;
+       return 1;
+}
+
+/* Extract a cert to der, and copy it to a chunk.
+ * Returns 1 if the cert is found and copied, 0 on der conversion failure
+ * and -1 if the output is not large enough.
+ */
+int ssl_sock_crt2der(X509 *crt, struct buffer *out)
+{
+       int len;
+       unsigned char *p = (unsigned char *) out->area;;
+
+       len =i2d_X509(crt, NULL);
+       if (len <= 0)
+               return 1;
+
+       if (out->size < len)
+               return -1;
+
+       i2d_X509(crt,&p);
+       out->data = len;
+       return 1;
+}
+
+
+/* Copy Date in ASN1_UTCTIME format in struct buffer out.
+ * Returns 1 if serial is found and copied, 0 if no valid time found
+ * and -1 if output is not large enough.
+ */
+int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out)
+{
+       if (tm->type == V_ASN1_GENERALIZEDTIME) {
+               ASN1_GENERALIZEDTIME *gentm = (ASN1_GENERALIZEDTIME *)tm;
+
+               if (gentm->length < 12)
+                       return 0;
+               if (gentm->data[0] != 0x32 || gentm->data[1] != 0x30)
+                       return 0;
+               if (out->size < gentm->length-2)
+                       return -1;
+
+               memcpy(out->area, gentm->data+2, gentm->length-2);
+               out->data = gentm->length-2;
+               return 1;
+       }
+       else if (tm->type == V_ASN1_UTCTIME) {
+               ASN1_UTCTIME *utctm = (ASN1_UTCTIME *)tm;
+
+               if (utctm->length < 10)
+                       return 0;
+               if (utctm->data[0] >= 0x35)
+                       return 0;
+               if (out->size < utctm->length)
+                       return -1;
+
+               memcpy(out->area, utctm->data, utctm->length);
+               out->data = utctm->length;
+               return 1;
+       }
+
+       return 0;
+}
+
+/* Extract an entry from a X509_NAME and copy its value to an output chunk.
+ * Returns 1 if entry found, 0 if entry not found, or -1 if output not large enough.
+ */
+int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
+                          struct buffer *out)
+{
+       X509_NAME_ENTRY *ne;
+       ASN1_OBJECT *obj;
+       ASN1_STRING *data;
+       const unsigned char *data_ptr;
+       int data_len;
+       int i, j, n;
+       int cur = 0;
+       const char *s;
+       char tmp[128];
+       int name_count;
+
+       name_count = X509_NAME_entry_count(a);
+
+       out->data = 0;
+       for (i = 0; i < name_count; i++) {
+               if (pos < 0)
+                       j = (name_count-1) - i;
+               else
+                       j = i;
+
+               ne = X509_NAME_get_entry(a, j);
+               obj = X509_NAME_ENTRY_get_object(ne);
+               data = X509_NAME_ENTRY_get_data(ne);
+               data_ptr = ASN1_STRING_get0_data(data);
+               data_len = ASN1_STRING_length(data);
+               n = OBJ_obj2nid(obj);
+               if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
+                       i2t_ASN1_OBJECT(tmp, sizeof(tmp), obj);
+                       s = tmp;
+               }
+
+               if (chunk_strcasecmp(entry, s) != 0)
+                       continue;
+
+               if (pos < 0)
+                       cur--;
+               else
+                       cur++;
+
+               if (cur != pos)
+                       continue;
+
+               if (data_len > out->size)
+                       return -1;
+
+               memcpy(out->area, data_ptr, data_len);
+               out->data = data_len;
+               return 1;
+       }
+
+       return 0;
+
+}
+
+/*
+ * Extract the DN in the specified format from the X509_NAME and copy result to a chunk.
+ * Currently supports rfc2253 for returning LDAP V3 DNs.
+ * Returns 1 if dn entries exist, 0 if no dn entry was found.
+ */
+int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out)
+{
+       BIO *bio = NULL;
+       int ret = 0;
+       int data_len = 0;
+
+       if (chunk_strcmp(format, "rfc2253") == 0) {
+               bio = BIO_new(BIO_s_mem());
+               if (bio == NULL)
+                       goto out;
+
+               if (X509_NAME_print_ex(bio, a, 0, XN_FLAG_RFC2253) < 0)
+                       goto out;
+
+               if ((data_len = BIO_read(bio, out->area, out->size)) <= 0)
+                       goto out;
+
+               out->data = data_len;
+
+               ret = 1;
+       }
+out:
+       if (bio)
+               BIO_free(bio);
+       return ret;
+}
+
+/* Extract and format full DN from a X509_NAME and copy result into a chunk
+ * Returns 1 if dn entries exits, 0 if no dn entry found or -1 if output is not large enough.
+ */
+int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out)
+{
+       X509_NAME_ENTRY *ne;
+       ASN1_OBJECT *obj;
+       ASN1_STRING *data;
+       const unsigned char *data_ptr;
+       int data_len;
+       int i, n, ln;
+       int l = 0;
+       const char *s;
+       char *p;
+       char tmp[128];
+       int name_count;
+
+
+       name_count = X509_NAME_entry_count(a);
+
+       out->data = 0;
+       p = out->area;
+       for (i = 0; i < name_count; i++) {
+               ne = X509_NAME_get_entry(a, i);
+               obj = X509_NAME_ENTRY_get_object(ne);
+               data = X509_NAME_ENTRY_get_data(ne);
+               data_ptr = ASN1_STRING_get0_data(data);
+               data_len = ASN1_STRING_length(data);
+               n = OBJ_obj2nid(obj);
+               if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) {
+                       i2t_ASN1_OBJECT(tmp, sizeof(tmp), obj);
+                       s = tmp;
+               }
+               ln = strlen(s);
+
+               l += 1 + ln + 1 + data_len;
+               if (l > out->size)
+                       return -1;
+               out->data = l;
+
+               *(p++)='/';
+               memcpy(p, s, ln);
+               p += ln;
+               *(p++)='=';
+               memcpy(p, data_ptr, data_len);
+               p += data_len;
+       }
+
+       if (!out->data)
+               return 0;
+
+       return 1;
+}
+