@@ -1008,3 +1008,224 @@ 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 (!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