1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-12-22 04:02:04 +03:00

Read client certificate information (Step 3/3)

This commit is contained in:
bel
2016-07-24 22:38:05 +02:00
parent aeb8721503
commit d8d9dd5fff
2 changed files with 104 additions and 37 deletions

View File

@@ -86,6 +86,17 @@ struct mg_request_info {
const char *name; /* HTTP header name */ const char *name; /* HTTP header name */
const char *value; /* HTTP header value */ const char *value; /* HTTP header value */
} http_headers[64]; /* Maximum 64 headers */ } http_headers[64]; /* Maximum 64 headers */
struct client_cert *client_cert; /* Client certificate information */
};
/* Client certificate information (part of mg_request_info) */
struct client_cert {
const char *subject;
const char *issuer;
const char *serial;
const char *finger;
}; };

View File

@@ -1024,17 +1024,11 @@ typedef struct ssl_st SSL;
typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_method_st SSL_METHOD;
typedef struct ssl_ctx_st SSL_CTX; typedef struct ssl_ctx_st SSL_CTX;
typedef struct x509_store_ctx_st X509_STORE_CTX; typedef struct x509_store_ctx_st X509_STORE_CTX;
typedef struct x509 X509;
typedef struct x509_name X509_NAME; typedef struct x509_name X509_NAME;
typedef struct asn1_integer ASN1_INTEGER; typedef struct asn1_integer ASN1_INTEGER;
typedef struct evp_md EVP_MD;
typedef struct x509 X509;
/*
typedef struct asn1_bit_string_st {
int length;
int type;
unsigned char *data;
} ASN1_BIT_STRING;
*/
#define SSL_CTRL_OPTIONS (32) #define SSL_CTRL_OPTIONS (32)
#define SSL_CTRL_CLEAR_OPTIONS (77) #define SSL_CTRL_CLEAR_OPTIONS (77)
@@ -1110,6 +1104,7 @@ struct ssl_func {
(*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr) (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr) #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
#define SSL_CTX_set_cipher_list \ #define SSL_CTX_set_cipher_list \
(*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr) (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
#define SSL_CTX_set_options(ctx, op) \ #define SSL_CTX_set_options(ctx, op) \
@@ -1119,6 +1114,10 @@ struct ssl_func {
#define SSL_CTX_set_ecdh_auto(ctx, onoff) \ #define SSL_CTX_set_ecdh_auto(ctx, onoff) \
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
#define CRYPTO_set_locking_callback \ #define CRYPTO_set_locking_callback \
(*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr) (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
@@ -1138,7 +1137,17 @@ struct ssl_func {
#define X509_NAME_oneline \ #define X509_NAME_oneline \
(*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr) (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr) #define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr)
#define i2c_ASN1_INTEGER (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr) #define i2c_ASN1_INTEGER \
(*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
#define EVP_get_digestbyname \
(*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
#define ASN1_digest \
(*(int (*)(int (*)(), \
const EVP_MD *, \
char *, \
unsigned char *, \
unsigned int *))crypto_sw[18].ptr)
#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
/* set_ssl_option() function updates this array. /* set_ssl_option() function updates this array.
@@ -1199,6 +1208,9 @@ static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
{"X509_NAME_oneline", NULL}, {"X509_NAME_oneline", NULL},
{"X509_get_serialNumber", NULL}, {"X509_get_serialNumber", NULL},
{"i2c_ASN1_INTEGER", NULL}, {"i2c_ASN1_INTEGER", NULL},
{"EVP_get_digestbyname", NULL},
{"ASN1_digest", NULL},
{"i2d_X509", NULL},
{NULL, NULL}}; {NULL, NULL}};
#endif /* NO_SSL_DL */ #endif /* NO_SSL_DL */
#endif /* NO_SSL */ #endif /* NO_SSL */
@@ -5299,9 +5311,9 @@ remove_double_dots_and_double_slashes(char *s)
{ {
char *p = s; char *p = s;
while ((s[0] == '.') && (s[1] == '.')) { while ((s[0] == '.') && (s[1] == '.')) {
s++; s++;
} }
while (*s != '\0') { while (*s != '\0') {
*p++ = *s++; *p++ = *s++;
@@ -11317,18 +11329,18 @@ hexdump2string(void *mem, int memlen, char *buf, int buflen)
if (memlen <= 0 || buflen <= 0) { if (memlen <= 0 || buflen <= 0) {
return 0; return 0;
} }
if (buflen < (3*memlen)) { if (buflen < (3 * memlen)) {
return 0; return 0;
} }
for (i = 0; i < memlen; i++) { for (i = 0; i < memlen; i++) {
if (i > 0) { if (i > 0) {
buf[3 * i - 1] = ' '; buf[3 * i - 1] = ' ';
} }
buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4)&0xF]; buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF]; buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
} }
buf[3*memlen-1] = 0; buf[3 * memlen - 1] = 0;
return 1; return 1;
} }
@@ -11339,30 +11351,57 @@ ssl_get_client_cert_info(struct mg_connection *conn)
{ {
X509 *cert = SSL_get_peer_certificate(conn->ssl); X509 *cert = SSL_get_peer_certificate(conn->ssl);
if (cert) { if (cert) {
char str_subject[1024];
char str_issuer[1024];
char str_serial[1024];
char str_finger[1024];
unsigned char buf[256];
int len;
/* Handle to algorithm used for fingerprint */
const EVP_MD *digest = EVP_get_digestbyname("sha1");
/* Get Subject and issuer */
X509_NAME *subj = X509_get_subject_name(cert); X509_NAME *subj = X509_get_subject_name(cert);
X509_NAME *iss = X509_get_issuer_name(cert); X509_NAME *iss = X509_get_issuer_name(cert);
char buf1[1024];
char buf2[1024]; /* Get serial number */
char buf3[1024];
unsigned char intbuf[256];
char *ret1 = X509_NAME_oneline(subj, buf1, (int)sizeof(buf1));
char *ret2 = X509_NAME_oneline(iss, buf2, (int)sizeof(buf2));
ASN1_INTEGER *serial = X509_get_serialNumber(cert); ASN1_INTEGER *serial = X509_get_serialNumber(cert);
int len = i2c_ASN1_INTEGER(serial, NULL);
if (len < sizeof(intbuf)) {
unsigned char *pbuf = intbuf;
int len2 = i2c_ASN1_INTEGER(serial, &pbuf);
if (!hexdump2string(intbuf, len2, buf3, (int)sizeof(buf3))) { /* Translate subject and issuer to a string */
*buf3 = 0; (void)X509_NAME_oneline(subj, str_subject, (int)sizeof(str_subject));
} (void)X509_NAME_oneline(iss, str_issuer, (int)sizeof(str_issuer));
} else {
*buf3 = 0;
}
/* TODO: store the information in buf1-3 somewhere */ /* Translate serial number to a hex string */
(void)ret1; len = i2c_ASN1_INTEGER(serial, NULL);
(void)ret2; if (len < sizeof(buf)) {
unsigned char *pbuf = buf;
int len2 = i2c_ASN1_INTEGER(serial, &pbuf);
if (!hexdump2string(
buf, len2, str_serial, (int)sizeof(str_serial))) {
*str_serial = 0;
}
} else {
*str_serial = 0;
}
/* Calculate SHA1 fingerprint and store as a hex string */
len = 0;
ASN1_digest((int (*)())i2d_X509, digest, (char *)cert, buf, &len);
if (!hexdump2string(buf, len, str_finger, (int)sizeof(str_finger))) {
*str_finger = 0;
}
conn->request_info.client_cert =
(struct client_cert *)mg_malloc(sizeof(struct client_cert));
if (conn->request_info.client_cert) {
conn->request_info.client_cert->subject = mg_strdup(str_subject);
conn->request_info.client_cert->issuer = mg_strdup(str_issuer);
conn->request_info.client_cert->serial = mg_strdup(str_serial);
conn->request_info.client_cert->finger = mg_strdup(str_finger);
} else {
/* TODO: write some OOM message */
}
X509_free(cert); X509_free(cert);
} }
@@ -12971,12 +13010,29 @@ worker_thread_run(struct worker_thread_args *thread_args)
#ifndef NO_SSL #ifndef NO_SSL
/* HTTPS connection */ /* HTTPS connection */
if (sslize(conn, conn->ctx->ssl_ctx, SSL_accept)) { if (sslize(conn, conn->ctx->ssl_ctx, SSL_accept)) {
/* Get SSL client certificate information (if set) */
ssl_get_client_cert_info(conn); ssl_get_client_cert_info(conn);
/* process HTTPS connection */
process_new_connection(conn); process_new_connection(conn);
/* Free client certificate info */
if (conn->request_info.client_cert) {
mg_free((void*)(conn->request_info.client_cert->subject));
mg_free((void*)(conn->request_info.client_cert->issuer));
mg_free((void*)(conn->request_info.client_cert->serial));
mg_free((void*)(conn->request_info.client_cert->finger));
conn->request_info.client_cert->subject = 0;
conn->request_info.client_cert->issuer = 0;
conn->request_info.client_cert->serial = 0;
conn->request_info.client_cert->finger = 0;
mg_free(conn->request_info.client_cert);
conn->request_info.client_cert = 0;
}
} }
#endif #endif
} else { } else {
/* HTTP connection */ /* process HTTP connection */
process_new_connection(conn); process_new_connection(conn);
} }