Browse Source

Read client certificate information (Step 3/3)

bel 9 năm trước cách đây
mục cha
commit
d8d9dd5fff
2 tập tin đã thay đổi với 106 bổ sung39 xóa
  1. 11 0
      include/civetweb.h
  2. 95 39
      src/civetweb.c

+ 11 - 0
include/civetweb.h

@@ -86,6 +86,17 @@ struct mg_request_info {
 		const char *name;  /* HTTP header name */
 		const char *value; /* HTTP header value */
 	} 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;
 };
 
 

+ 95 - 39
src/civetweb.c

@@ -1024,17 +1024,11 @@ typedef struct ssl_st SSL;
 typedef struct ssl_method_st SSL_METHOD;
 typedef struct ssl_ctx_st SSL_CTX;
 typedef struct x509_store_ctx_st X509_STORE_CTX;
-typedef struct x509 X509;
 typedef struct x509_name X509_NAME;
 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_CLEAR_OPTIONS (77)
@@ -1110,6 +1104,7 @@ struct ssl_func {
 	(*(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_set_cipher_list                                                \
 	(*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
 #define SSL_CTX_set_options(ctx, op)                                           \
@@ -1119,6 +1114,10 @@ struct ssl_func {
 #define SSL_CTX_set_ecdh_auto(ctx, onoff)                                      \
 	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_set_locking_callback                                            \
 	(*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
@@ -1138,7 +1137,17 @@ struct ssl_func {
 #define X509_NAME_oneline                                                      \
 	(*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].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.
@@ -1199,6 +1208,9 @@ static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
                                       {"X509_NAME_oneline", NULL},
                                       {"X509_get_serialNumber", NULL},
                                       {"i2c_ASN1_INTEGER", NULL},
+                                      {"EVP_get_digestbyname", NULL},
+                                      {"ASN1_digest", NULL},
+                                      {"i2d_X509", NULL},
                                       {NULL, NULL}};
 #endif /* NO_SSL_DL */
 #endif /* NO_SSL */
@@ -5299,9 +5311,9 @@ remove_double_dots_and_double_slashes(char *s)
 {
 	char *p = s;
 
-    while ((s[0] == '.') && (s[1] == '.')) {
-        s++;
-    }
+	while ((s[0] == '.') && (s[1] == '.')) {
+		s++;
+	}
 
 	while (*s != '\0') {
 		*p++ = *s++;
@@ -11317,18 +11329,18 @@ hexdump2string(void *mem, int memlen, char *buf, int buflen)
 	if (memlen <= 0 || buflen <= 0) {
 		return 0;
 	}
-    if (buflen < (3*memlen)) {
-        return 0;
-    }
+	if (buflen < (3 * memlen)) {
+		return 0;
+	}
 
 	for (i = 0; i < memlen; i++) {
 		if (i > 0) {
 			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*memlen-1] = 0;
+	buf[3 * memlen - 1] = 0;
 
 	return 1;
 }
@@ -11339,30 +11351,57 @@ ssl_get_client_cert_info(struct mg_connection *conn)
 {
 	X509 *cert = SSL_get_peer_certificate(conn->ssl);
 	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 *iss = X509_get_issuer_name(cert);
-		char buf1[1024];
-		char buf2[1024];
-		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));
+
+		/* Get serial number */
 		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))) {
-			    *buf3 = 0;
-		    }        
-        } else {
-            *buf3 = 0;
-        }
-
-		/* TODO: store the information in buf1-3 somewhere */
-        (void)ret1;
-        (void)ret2;
+
+		/* Translate subject and issuer to a string */
+		(void)X509_NAME_oneline(subj, str_subject, (int)sizeof(str_subject));
+		(void)X509_NAME_oneline(iss, str_issuer, (int)sizeof(str_issuer));
+
+		/* Translate serial number to a hex string */
+		len = i2c_ASN1_INTEGER(serial, NULL);
+		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);
 	}
@@ -12971,12 +13010,29 @@ worker_thread_run(struct worker_thread_args *thread_args)
 #ifndef NO_SSL
 				/* HTTPS connection */
 				if (sslize(conn, conn->ctx->ssl_ctx, SSL_accept)) {
+					/* Get SSL client certificate information (if set) */
 					ssl_get_client_cert_info(conn);
+
+					/* process HTTPS connection */
 					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
 			} else {
-				/* HTTP connection */
+				/* process HTTP connection */
 				process_new_connection(conn);
 			}