mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
REORG: ssl: move utility functions to src/ssl_utils.c
These functions are mainly used to extract information from certificates.
This commit is contained in:
parent
15e169447d
commit
6a66a5ec9b
2
Makefile
2
Makefile
@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
|
|||||||
ifneq ($(USE_DL),)
|
ifneq ($(USE_DL),)
|
||||||
OPTIONS_LDFLAGS += -ldl
|
OPTIONS_LDFLAGS += -ldl
|
||||||
endif
|
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
|
endif
|
||||||
|
|
||||||
# The private cache option affect the way the shctx is built
|
# The private cache option affect the way the shctx is built
|
||||||
|
@ -107,20 +107,12 @@ void ssl_async_fd_handler(int fd);
|
|||||||
void ssl_async_fd_free(int fd);
|
void ssl_async_fd_free(int fd);
|
||||||
#endif
|
#endif
|
||||||
struct issuer_chain* ssl_get0_issuer_chain(X509 *cert);
|
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_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);
|
int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err);
|
||||||
void ssl_free_global_issuers(void);
|
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_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_init_single_engine(const char *engine_id, const char *def_algorithms);
|
||||||
int ssl_store_load_locations_file(char *path);
|
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 */
|
/* ssl shctx macro */
|
||||||
|
|
||||||
|
40
include/proto/ssl_utils.h
Normal file
40
include/proto/ssl_utils.h
Normal file
@ -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 */
|
||||||
|
|
@ -35,6 +35,7 @@
|
|||||||
#include <proto/channel.h>
|
#include <proto/channel.h>
|
||||||
#include <proto/ssl_ckch.h>
|
#include <proto/ssl_ckch.h>
|
||||||
#include <proto/ssl_sock.h>
|
#include <proto/ssl_sock.h>
|
||||||
|
#include <proto/ssl_utils.h>
|
||||||
#include <proto/stream_interface.h>
|
#include <proto/stream_interface.h>
|
||||||
|
|
||||||
/* Uncommitted CKCH transaction */
|
/* Uncommitted CKCH transaction */
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <proto/arg.h>
|
#include <proto/arg.h>
|
||||||
#include <proto/obj_type.h>
|
#include <proto/obj_type.h>
|
||||||
#include <proto/ssl_sock.h>
|
#include <proto/ssl_sock.h>
|
||||||
|
#include <proto/ssl_utils.h>
|
||||||
#include <proto/sample.h>
|
#include <proto/sample.h>
|
||||||
|
|
||||||
|
|
||||||
|
269
src/ssl_sock.c
269
src/ssl_sock.c
@ -86,6 +86,7 @@
|
|||||||
#include <proto/ssl_ckch.h>
|
#include <proto/ssl_ckch.h>
|
||||||
#include <proto/ssl_crtlist.h>
|
#include <proto/ssl_crtlist.h>
|
||||||
#include <proto/ssl_sock.h>
|
#include <proto/ssl_sock.h>
|
||||||
|
#include <proto/ssl_utils.h>
|
||||||
#include <proto/stream.h>
|
#include <proto/stream.h>
|
||||||
#include <proto/task.h>
|
#include <proto/task.h>
|
||||||
#include <proto/vars.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) */
|
/* used for ppv2 pkey algo (can be used for logging) */
|
||||||
int ssl_sock_get_pkey_algo(struct connection *conn, struct buffer *out)
|
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);
|
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)
|
void ssl_sock_set_alpn(struct connection *conn, const unsigned char *alpn, int len)
|
||||||
{
|
{
|
||||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
||||||
|
290
src/ssl_utils.c
Normal file
290
src/ssl_utils.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user