@@ -1008,3 +1008,238 @@ void tlshd_tags_shutdown(void)
1008
1008
NULL );
1009
1009
g_ptr_array_free (tlshd_tags_filter_all , TRUE);
1010
1010
}
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