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