@@ -1006,3 +1006,238 @@ void tlshd_tags_shutdown(void)
10061006 NULL );
10071007 g_ptr_array_free (tlshd_tags_filter_all , TRUE);
10081008}
1009+
1010+ static bool tlshd_tags_x509_match_subject (struct tlshd_tags_filter * filter ,
1011+ gnutls_x509_crt_t * cert )
1012+ {
1013+ gnutls_datum_t dn ;
1014+ int ret ;
1015+
1016+ ret = gnutls_x509_crt_get_dn3 (* cert , & dn , 0 );
1017+ if (ret != GNUTLS_E_SUCCESS ) {
1018+ tlshd_log_gnutls_error (ret );
1019+ return false;
1020+ }
1021+
1022+ /* XXX: Do we need to consult filter->fi_match_type here ? */
1023+
1024+ #ifdef HAVE_GLIB_G_PATTERN_SPEC_MATCH
1025+ if (!g_pattern_spec_match (filter -> fi_pattern , dn .size ,
1026+ (const gchar * )dn .data , NULL )) {
1027+ #else
1028+ if (!g_pattern_match (filter -> fi_pattern , dn .size ,
1029+ (const gchar * )dn .data , NULL )) {
1030+ #endif
1031+ tlshd_log_debug ("Filter '%s' did not match subject '%s'" ,
1032+ filter -> fi_name , dn .data );
1033+ gnutls_free (dn .data );
1034+ return false;
1035+ }
1036+ tlshd_log_debug ("Filter '%s' matched subject '%s'" ,
1037+ filter -> fi_name , dn .data );
1038+ gnutls_free (dn .data );
1039+ return true;
1040+ }
1041+
1042+ static bool tlshd_tags_x509_match_issuer (struct tlshd_tags_filter * filter ,
1043+ gnutls_x509_crt_t * cert )
1044+ {
1045+ gnutls_datum_t dn ;
1046+ int ret ;
1047+
1048+ ret = gnutls_x509_crt_get_issuer_dn3 (* cert , & dn , 0 );
1049+ if (ret != GNUTLS_E_SUCCESS ) {
1050+ tlshd_log_gnutls_error (ret );
1051+ return false;
1052+ }
1053+
1054+ /* XXX: Do we need to consult filter->fi_match_type here ? */
1055+
1056+ #ifdef HAVE_GLIB_G_PATTERN_SPEC_MATCH
1057+ if (!g_pattern_spec_match (filter -> fi_pattern , dn .size ,
1058+ (const gchar * )dn .data , NULL )) {
1059+ #else
1060+ if (!g_pattern_match (filter -> fi_pattern , dn .size ,
1061+ (const gchar * )dn .data , NULL )) {
1062+ #endif
1063+ tlshd_log_debug ("Filter '%s' did not match issuer '%s'" ,
1064+ filter -> fi_name , dn .data );
1065+ gnutls_free (dn .data );
1066+ return false;
1067+ }
1068+ tlshd_log_debug ("Filter '%s' matched issuer '%s'" ,
1069+ filter -> fi_name , dn .data );
1070+ gnutls_free (dn .data );
1071+ return true;
1072+ }
1073+
1074+ static bool tlshd_tags_x509_match_serial (struct tlshd_tags_filter * filter ,
1075+ gnutls_x509_crt_t * cert )
1076+ {
1077+ unsigned char raw [40 ];
1078+ char * c , buf [100 ];
1079+ size_t i , size ;
1080+ int ret ;
1081+
1082+ size = sizeof (raw );
1083+ ret = gnutls_x509_crt_get_serial (* cert , raw , & size );
1084+ if (ret != GNUTLS_E_SUCCESS ) {
1085+ tlshd_log_gnutls_error (ret );
1086+ return false;
1087+ }
1088+
1089+ c = buf ;
1090+ for (i = 0 ; i < size ; i ++ ) {
1091+ sprintf (c , "%.2x" , raw [i ]);
1092+ c += 2 ;
1093+ }
1094+ * c = '\0' ;
1095+
1096+ /* XXX: Do we need to consult filter->fi_match_type here ? */
1097+
1098+ #ifdef HAVE_GLIB_G_PATTERN_SPEC_MATCH
1099+ if (!g_pattern_spec_match (filter -> fi_pattern , strlen (buf ), buf , NULL )) {
1100+ #else
1101+ if (!g_pattern_match (filter -> fi_pattern , strlen (buf ), buf , NULL )) {
1102+ #endif
1103+ tlshd_log_debug ("Filter '%s' did not match serial '%s'" ,
1104+ filter -> fi_name , buf );
1105+ return false;
1106+ }
1107+ tlshd_log_debug ("Filter '%s' matched serial '%s'" ,
1108+ filter -> fi_name , buf );
1109+ return true;
1110+ }
1111+
1112+ static bool tlshd_tags_x509_match_san (struct tlshd_tags_filter * filter ,
1113+ gnutls_x509_crt_t * cert )
1114+ {
1115+ char buf [256 ]; /* XXX: Dynamically-allocate this buffer */
1116+ unsigned int i ;
1117+ size_t size ;
1118+ int ret ;
1119+
1120+ tlshd_log_debug ("SAN filter: '%s'" , filter -> fi_name );
1121+
1122+ for (ret = 0 , i = 0 ; ret >= 0 ; i ++ ) {
1123+ size = sizeof (buf );
1124+ ret = gnutls_x509_crt_get_subject_alt_name (* cert , i , buf ,
1125+ & size , NULL );
1126+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE )
1127+ break ;
1128+
1129+ switch (ret ) {
1130+ case GNUTLS_SAN_DNSNAME :
1131+ tlshd_log_debug ("DNS: %s" , buf );
1132+ break ;
1133+ case GNUTLS_SAN_RFC822NAME :
1134+ tlshd_log_debug ("RFC822: %s" , buf );
1135+ break ;
1136+ case GNUTLS_SAN_URI :
1137+ tlshd_log_debug ("URI: %s" , buf );
1138+ break ;
1139+ case GNUTLS_SAN_IPADDRESS :
1140+ tlshd_log_debug ("IP: %s" , buf );
1141+ break ;
1142+ case GNUTLS_SAN_OTHERNAME :
1143+ tlshd_log_debug ("Other: %s" , buf );
1144+ break ;
1145+ case GNUTLS_SAN_DN :
1146+ tlshd_log_debug ("DN: %s" , buf );
1147+ break ;
1148+ case GNUTLS_SAN_REGISTERED_ID :
1149+ tlshd_log_debug ("Registered ID: %s" , buf );
1150+ break ;
1151+ case GNUTLS_SAN_OTHERNAME_XMPP :
1152+ tlshd_log_debug ("Other XMPP: %s" , buf );
1153+ break ;
1154+ case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL :
1155+ tlshd_log_debug ("Other Krb5: %s" , buf );
1156+ break ;
1157+ case GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL :
1158+ tlshd_log_debug ("Other MS User principal: %s" , buf );
1159+ break ;
1160+
1161+ default :
1162+ if (ret < 0 ) {
1163+ tlshd_log_gnutls_error (ret );
1164+ break ;
1165+ }
1166+ }
1167+ }
1168+
1169+ return false;
1170+ }
1171+
1172+ struct tlshd_tags_match_args {
1173+ struct tlshd_tags_tag * ma_tag ;
1174+ gnutls_x509_crt_t * ma_cert ;
1175+ bool ma_matched ;
1176+ };
1177+
1178+ static void tlshd_tags_x509_match_filters_cb (gpointer data , gpointer user_data )
1179+ {
1180+ struct tlshd_tags_filter * filter = (struct tlshd_tags_filter * )data ;
1181+ struct tlshd_tags_match_args * args = (struct tlshd_tags_match_args * )user_data ;
1182+
1183+ /* A previous filter failed to match, no need to check any further */
1184+ if (!args -> ma_matched )
1185+ return ;
1186+
1187+ if (strcmp (filter -> fi_field , "subject" ) == 0 )
1188+ args -> ma_matched = tlshd_tags_x509_match_subject (filter , args -> ma_cert );
1189+ else if (strcmp (filter -> fi_field , "issuer" ) == 0 )
1190+ args -> ma_matched = tlshd_tags_x509_match_issuer (filter , args -> ma_cert );
1191+ else if (strcmp (filter -> fi_field , "serial" ) == 0 )
1192+ args -> ma_matched = tlshd_tags_x509_match_serial (filter , args -> ma_cert );
1193+ else if (strcmp (filter -> fi_field , "san" ) == 0 )
1194+ args -> ma_matched = tlshd_tags_x509_match_san (filter , args -> ma_cert );
1195+ }
1196+
1197+ static void tlshd_tags_x509_match_cb (gpointer data , gpointer user_data )
1198+ {
1199+ struct tlshd_tags_match_args args = {
1200+ .ma_tag = (struct tlshd_tags_tag * )data ,
1201+ .ma_cert = (gnutls_x509_crt_t * )user_data ,
1202+ .ma_matched = true,
1203+ };
1204+
1205+ g_ptr_array_foreach (args .ma_tag -> ta_filters ,
1206+ tlshd_tags_x509_match_filters_cb , (gpointer )& args );
1207+ args .ma_tag -> ta_matched = args .ma_matched ;
1208+ }
1209+
1210+ /**
1211+ * tlshd_tags_x509_match_session - match certificate against configured tags
1212+ * @session: session with incoming x.509 certificates
1213+ *
1214+ * Side-effect: The tt_matched boolean is set in each tag in the
1215+ * global tag list that is matched. When this function is called
1216+ * in a child process, the parent's tag list is not changed (the
1217+ * parent's tag list is copied-on-write after the child forks).
1218+ */
1219+ void tlsdh_tags_x509_match_session (gnutls_session_t session )
1220+ {
1221+ const gnutls_datum_t * cert_list ;
1222+ unsigned int num_certs = 0 ;
1223+ gnutls_x509_crt_t peercert ;
1224+
1225+ if (!tlshd_tags_tag_all )
1226+ return ;
1227+ if (gnutls_certificate_type_get (session ) != GNUTLS_CRT_X509 )
1228+ return ;
1229+ cert_list = gnutls_certificate_get_peers (session , & num_certs );
1230+ if (num_certs == 0 )
1231+ return ;
1232+
1233+ /*
1234+ * The first certificate in the returned list is the peer's
1235+ * certificate. That is the only one that is checked against
1236+ * our tags list.
1237+ */
1238+ gnutls_x509_crt_init (& peercert );
1239+ gnutls_x509_crt_import (peercert , & cert_list [0 ], GNUTLS_X509_FMT_DER );
1240+ g_ptr_array_foreach (tlshd_tags_tag_all ,
1241+ tlshd_tags_x509_match_cb , (gpointer )& peercert );
1242+ gnutls_x509_crt_deinit (peercert );
1243+ }
0 commit comments