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