Changeset e183628 in mod_gnutls for src/gnutls_hooks.c
- Timestamp:
- Sep 19, 2011, 11:58:43 PM (11 years ago)
- Branches:
- asyncio, debian/master, debian/stretch-backports, jessie-backports, master, msva, proxy-ticket, upstream
- Children:
- c7c2ad2
- Parents:
- 6223319
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/gnutls_hooks.c
r6223319 re183628 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Copyright 2007 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 22 23 23 24 #if APR_HAS_THREADS 24 # 25 #if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11 25 26 #include <gcrypt.h> 26 27 GCRY_THREAD_OPTION_PTHREAD_IMPL; 27 # 28 #endif 28 29 #endif 29 30 … … 37 38 38 39 static int mpm_is_threaded; 39 static gnutls_datum session_ticket_key = { NULL, 0};40 static gnutls_datum session_ticket_key = {NULL, 0}; 40 41 41 42 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); 42 43 /* use side==0 for server and side==1 for client */ 43 44 static void mgs_add_common_cert_vars(request_rec * r, 44 45 45 gnutls_x509_crt_t cert, int side, 46 int export_certificates_enabled); 46 47 static void mgs_add_common_pgpcert_vars(request_rec * r, 47 gnutls_openpgp_crt_t cert, 48 int side, 49 int export_certificates_enabled); 50 51 static apr_status_t mgs_cleanup_pre_config(void *data) 52 { 53 gnutls_free(session_ticket_key.data); 54 session_ticket_key.data = NULL; 55 session_ticket_key.size = 0; 56 gnutls_global_deinit(); 57 return APR_SUCCESS; 48 gnutls_openpgp_crt_t cert, 49 int side, 50 int export_certificates_enabled); 51 52 static apr_status_t mgs_cleanup_pre_config(void *data) { 53 gnutls_free(session_ticket_key.data); 54 session_ticket_key.data = NULL; 55 session_ticket_key.size = 0; 56 gnutls_global_deinit(); 57 return APR_SUCCESS; 58 58 } 59 59 60 60 #if MOD_GNUTLS_DEBUG 61 static void gnutls_debug_log_all(int level, const char *str) 62 {63 61 62 static void gnutls_debug_log_all(int level, const char *str) { 63 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str); 64 64 } 65 65 66 66 #define _gnutls_log apr_file_printf 67 67 #else 68 # 68 #define _gnutls_log(...) 69 69 #endif 70 70 71 71 int 72 72 mgs_hook_pre_config(apr_pool_t * pconf, 73 apr_pool_t * plog, apr_pool_t * ptemp) 74 { 75 int ret; 73 apr_pool_t * plog, apr_pool_t * ptemp) { 74 int ret; 76 75 77 76 #if MOD_GNUTLS_DEBUG 78 79 80 81 82 83 84 85 86 87 77 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", 78 APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, 79 pconf); 80 81 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 82 83 gnutls_global_set_log_level(9); 84 gnutls_global_set_log_function(gnutls_debug_log_all); 85 _gnutls_log(debug_log_fp, "gnutls: %s\n", 86 gnutls_check_version(NULL)); 88 87 #endif 89 88 90 89 #if APR_HAS_THREADS 91 90 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded); 92 91 #if (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 11) || GNUTLS_VERSION_MAJOR < 2 93 94 95 96 92 if (mpm_is_threaded) { 93 gcry_control(GCRYCTL_SET_THREAD_CBS, 94 &gcry_threads_pthread); 95 } 97 96 #endif 98 97 #else 99 mpm_is_threaded = 0; 100 #endif 101 102 103 if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) { 104 _gnutls_log(debug_log_fp, 105 "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", 106 LIBGNUTLS_VERSION, gnutls_check_version(NULL)); 107 return -3; 108 } 109 110 ret = gnutls_global_init(); 111 if (ret < 0) { 112 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n", 113 gnutls_strerror(ret)); 114 return -3; 115 } 116 117 ret = gnutls_session_ticket_key_generate(&session_ticket_key); 118 if (ret < 0) { 119 _gnutls_log(debug_log_fp, 120 "gnutls_session_ticket_key_generate: %s\n", 121 gnutls_strerror(ret)); 122 } 123 124 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 125 apr_pool_cleanup_null); 126 127 128 return OK; 129 } 130 131 static int mgs_select_virtual_server_cb(gnutls_session_t session) 132 { 133 mgs_handle_t *ctxt; 134 mgs_srvconf_rec *tsc; 135 int ret; 136 int cprio[2]; 137 138 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 139 140 ctxt = gnutls_transport_get_ptr(session); 141 142 /* find the virtual server */ 143 tsc = mgs_find_sni_server(session); 144 145 if (tsc != NULL) 146 ctxt->sc = tsc; 147 148 gnutls_certificate_server_set_request(session, 149 ctxt-> 150 sc->client_verify_mode); 151 152 /* set the new server credentials 153 */ 154 155 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, 156 ctxt->sc->certs); 157 158 gnutls_credentials_set(session, GNUTLS_CRD_ANON, 159 ctxt->sc->anon_creds); 98 mpm_is_threaded = 0; 99 #endif 100 101 102 if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) { 103 _gnutls_log(debug_log_fp, 104 "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", 105 LIBGNUTLS_VERSION, gnutls_check_version(NULL)); 106 return -3; 107 } 108 109 ret = gnutls_global_init(); 110 if (ret < 0) { 111 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n", 112 gnutls_strerror(ret)); 113 return -3; 114 } 115 116 ret = gnutls_session_ticket_key_generate(&session_ticket_key); 117 if (ret < 0) { 118 _gnutls_log(debug_log_fp, 119 "gnutls_session_ticket_key_generate: %s\n", 120 gnutls_strerror(ret)); 121 } 122 123 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 124 apr_pool_cleanup_null); 125 126 127 return OK; 128 } 129 130 static int mgs_select_virtual_server_cb(gnutls_session_t session) { 131 mgs_handle_t *ctxt; 132 mgs_srvconf_rec *tsc; 133 int ret; 134 int cprio[2]; 135 136 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 137 138 ctxt = gnutls_transport_get_ptr(session); 139 140 /* find the virtual server */ 141 tsc = mgs_find_sni_server(session); 142 143 if (tsc != NULL) 144 ctxt->sc = tsc; 145 146 gnutls_certificate_server_set_request(session, 147 ctxt-> 148 sc->client_verify_mode); 149 150 /* set the new server credentials 151 */ 152 153 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, 154 ctxt->sc->certs); 155 156 gnutls_credentials_set(session, GNUTLS_CRD_ANON, 157 ctxt->sc->anon_creds); 160 158 161 159 #ifdef ENABLE_SRP 162 if (ctxt->sc->srp_tpasswd_conf_file != NULL 163 && ctxt->sc->srp_tpasswd_file != NULL) { 164 gnutls_credentials_set(session, GNUTLS_CRD_SRP, 165 ctxt->sc->srp_creds); 166 } 167 #endif 168 169 /* update the priorities - to avoid negotiating a ciphersuite that is not 170 * enabled on this virtual server. Note that here we ignore the version 171 * negotiation. 172 */ 173 ret = gnutls_priority_set(session, ctxt->sc->priorities); 174 /* actually it shouldn't fail since we have checked at startup */ 175 if (ret < 0) 176 return ret; 177 178 /* If both certificate types are not present disallow them from 179 * being negotiated. 180 */ 181 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) { 182 cprio[0] = GNUTLS_CRT_X509; 183 cprio[1] = 0; 184 gnutls_certificate_type_set_priority(session, cprio); 185 } else if (ctxt->sc->cert_pgp != NULL 186 && ctxt->sc->certs_x509[0] == NULL) { 187 cprio[0] = GNUTLS_CRT_OPENPGP; 188 cprio[1] = 0; 189 gnutls_certificate_type_set_priority(session, cprio); 190 } 191 192 return 0; 193 } 194 195 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) 196 { 197 mgs_handle_t *ctxt; 198 199 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 200 ctxt = gnutls_transport_get_ptr(session); 201 202 if (ctxt == NULL) 203 return GNUTLS_E_INTERNAL_ERROR; 204 205 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { 206 ret->type = GNUTLS_CRT_X509; 207 ret->ncerts = ctxt->sc->certs_x509_num; 208 ret->deinit_all = 0; 209 210 ret->cert.x509 = ctxt->sc->certs_x509; 211 ret->key.x509 = ctxt->sc->privkey_x509; 212 213 return 0; 214 } else if (gnutls_certificate_type_get(session) == 215 GNUTLS_CRT_OPENPGP) { 216 ret->type = GNUTLS_CRT_OPENPGP; 217 ret->ncerts = 1; 218 ret->deinit_all = 0; 219 220 ret->cert.pgp = ctxt->sc->cert_pgp; 221 ret->key.pgp = ctxt->sc->privkey_pgp; 222 223 return 0; 224 225 } 226 227 return GNUTLS_E_INTERNAL_ERROR; 160 if (ctxt->sc->srp_tpasswd_conf_file != NULL 161 && ctxt->sc->srp_tpasswd_file != NULL) { 162 gnutls_credentials_set(session, GNUTLS_CRD_SRP, 163 ctxt->sc->srp_creds); 164 } 165 #endif 166 167 /* update the priorities - to avoid negotiating a ciphersuite that is not 168 * enabled on this virtual server. Note that here we ignore the version 169 * negotiation. 170 */ 171 ret = gnutls_priority_set(session, ctxt->sc->priorities); 172 /* actually it shouldn't fail since we have checked at startup */ 173 if (ret < 0) 174 return ret; 175 176 /* If both certificate types are not present disallow them from 177 * being negotiated. 178 */ 179 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) { 180 cprio[0] = GNUTLS_CRT_X509; 181 cprio[1] = 0; 182 gnutls_certificate_type_set_priority(session, cprio); 183 } else if (ctxt->sc->cert_pgp != NULL 184 && ctxt->sc->certs_x509[0] == NULL) { 185 cprio[0] = GNUTLS_CRT_OPENPGP; 186 cprio[1] = 0; 187 gnutls_certificate_type_set_priority(session, cprio); 188 } 189 190 return 0; 191 } 192 193 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) { 194 mgs_handle_t *ctxt; 195 196 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 197 ctxt = gnutls_transport_get_ptr(session); 198 199 if (ctxt == NULL) 200 return GNUTLS_E_INTERNAL_ERROR; 201 202 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { 203 ret->type = GNUTLS_CRT_X509; 204 ret->ncerts = ctxt->sc->certs_x509_num; 205 ret->deinit_all = 0; 206 207 ret->cert.x509 = ctxt->sc->certs_x509; 208 ret->key.x509 = ctxt->sc->privkey_x509; 209 210 return 0; 211 } else if (gnutls_certificate_type_get(session) == 212 GNUTLS_CRT_OPENPGP) { 213 ret->type = GNUTLS_CRT_OPENPGP; 214 ret->ncerts = 1; 215 ret->deinit_all = 0; 216 217 ret->cert.pgp = ctxt->sc->cert_pgp; 218 ret->key.pgp = ctxt->sc->privkey_pgp; 219 220 return 0; 221 222 } 223 224 return GNUTLS_E_INTERNAL_ERROR; 228 225 } 229 226 230 227 /* 2048-bit group parameters from SRP specification */ 231 228 const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" 232 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"233 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"234 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"235 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"236 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"237 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"238 "-----END DH PARAMETERS-----\n";229 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" 230 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" 231 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n" 232 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n" 233 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n" 234 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n" 235 "-----END DH PARAMETERS-----\n"; 239 236 240 237 /* Read the common name or the alternative name of the certificate. … … 244 241 */ 245 242 static int read_crt_cn(server_rec * s, apr_pool_t * p, 246 gnutls_x509_crt_t cert, char **cert_cn) 247 { 248 int rv = 0, i; 249 size_t data_len; 250 251 252 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 253 *cert_cn = NULL; 254 255 data_len = 0; 256 rv = gnutls_x509_crt_get_dn_by_oid(cert, 257 GNUTLS_OID_X520_COMMON_NAME, 258 0, 0, NULL, &data_len); 259 260 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 261 *cert_cn = apr_palloc(p, data_len); 262 rv = gnutls_x509_crt_get_dn_by_oid(cert, 263 GNUTLS_OID_X520_COMMON_NAME, 264 0, 0, *cert_cn, 265 &data_len); 266 } else { /* No CN return subject alternative name */ 267 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 268 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 269 s->server_hostname, s->port); 270 rv = 0; 271 /* read subject alternative name */ 272 for (i = 0; !(rv < 0); i++) { 273 data_len = 0; 274 rv = gnutls_x509_crt_get_subject_alt_name(cert, i, 275 NULL, 276 &data_len, 277 NULL); 278 279 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER 280 && data_len > 1) { 281 /* FIXME: not very efficient. What if we have several alt names 282 * before DNSName? 283 */ 284 *cert_cn = apr_palloc(p, data_len + 1); 285 286 rv = gnutls_x509_crt_get_subject_alt_name 287 (cert, i, *cert_cn, &data_len, NULL); 288 (*cert_cn)[data_len] = 0; 289 290 if (rv == GNUTLS_SAN_DNSNAME) 291 break; 292 } 293 } 294 } 295 296 return rv; 243 gnutls_x509_crt_t cert, char **cert_cn) { 244 int rv = 0, i; 245 size_t data_len; 246 247 248 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 249 *cert_cn = NULL; 250 251 data_len = 0; 252 rv = gnutls_x509_crt_get_dn_by_oid(cert, 253 GNUTLS_OID_X520_COMMON_NAME, 254 0, 0, NULL, &data_len); 255 256 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 257 *cert_cn = apr_palloc(p, data_len); 258 rv = gnutls_x509_crt_get_dn_by_oid(cert, 259 GNUTLS_OID_X520_COMMON_NAME, 260 0, 0, *cert_cn, 261 &data_len); 262 } else { /* No CN return subject alternative name */ 263 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 264 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 265 s->server_hostname, s->port); 266 rv = 0; 267 /* read subject alternative name */ 268 for (i = 0; !(rv < 0); i++) { 269 data_len = 0; 270 rv = gnutls_x509_crt_get_subject_alt_name(cert, i, 271 NULL, 272 &data_len, 273 NULL); 274 275 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER 276 && data_len > 1) { 277 /* FIXME: not very efficient. What if we have several alt names 278 * before DNSName? 279 */ 280 *cert_cn = apr_palloc(p, data_len + 1); 281 282 rv = gnutls_x509_crt_get_subject_alt_name 283 (cert, i, *cert_cn, &data_len, NULL); 284 (*cert_cn)[data_len] = 0; 285 286 if (rv == GNUTLS_SAN_DNSNAME) 287 break; 288 } 289 } 290 } 291 292 return rv; 297 293 } 298 294 299 295 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p, 300 gnutls_openpgp_crt_t cert, char **cert_cn) 301 { 302 int rv = 0; 303 size_t data_len; 304 305 306 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 307 *cert_cn = NULL; 308 309 data_len = 0; 310 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); 311 312 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 313 *cert_cn = apr_palloc(p, data_len); 314 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, 315 &data_len); 316 } else { /* No CN return subject alternative name */ 317 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 318 "No name found in PGP certificate for '%s:%d'.", 319 s->server_hostname, s->port); 320 } 321 322 return rv; 323 } 324 296 gnutls_openpgp_crt_t cert, char **cert_cn) { 297 int rv = 0; 298 size_t data_len; 299 300 301 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 302 *cert_cn = NULL; 303 304 data_len = 0; 305 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); 306 307 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 308 *cert_cn = apr_palloc(p, data_len); 309 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, 310 &data_len); 311 } else { /* No CN return subject alternative name */ 312 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 313 "No name found in PGP certificate for '%s:%d'.", 314 s->server_hostname, s->port); 315 } 316 317 return rv; 318 } 325 319 326 320 int 327 321 mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 328 apr_pool_t * ptemp, server_rec * base_server) 329 { 330 int rv; 331 server_rec *s; 332 gnutls_dh_params_t dh_params = NULL; 333 gnutls_rsa_params_t rsa_params = NULL; 334 mgs_srvconf_rec *sc; 335 mgs_srvconf_rec *sc_base; 336 void *data = NULL; 337 int first_run = 0; 338 const char *userdata_key = "mgs_init"; 339 340 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 341 apr_pool_userdata_get(&data, userdata_key, 342 base_server->process->pool); 343 if (data == NULL) { 344 first_run = 1; 345 apr_pool_userdata_set((const void *) 1, userdata_key, 346 apr_pool_cleanup_null, 347 base_server->process->pool); 348 } 349 350 351 s = base_server; 352 sc_base = 353 (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 354 &gnutls_module); 355 356 gnutls_dh_params_init(&dh_params); 357 358 if (sc_base->dh_params == NULL) { 359 gnutls_datum pdata = { 360 (void *) static_dh_params, 361 sizeof(static_dh_params) 362 }; 363 /* loading defaults */ 364 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 365 GNUTLS_X509_FMT_PEM); 366 367 if (rv < 0) { 368 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 369 "GnuTLS: Unable to load DH Params: (%d) %s", 370 rv, gnutls_strerror(rv)); 371 exit(rv); 372 } 373 } else 374 dh_params = sc_base->dh_params; 375 376 if (sc_base->rsa_params != NULL) 377 rsa_params = sc_base->rsa_params; 378 379 /* else not an error but RSA-EXPORT ciphersuites are not available 380 */ 381 382 rv = mgs_cache_post_config(p, s, sc_base); 383 if (rv != 0) { 384 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 385 "GnuTLS: Post Config for GnuTLSCache Failed." 386 " Shutting Down."); 387 exit(-1); 388 } 389 390 for (s = base_server; s; s = s->next) { 391 void *load = NULL; 392 sc = (mgs_srvconf_rec *) 393 ap_get_module_config(s->module_config, &gnutls_module); 394 sc->cache_type = sc_base->cache_type; 395 sc->cache_config = sc_base->cache_config; 396 397 /* Check if the priorities have been set */ 398 if (sc->priorities == NULL 399 && sc->enabled == GNUTLS_ENABLED_TRUE) { 400 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 401 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!", 402 s->server_hostname, s->port); 403 exit(-1); 404 } 405 406 /* Check if DH or RSA params have been set per host */ 407 if (sc->rsa_params != NULL) 408 load = sc->rsa_params; 409 else if (rsa_params) 410 load = rsa_params; 411 412 if (load != NULL) 413 gnutls_certificate_set_rsa_export_params(sc->certs, 414 load); 415 416 417 load = NULL; 418 if (sc->dh_params != NULL) 419 load = sc->dh_params; 420 else if (dh_params) 421 load = dh_params; 422 423 if (load != NULL) { /* not needed but anyway */ 424 gnutls_certificate_set_dh_params(sc->certs, load); 425 gnutls_anon_set_server_dh_params(sc->anon_creds, 426 load); 427 } 428 429 gnutls_certificate_server_set_retrieve_function(sc->certs, 430 cert_retrieve_fn); 322 apr_pool_t * ptemp, server_rec * base_server) { 323 int rv; 324 server_rec *s; 325 gnutls_dh_params_t dh_params = NULL; 326 gnutls_rsa_params_t rsa_params = NULL; 327 mgs_srvconf_rec *sc; 328 mgs_srvconf_rec *sc_base; 329 void *data = NULL; 330 int first_run = 0; 331 const char *userdata_key = "mgs_init"; 332 333 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 334 apr_pool_userdata_get(&data, userdata_key, 335 base_server->process->pool); 336 if (data == NULL) { 337 first_run = 1; 338 apr_pool_userdata_set((const void *) 1, userdata_key, 339 apr_pool_cleanup_null, 340 base_server->process->pool); 341 } 342 343 344 s = base_server; 345 sc_base = 346 (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 347 &gnutls_module); 348 349 gnutls_dh_params_init(&dh_params); 350 351 if (sc_base->dh_params == NULL) { 352 gnutls_datum pdata = { 353 (void *) static_dh_params, 354 sizeof (static_dh_params) 355 }; 356 /* loading defaults */ 357 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 358 GNUTLS_X509_FMT_PEM); 359 360 if (rv < 0) { 361 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 362 "GnuTLS: Unable to load DH Params: (%d) %s", 363 rv, gnutls_strerror(rv)); 364 exit(rv); 365 } 366 } else 367 dh_params = sc_base->dh_params; 368 369 if (sc_base->rsa_params != NULL) 370 rsa_params = sc_base->rsa_params; 371 372 /* else not an error but RSA-EXPORT ciphersuites are not available 373 */ 374 375 rv = mgs_cache_post_config(p, s, sc_base); 376 if (rv != 0) { 377 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 378 "GnuTLS: Post Config for GnuTLSCache Failed." 379 " Shutting Down."); 380 exit(-1); 381 } 382 383 for (s = base_server; s; s = s->next) { 384 void *load = NULL; 385 sc = (mgs_srvconf_rec *) 386 ap_get_module_config(s->module_config, &gnutls_module); 387 sc->cache_type = sc_base->cache_type; 388 sc->cache_config = sc_base->cache_config; 389 390 /* Check if the priorities have been set */ 391 if (sc->priorities == NULL 392 && sc->enabled == GNUTLS_ENABLED_TRUE) { 393 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 394 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!", 395 s->server_hostname, s->port); 396 exit(-1); 397 } 398 399 /* Check if DH or RSA params have been set per host */ 400 if (sc->rsa_params != NULL) 401 load = sc->rsa_params; 402 else if (rsa_params) 403 load = rsa_params; 404 405 if (load != NULL) 406 gnutls_certificate_set_rsa_export_params(sc->certs, 407 load); 408 409 410 load = NULL; 411 if (sc->dh_params != NULL) 412 load = sc->dh_params; 413 else if (dh_params) 414 load = dh_params; 415 416 if (load != NULL) { /* not needed but anyway */ 417 gnutls_certificate_set_dh_params(sc->certs, load); 418 gnutls_anon_set_server_dh_params(sc->anon_creds, 419 load); 420 } 421 422 gnutls_certificate_server_set_retrieve_function(sc->certs, 423 cert_retrieve_fn); 431 424 432 425 #ifdef ENABLE_SRP 433 if (sc->srp_tpasswd_conf_file != NULL 434 && sc->srp_tpasswd_file != NULL) { 435 rv = gnutls_srp_set_server_credentials_file 436 (sc->srp_creds, sc->srp_tpasswd_file, 437 sc->srp_tpasswd_conf_file); 438 439 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) { 440 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 441 s, 442 "[GnuTLS] - Host '%s:%d' is missing a " 443 "SRP password or conf File!", 444 s->server_hostname, s->port); 445 exit(-1); 446 } 447 } 448 #endif 449 450 if (sc->certs_x509[0] == NULL && 451 sc->cert_pgp == NULL && 452 sc->enabled == GNUTLS_ENABLED_TRUE) { 453 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 454 "[GnuTLS] - Host '%s:%d' is missing a " 455 "Certificate File!", 456 s->server_hostname, s->port); 457 exit(-1); 458 } 459 460 if (sc->enabled == GNUTLS_ENABLED_TRUE && 461 ((sc->certs_x509[0] != NULL 462 && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL 463 && sc->privkey_pgp 464 == NULL))) { 465 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 466 "[GnuTLS] - Host '%s:%d' is missing a " 467 "Private Key File!", 468 s->server_hostname, s->port); 469 exit(-1); 470 } 471 472 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 473 rv = read_crt_cn(s, p, sc->certs_x509[0], 474 &sc->cert_cn); 475 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */ 476 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, 477 &sc->cert_cn); 478 479 if (rv < 0) { 480 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 481 s, 482 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 483 s->server_hostname, s->port); 484 sc->cert_cn = NULL; 485 continue; 486 } 487 } 488 } 489 490 491 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 492 493 return OK; 494 } 495 496 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) 497 { 498 apr_status_t rv = APR_SUCCESS; 499 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 500 &gnutls_module); 501 502 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 503 if (sc->cache_type != mgs_cache_none) { 504 rv = mgs_cache_child_init(p, s, sc); 505 if (rv != APR_SUCCESS) { 506 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 507 "[GnuTLS] - Failed to run Cache Init"); 508 } 509 } 510 } 511 512 const char *mgs_hook_http_scheme(const request_rec * r) 513 { 514 mgs_srvconf_rec *sc; 515 516 if (r == NULL) 517 return NULL; 518 519 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 520 server->module_config, 521 &gnutls_module); 522 523 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 524 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 525 return NULL; 526 } 527 528 return "https"; 529 } 530 531 apr_port_t mgs_hook_default_port(const request_rec * r) 532 { 533 mgs_srvconf_rec *sc; 534 535 if (r == NULL) 536 return 0; 537 538 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 539 server->module_config, 540 &gnutls_module); 541 542 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 543 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 544 return 0; 545 } 546 547 return 443; 426 if (sc->srp_tpasswd_conf_file != NULL 427 && sc->srp_tpasswd_file != NULL) { 428 rv = gnutls_srp_set_server_credentials_file 429 (sc->srp_creds, sc->srp_tpasswd_file, 430 sc->srp_tpasswd_conf_file); 431 432 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) { 433 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 434 s, 435 "[GnuTLS] - Host '%s:%d' is missing a " 436 "SRP password or conf File!", 437 s->server_hostname, s->port); 438 exit(-1); 439 } 440 } 441 #endif 442 443 if (sc->certs_x509[0] == NULL && 444 sc->cert_pgp == NULL && 445 sc->enabled == GNUTLS_ENABLED_TRUE) { 446 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 447 "[GnuTLS] - Host '%s:%d' is missing a " 448 "Certificate File!", 449 s->server_hostname, s->port); 450 exit(-1); 451 } 452 453 if (sc->enabled == GNUTLS_ENABLED_TRUE && 454 ((sc->certs_x509[0] != NULL 455 && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL 456 && sc->privkey_pgp 457 == NULL))) { 458 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 459 "[GnuTLS] - Host '%s:%d' is missing a " 460 "Private Key File!", 461 s->server_hostname, s->port); 462 exit(-1); 463 } 464 465 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 466 rv = read_crt_cn(s, p, sc->certs_x509[0], 467 &sc->cert_cn); 468 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */ 469 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, 470 &sc->cert_cn); 471 472 if (rv < 0) { 473 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 474 s, 475 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 476 s->server_hostname, s->port); 477 sc->cert_cn = NULL; 478 continue; 479 } 480 } 481 } 482 483 484 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 485 486 return OK; 487 } 488 489 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) { 490 apr_status_t rv = APR_SUCCESS; 491 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 492 &gnutls_module); 493 494 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 495 if (sc->cache_type != mgs_cache_none) { 496 rv = mgs_cache_child_init(p, s, sc); 497 if (rv != APR_SUCCESS) { 498 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 499 "[GnuTLS] - Failed to run Cache Init"); 500 } 501 } 502 } 503 504 const char *mgs_hook_http_scheme(const request_rec * r) { 505 mgs_srvconf_rec *sc; 506 507 if (r == NULL) 508 return NULL; 509 510 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 511 server->module_config, 512 &gnutls_module); 513 514 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 515 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 516 return NULL; 517 } 518 519 return "https"; 520 } 521 522 apr_port_t mgs_hook_default_port(const request_rec * r) { 523 mgs_srvconf_rec *sc; 524 525 if (r == NULL) 526 return 0; 527 528 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 529 server->module_config, 530 &gnutls_module); 531 532 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 533 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 534 return 0; 535 } 536 537 return 443; 548 538 } 549 539 … … 551 541 552 542 #if USING_2_1_RECENT 543 553 544 typedef struct { 554 555 556 545 mgs_handle_t *ctxt; 546 mgs_srvconf_rec *sc; 547 const char *sni_name; 557 548 } vhost_cb_rec; 558 549 559 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) 560 { 561 mgs_srvconf_rec *tsc; 562 vhost_cb_rec *x = baton; 563 564 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 565 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 566 &gnutls_module); 567 568 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 569 return 0; 570 } 571 572 /* The CN can contain a * -- this will match those too. */ 573 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 574 /* found a match */ 550 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) { 551 mgs_srvconf_rec *tsc; 552 vhost_cb_rec *x = baton; 553 554 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 555 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 556 &gnutls_module); 557 558 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 559 return 0; 560 } 561 562 /* The CN can contain a * -- this will match those too. */ 563 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 564 /* found a match */ 575 565 #if MOD_GNUTLS_DEBUG 576 577 578 579 580 #endif 581 582 583 584 585 586 587 588 589 590 566 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 567 x->ctxt->c->base_server, 568 "GnuTLS: Virtual Host CB: " 569 "'%s' == '%s'", tsc->cert_cn, x->sni_name); 570 #endif 571 /* Because we actually change the server used here, we need to reset 572 * things like ClientVerify. 573 */ 574 x->sc = tsc; 575 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our 576 * certificate structure *should* change when the server changes. 577 * acccckkkkkk. 578 */ 579 return 1; 580 } else { 591 581 #if MOD_GNUTLS_DEBUG 592 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 593 x->ctxt->c->base_server, 594 "GnuTLS: Virtual Host CB: " 595 "'%s' != '%s'", tsc->cert_cn, x->sni_name); 596 #endif 597 598 } 599 return 0; 600 } 601 #endif 602 603 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) 604 { 605 int rv; 606 unsigned int sni_type; 607 size_t data_len = MAX_HOST_LEN; 608 char sni_name[MAX_HOST_LEN]; 609 mgs_handle_t *ctxt; 582 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 583 x->ctxt->c->base_server, 584 "GnuTLS: Virtual Host CB: " 585 "'%s' != '%s'", tsc->cert_cn, x->sni_name); 586 #endif 587 588 } 589 return 0; 590 } 591 #endif 592 593 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) { 594 int rv; 595 unsigned int sni_type; 596 size_t data_len = MAX_HOST_LEN; 597 char sni_name[MAX_HOST_LEN]; 598 mgs_handle_t *ctxt; 610 599 #if USING_2_1_RECENT 611 600 vhost_cb_rec cbx; 612 601 #else 613 614 615 #endif 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 602 server_rec *s; 603 mgs_srvconf_rec *tsc; 604 #endif 605 606 if (session == NULL) 607 return NULL; 608 609 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 610 ctxt = gnutls_transport_get_ptr(session); 611 612 rv = gnutls_server_name_get(ctxt->session, sni_name, 613 &data_len, &sni_type, 0); 614 615 if (rv != 0) { 616 return NULL; 617 } 618 619 if (sni_type != GNUTLS_NAME_DNS) { 620 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 621 ctxt->c->base_server, 622 "GnuTLS: Unknown type '%d' for SNI: " 623 "'%s'", sni_type, sni_name); 624 return NULL; 625 } 637 626 638 627 /** … … 641 630 */ 642 631 #if USING_2_1_RECENT 643 644 645 646 647 648 649 650 632 cbx.ctxt = ctxt; 633 cbx.sc = NULL; 634 cbx.sni_name = sni_name; 635 636 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); 637 if (rv == 1) { 638 return cbx.sc; 639 } 651 640 #else 652 653 654 655 656 657 658 659 641 for (s = ap_server_conf; s; s = s->next) { 642 643 tsc = 644 (mgs_srvconf_rec *) 645 ap_get_module_config(s->module_config, &gnutls_module); 646 if (tsc->enabled != GNUTLS_ENABLED_TRUE) { 647 continue; 648 } 660 649 #if MOD_GNUTLS_DEBUG 661 662 663 664 665 666 667 668 669 #endif 670 671 650 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 651 ctxt->c->base_server, 652 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", 653 tsc->cert_cn, rv, 654 gnutls_pk_algorithm_get_name 655 (gnutls_x509_privkey_get_pk_algorithm 656 (ctxt->sc->privkey_x509)), (unsigned int) s, 657 (unsigned int) s->next, (unsigned int) tsc); 658 #endif 659 /* The CN can contain a * -- this will match those too. */ 660 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) { 672 661 #if MOD_GNUTLS_DEBUG 673 674 675 676 677 678 #endif 679 680 681 682 #endif 683 662 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 663 ctxt->c->base_server, 664 "GnuTLS: Virtual Host: " 665 "'%s' == '%s'", tsc->cert_cn, 666 sni_name); 667 #endif 668 return tsc; 669 } 670 } 671 #endif 672 return NULL; 684 673 } 685 674 686 675 687 676 static const int protocol_priority[] = { 688 677 GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 689 678 }; 690 679 691 692 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) 693 { 694 mgs_handle_t *ctxt; 695 mgs_srvconf_rec *sc = 696 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 697 module_config, 698 &gnutls_module); 699 700 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 701 ctxt = apr_pcalloc(pool, sizeof(*ctxt)); 702 ctxt->c = c; 703 ctxt->sc = sc; 704 ctxt->status = 0; 705 706 ctxt->input_rc = APR_SUCCESS; 707 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc); 708 ctxt->input_cbuf.length = 0; 709 710 ctxt->output_rc = APR_SUCCESS; 711 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc); 712 ctxt->output_blen = 0; 713 ctxt->output_length = 0; 714 715 gnutls_init(&ctxt->session, GNUTLS_SERVER); 716 if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) 717 gnutls_session_ticket_enable_server(ctxt->session, 718 &session_ticket_key); 719 720 /* because we don't set any default priorities here (we set later at 721 * the user hello callback) we need to at least set this in order for 722 * gnutls to be able to read packets. 723 */ 724 gnutls_protocol_set_priority(ctxt->session, protocol_priority); 725 726 gnutls_handshake_set_post_client_hello_function(ctxt->session, 727 mgs_select_virtual_server_cb); 728 729 mgs_cache_session_init(ctxt); 730 731 return ctxt; 732 } 733 734 int mgs_hook_pre_connection(conn_rec * c, void *csd) 735 { 736 mgs_handle_t *ctxt; 737 mgs_srvconf_rec *sc; 738 739 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 740 741 if (c == NULL) { 742 return DECLINED; 743 } 744 745 sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 746 module_config, 747 &gnutls_module); 748 749 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 750 return DECLINED; 751 } 752 753 if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip,c->local_ip) == 0) { 680 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) { 681 mgs_handle_t *ctxt; 682 mgs_srvconf_rec *sc = 683 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 684 module_config, 685 &gnutls_module); 686 687 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 688 ctxt = apr_pcalloc(pool, sizeof (*ctxt)); 689 ctxt->c = c; 690 ctxt->sc = sc; 691 ctxt->status = 0; 692 693 ctxt->input_rc = APR_SUCCESS; 694 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc); 695 ctxt->input_cbuf.length = 0; 696 697 ctxt->output_rc = APR_SUCCESS; 698 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc); 699 ctxt->output_blen = 0; 700 ctxt->output_length = 0; 701 702 gnutls_init(&ctxt->session, GNUTLS_SERVER); 703 if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) 704 gnutls_session_ticket_enable_server(ctxt->session, 705 &session_ticket_key); 706 707 /* because we don't set any default priorities here (we set later at 708 * the user hello callback) we need to at least set this in order for 709 * gnutls to be able to read packets. 710 */ 711 gnutls_protocol_set_priority(ctxt->session, protocol_priority); 712 713 gnutls_handshake_set_post_client_hello_function(ctxt->session, 714 mgs_select_virtual_server_cb); 715 716 mgs_cache_session_init(ctxt); 717 718 return ctxt; 719 } 720 721 int mgs_hook_pre_connection(conn_rec * c, void *csd) { 722 mgs_handle_t *ctxt; 723 mgs_srvconf_rec *sc; 724 725 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 726 727 if (c == NULL) { 728 return DECLINED; 729 } 730 731 sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 732 module_config, 733 &gnutls_module); 734 735 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 736 return DECLINED; 737 } 738 739 if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip, c->local_ip) == 0) { 754 740 /* Connection initiated by Apache (mod_proxy) => ignore */ 755 return OK; 756 } 757 758 ctxt = create_gnutls_handle(c->pool, c); 759 760 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 761 762 gnutls_transport_set_pull_function(ctxt->session, 763 mgs_transport_read); 764 gnutls_transport_set_push_function(ctxt->session, 765 mgs_transport_write); 766 gnutls_transport_set_ptr(ctxt->session, ctxt); 767 768 ctxt->input_filter = 769 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 770 ctxt->output_filter = 771 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 772 773 return OK; 774 } 775 776 int mgs_hook_fixups(request_rec * r) 777 { 778 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 779 char buf[AP_IOBUFSIZE]; 780 const char *tmp; 781 size_t len; 782 mgs_handle_t *ctxt; 783 int rv = OK; 784 785 if (r == NULL) 786 return DECLINED; 787 788 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 789 apr_table_t *env = r->subprocess_env; 790 791 ctxt = 792 ap_get_module_config(r->connection->conn_config, 793 &gnutls_module); 794 795 if (!ctxt || ctxt->session == NULL) { 796 return DECLINED; 797 } 798 799 apr_table_setn(env, "HTTPS", "on"); 800 801 apr_table_setn(env, "SSL_VERSION_LIBRARY", 802 "GnuTLS/" LIBGNUTLS_VERSION); 803 apr_table_setn(env, "SSL_VERSION_INTERFACE", 804 "mod_gnutls/" MOD_GNUTLS_VERSION); 805 806 apr_table_setn(env, "SSL_PROTOCOL", 807 gnutls_protocol_get_name(gnutls_protocol_get_version 808 (ctxt->session))); 809 810 /* should have been called SSL_CIPHERSUITE instead */ 811 apr_table_setn(env, "SSL_CIPHER", 812 gnutls_cipher_suite_get_name(gnutls_kx_get 813 (ctxt->session), 814 gnutls_cipher_get 815 (ctxt->session), 816 gnutls_mac_get 817 (ctxt->session))); 818 819 apr_table_setn(env, "SSL_COMPRESS_METHOD", 820 gnutls_compression_get_name(gnutls_compression_get 821 (ctxt->session))); 741 return OK; 742 } 743 744 ctxt = create_gnutls_handle(c->pool, c); 745 746 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 747 748 gnutls_transport_set_pull_function(ctxt->session, 749 mgs_transport_read); 750 gnutls_transport_set_push_function(ctxt->session, 751 mgs_transport_write); 752 gnutls_transport_set_ptr(ctxt->session, ctxt); 753 754 ctxt->input_filter = 755 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 756 ctxt->output_filter = 757 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 758 759 return OK; 760 } 761 762 int mgs_hook_fixups(request_rec * r) { 763 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 764 char buf[AP_IOBUFSIZE]; 765 const char *tmp; 766 size_t len; 767 mgs_handle_t *ctxt; 768 int rv = OK; 769 770 if (r == NULL) 771 return DECLINED; 772 773 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 774 apr_table_t *env = r->subprocess_env; 775 776 ctxt = 777 ap_get_module_config(r->connection->conn_config, 778 &gnutls_module); 779 780 if (!ctxt || ctxt->session == NULL) { 781 return DECLINED; 782 } 783 784 apr_table_setn(env, "HTTPS", "on"); 785 786 apr_table_setn(env, "SSL_VERSION_LIBRARY", 787 "GnuTLS/" LIBGNUTLS_VERSION); 788 apr_table_setn(env, "SSL_VERSION_INTERFACE", 789 "mod_gnutls/" MOD_GNUTLS_VERSION); 790 791 apr_table_setn(env, "SSL_PROTOCOL", 792 gnutls_protocol_get_name(gnutls_protocol_get_version 793 (ctxt->session))); 794 795 /* should have been called SSL_CIPHERSUITE instead */ 796 apr_table_setn(env, "SSL_CIPHER", 797 gnutls_cipher_suite_get_name(gnutls_kx_get 798 (ctxt->session), 799 gnutls_cipher_get 800 (ctxt->session), 801 gnutls_mac_get 802 (ctxt->session))); 803 804 apr_table_setn(env, "SSL_COMPRESS_METHOD", 805 gnutls_compression_get_name(gnutls_compression_get 806 (ctxt->session))); 822 807 823 808 #ifdef ENABLE_SRP 824 tmp = gnutls_srp_server_get_username(ctxt->session); 825 apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : ""); 826 #endif 827 828 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL) 829 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 830 831 unsigned int key_size = 832 8 * 833 gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)); 834 tmp = apr_psprintf(r->pool, "%u", key_size); 835 836 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 837 838 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 839 840 apr_table_setn(env, "SSL_CIPHER_EXPORT", 841 (key_size <= 40) ? "true" : "false"); 842 843 len = sizeof(sbuf); 844 gnutls_session_get_id(ctxt->session, sbuf, &len); 845 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 846 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 847 848 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 849 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, 850 ctxt-> 851 sc->export_certificates_enabled); 852 else if (gnutls_certificate_type_get(ctxt->session) == 853 GNUTLS_CRT_OPENPGP) 854 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, 855 ctxt-> 856 sc->export_certificates_enabled); 857 858 return rv; 859 } 860 861 int mgs_hook_authz(request_rec * r) 862 { 863 int rv; 864 mgs_handle_t *ctxt; 865 mgs_dirconf_rec *dc; 866 867 if (r == NULL) 868 return DECLINED; 869 870 dc = ap_get_module_config(r->per_dir_config, &gnutls_module); 871 872 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 873 ctxt = 874 ap_get_module_config(r->connection->conn_config, 875 &gnutls_module); 876 877 if (!ctxt || ctxt->session == NULL) { 878 return DECLINED; 879 } 880 881 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 882 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 883 "GnuTLS: Directory set to Ignore Client Certificate!"); 884 } else { 885 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 886 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 887 "GnuTLS: Attempting to rehandshake with peer. %d %d", 888 ctxt->sc->client_verify_mode, 889 dc->client_verify_mode); 890 891 /* If we already have a client certificate, there's no point in 892 * re-handshaking... */ 893 rv = mgs_cert_verify(r, ctxt); 894 if (rv != DECLINED && rv != HTTP_FORBIDDEN) 895 return rv; 896 897 gnutls_certificate_server_set_request 898 (ctxt->session, dc->client_verify_mode); 899 900 if (mgs_rehandshake(ctxt) != 0) { 901 return HTTP_FORBIDDEN; 902 } 903 } else if (ctxt->sc->client_verify_mode == 904 GNUTLS_CERT_IGNORE) { 809 tmp = gnutls_srp_server_get_username(ctxt->session); 810 apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : ""); 811 #endif 812 813 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL) 814 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 815 816 unsigned int key_size = 817 8 * 818 gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)); 819 tmp = apr_psprintf(r->pool, "%u", key_size); 820 821 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 822 823 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 824 825 apr_table_setn(env, "SSL_CIPHER_EXPORT", 826 (key_size <= 40) ? "true" : "false"); 827 828 len = sizeof (sbuf); 829 gnutls_session_get_id(ctxt->session, sbuf, &len); 830 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 831 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 832 833 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 834 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, 835 ctxt-> 836 sc->export_certificates_enabled); 837 else if (gnutls_certificate_type_get(ctxt->session) == 838 GNUTLS_CRT_OPENPGP) 839 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, 840 ctxt-> 841 sc->export_certificates_enabled); 842 843 return rv; 844 } 845 846 int mgs_hook_authz(request_rec * r) { 847 int rv; 848 mgs_handle_t *ctxt; 849 mgs_dirconf_rec *dc; 850 851 if (r == NULL) 852 return DECLINED; 853 854 dc = ap_get_module_config(r->per_dir_config, &gnutls_module); 855 856 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 857 ctxt = 858 ap_get_module_config(r->connection->conn_config, 859 &gnutls_module); 860 861 if (!ctxt || ctxt->session == NULL) { 862 return DECLINED; 863 } 864 865 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 866 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 867 "GnuTLS: Directory set to Ignore Client Certificate!"); 868 } else { 869 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 870 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 871 "GnuTLS: Attempting to rehandshake with peer. %d %d", 872 ctxt->sc->client_verify_mode, 873 dc->client_verify_mode); 874 875 /* If we already have a client certificate, there's no point in 876 * re-handshaking... */ 877 rv = mgs_cert_verify(r, ctxt); 878 if (rv != DECLINED && rv != HTTP_FORBIDDEN) 879 return rv; 880 881 gnutls_certificate_server_set_request 882 (ctxt->session, dc->client_verify_mode); 883 884 if (mgs_rehandshake(ctxt) != 0) { 885 return HTTP_FORBIDDEN; 886 } 887 } else if (ctxt->sc->client_verify_mode == 888 GNUTLS_CERT_IGNORE) { 905 889 #if MOD_GNUTLS_DEBUG 906 907 908 #endif 909 910 911 912 913 914 915 916 917 918 919 890 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 891 "GnuTLS: Peer is set to IGNORE"); 892 #endif 893 return DECLINED; 894 } 895 rv = mgs_cert_verify(r, ctxt); 896 if (rv != DECLINED && 897 (rv != HTTP_FORBIDDEN || 898 dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) { 899 return rv; 900 } 901 } 902 903 return DECLINED; 920 904 } 921 905 … … 929 913 */ 930 914 #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") 915 931 916 static void 932 917 mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, 933 int export_certificates_enabled) 934 { 935 unsigned char sbuf[64]; /* buffer to hold serials */ 936 char buf[AP_IOBUFSIZE]; 937 const char *tmp; 938 char *tmp2; 939 size_t len; 940 int ret, i; 941 942 if (r == NULL) 943 return; 944 945 apr_table_t *env = r->subprocess_env; 946 947 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 948 if (export_certificates_enabled != 0) { 949 char cert_buf[10 * 1024]; 950 len = sizeof(cert_buf); 951 952 if (gnutls_x509_crt_export 953 (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) 954 apr_table_setn(env, 955 apr_pstrcat(r->pool, MGS_SIDE, 956 "_CERT", NULL), 957 apr_pstrmemdup(r->pool, cert_buf, 958 len)); 959 960 } 961 962 len = sizeof(buf); 963 gnutls_x509_crt_get_dn(cert, buf, &len); 964 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL), 965 apr_pstrmemdup(r->pool, buf, len)); 966 967 len = sizeof(buf); 968 gnutls_x509_crt_get_issuer_dn(cert, buf, &len); 969 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL), 970 apr_pstrmemdup(r->pool, buf, len)); 971 972 len = sizeof(sbuf); 973 gnutls_x509_crt_get_serial(cert, sbuf, &len); 974 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 975 apr_table_setn(env, 976 apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL), 977 apr_pstrdup(r->pool, tmp)); 978 979 ret = gnutls_x509_crt_get_version(cert); 980 if (ret > 0) 981 apr_table_setn(env, 982 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 983 NULL), apr_psprintf(r->pool, 984 "%u", ret)); 985 986 apr_table_setn(env, 987 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 988 "X.509"); 989 990 tmp = 991 mgs_time2sz(gnutls_x509_crt_get_expiration_time 992 (cert), buf, sizeof(buf)); 993 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 994 apr_pstrdup(r->pool, tmp)); 995 996 tmp = 997 mgs_time2sz(gnutls_x509_crt_get_activation_time 998 (cert), buf, sizeof(buf)); 999 apr_table_setn(env, 1000 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1001 apr_pstrdup(r->pool, tmp)); 1002 1003 ret = gnutls_x509_crt_get_signature_algorithm(cert); 1004 if (ret >= 0) { 1005 apr_table_setn(env, 1006 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", 1007 NULL), 1008 gnutls_sign_algorithm_get_name(ret)); 1009 } 1010 1011 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL); 1012 if (ret >= 0) { 1013 apr_table_setn(env, 1014 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1015 NULL), 1016 gnutls_pk_algorithm_get_name(ret)); 1017 } 1018 1019 /* export all the alternative names (DNS, RFC822 and URI) */ 1020 for (i = 0; !(ret < 0); i++) { 1021 len = 0; 1022 ret = gnutls_x509_crt_get_subject_alt_name(cert, i, 1023 NULL, &len, 1024 NULL); 1025 1026 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) { 1027 tmp2 = apr_palloc(r->pool, len + 1); 1028 1029 ret = 1030 gnutls_x509_crt_get_subject_alt_name(cert, i, 1031 tmp2, 1032 &len, 1033 NULL); 1034 tmp2[len] = 0; 1035 1036 if (ret == GNUTLS_SAN_DNSNAME) { 1037 apr_table_setn(env, 1038 apr_psprintf(r->pool, 1039 "%s_S_AN%u", 1040 MGS_SIDE, i), 1041 apr_psprintf(r->pool, 1042 "DNSNAME:%s", 1043 tmp2)); 1044 } else if (ret == GNUTLS_SAN_RFC822NAME) { 1045 apr_table_setn(env, 1046 apr_psprintf(r->pool, 1047 "%s_S_AN%u", 1048 MGS_SIDE, i), 1049 apr_psprintf(r->pool, 1050 "RFC822NAME:%s", 1051 tmp2)); 1052 } else if (ret == GNUTLS_SAN_URI) { 1053 apr_table_setn(env, 1054 apr_psprintf(r->pool, 1055 "%s_S_AN%u", 1056 MGS_SIDE, i), 1057 apr_psprintf(r->pool, 1058 "URI:%s", 1059 tmp2)); 1060 } else { 1061 apr_table_setn(env, 1062 apr_psprintf(r->pool, 1063 "%s_S_AN%u", 1064 MGS_SIDE, i), 1065 "UNSUPPORTED"); 1066 } 1067 } 1068 } 918 int export_certificates_enabled) { 919 unsigned char sbuf[64]; /* buffer to hold serials */ 920 char buf[AP_IOBUFSIZE]; 921 const char *tmp; 922 char *tmp2; 923 size_t len; 924 int ret, i; 925 926 if (r == NULL) 927 return; 928 929 apr_table_t *env = r->subprocess_env; 930 931 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 932 if (export_certificates_enabled != 0) { 933 char cert_buf[10 * 1024]; 934 len = sizeof (cert_buf); 935 936 if (gnutls_x509_crt_export 937 (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) 938 apr_table_setn(env, 939 apr_pstrcat(r->pool, MGS_SIDE, 940 "_CERT", NULL), 941 apr_pstrmemdup(r->pool, cert_buf, 942 len)); 943 944 } 945 946 len = sizeof (buf); 947 gnutls_x509_crt_get_dn(cert, buf, &len); 948 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL), 949 apr_pstrmemdup(r->pool, buf, len)); 950 951 len = sizeof (buf); 952 gnutls_x509_crt_get_issuer_dn(cert, buf, &len); 953 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL), 954 apr_pstrmemdup(r->pool, buf, len)); 955 956 len = sizeof (sbuf); 957 gnutls_x509_crt_get_serial(cert, sbuf, &len); 958 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 959 apr_table_setn(env, 960 apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL), 961 apr_pstrdup(r->pool, tmp)); 962 963 ret = gnutls_x509_crt_get_version(cert); 964 if (ret > 0) 965 apr_table_setn(env, 966 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 967 NULL), apr_psprintf(r->pool, 968 "%u", ret)); 969 970 apr_table_setn(env, 971 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 972 "X.509"); 973 974 tmp = 975 mgs_time2sz(gnutls_x509_crt_get_expiration_time 976 (cert), buf, sizeof (buf)); 977 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 978 apr_pstrdup(r->pool, tmp)); 979 980 tmp = 981 mgs_time2sz(gnutls_x509_crt_get_activation_time 982 (cert), buf, sizeof (buf)); 983 apr_table_setn(env, 984 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 985 apr_pstrdup(r->pool, tmp)); 986 987 ret = gnutls_x509_crt_get_signature_algorithm(cert); 988 if (ret >= 0) { 989 apr_table_setn(env, 990 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", 991 NULL), 992 gnutls_sign_algorithm_get_name(ret)); 993 } 994 995 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL); 996 if (ret >= 0) { 997 apr_table_setn(env, 998 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 999 NULL), 1000 gnutls_pk_algorithm_get_name(ret)); 1001 } 1002 1003 /* export all the alternative names (DNS, RFC822 and URI) */ 1004 for (i = 0; !(ret < 0); i++) { 1005 len = 0; 1006 ret = gnutls_x509_crt_get_subject_alt_name(cert, i, 1007 NULL, &len, 1008 NULL); 1009 1010 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) { 1011 tmp2 = apr_palloc(r->pool, len + 1); 1012 1013 ret = 1014 gnutls_x509_crt_get_subject_alt_name(cert, i, 1015 tmp2, 1016 &len, 1017 NULL); 1018 tmp2[len] = 0; 1019 1020 if (ret == GNUTLS_SAN_DNSNAME) { 1021 apr_table_setn(env, 1022 apr_psprintf(r->pool, 1023 "%s_S_AN%u", 1024 MGS_SIDE, i), 1025 apr_psprintf(r->pool, 1026 "DNSNAME:%s", 1027 tmp2)); 1028 } else if (ret == GNUTLS_SAN_RFC822NAME) { 1029 apr_table_setn(env, 1030 apr_psprintf(r->pool, 1031 "%s_S_AN%u", 1032 MGS_SIDE, i), 1033 apr_psprintf(r->pool, 1034 "RFC822NAME:%s", 1035 tmp2)); 1036 } else if (ret == GNUTLS_SAN_URI) { 1037 apr_table_setn(env, 1038 apr_psprintf(r->pool, 1039 "%s_S_AN%u", 1040 MGS_SIDE, i), 1041 apr_psprintf(r->pool, 1042 "URI:%s", 1043 tmp2)); 1044 } else { 1045 apr_table_setn(env, 1046 apr_psprintf(r->pool, 1047 "%s_S_AN%u", 1048 MGS_SIDE, i), 1049 "UNSUPPORTED"); 1050 } 1051 } 1052 } 1069 1053 } 1070 1054 1071 1055 static void 1072 1056 mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, 1073 int side, int export_certificates_enabled) 1074 { 1075 unsigned char sbuf[64]; /* buffer to hold serials */ 1076 char buf[AP_IOBUFSIZE]; 1077 const char *tmp; 1078 size_t len; 1079 int ret; 1080 1081 if (r == NULL) 1082 return; 1083 1084 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1085 apr_table_t *env = r->subprocess_env; 1086 1087 if (export_certificates_enabled != 0) { 1088 char cert_buf[10 * 1024]; 1089 len = sizeof(cert_buf); 1090 1091 if (gnutls_openpgp_crt_export 1092 (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) 1093 apr_table_setn(env, 1094 apr_pstrcat(r->pool, MGS_SIDE, 1095 "_CERT", NULL), 1096 apr_pstrmemdup(r->pool, cert_buf, 1097 len)); 1098 1099 } 1100 1101 len = sizeof(buf); 1102 gnutls_openpgp_crt_get_name(cert, 0, buf, &len); 1103 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), 1104 apr_pstrmemdup(r->pool, buf, len)); 1105 1106 len = sizeof(sbuf); 1107 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); 1108 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 1109 apr_table_setn(env, 1110 apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", 1111 NULL), apr_pstrdup(r->pool, tmp)); 1112 1113 ret = gnutls_openpgp_crt_get_version(cert); 1114 if (ret > 0) 1115 apr_table_setn(env, 1116 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 1117 NULL), apr_psprintf(r->pool, 1118 "%u", ret)); 1119 1120 apr_table_setn(env, 1121 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 1122 "OPENPGP"); 1123 1124 tmp = 1125 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time 1126 (cert), buf, sizeof(buf)); 1127 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 1128 apr_pstrdup(r->pool, tmp)); 1129 1130 tmp = 1131 mgs_time2sz(gnutls_openpgp_crt_get_creation_time 1132 (cert), buf, sizeof(buf)); 1133 apr_table_setn(env, 1134 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1135 apr_pstrdup(r->pool, tmp)); 1136 1137 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); 1138 if (ret >= 0) { 1139 apr_table_setn(env, 1140 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1141 NULL), 1142 gnutls_pk_algorithm_get_name(ret)); 1143 } 1057 int side, int export_certificates_enabled) { 1058 unsigned char sbuf[64]; /* buffer to hold serials */ 1059 char buf[AP_IOBUFSIZE]; 1060 const char *tmp; 1061 size_t len; 1062 int ret; 1063 1064 if (r == NULL) 1065 return; 1066 1067 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1068 apr_table_t *env = r->subprocess_env; 1069 1070 if (export_certificates_enabled != 0) { 1071 char cert_buf[10 * 1024]; 1072 len = sizeof (cert_buf); 1073 1074 if (gnutls_openpgp_crt_export 1075 (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) 1076 apr_table_setn(env, 1077 apr_pstrcat(r->pool, MGS_SIDE, 1078 "_CERT", NULL), 1079 apr_pstrmemdup(r->pool, cert_buf, 1080 len)); 1081 1082 } 1083 1084 len = sizeof (buf); 1085 gnutls_openpgp_crt_get_name(cert, 0, buf, &len); 1086 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), 1087 apr_pstrmemdup(r->pool, buf, len)); 1088 1089 len = sizeof (sbuf); 1090 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); 1091 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 1092 apr_table_setn(env, 1093 apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", 1094 NULL), apr_pstrdup(r->pool, tmp)); 1095 1096 ret = gnutls_openpgp_crt_get_version(cert); 1097 if (ret > 0) 1098 apr_table_setn(env, 1099 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 1100 NULL), apr_psprintf(r->pool, 1101 "%u", ret)); 1102 1103 apr_table_setn(env, 1104 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 1105 "OPENPGP"); 1106 1107 tmp = 1108 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time 1109 (cert), buf, sizeof (buf)); 1110 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 1111 apr_pstrdup(r->pool, tmp)); 1112 1113 tmp = 1114 mgs_time2sz(gnutls_openpgp_crt_get_creation_time 1115 (cert), buf, sizeof (buf)); 1116 apr_table_setn(env, 1117 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1118 apr_pstrdup(r->pool, tmp)); 1119 1120 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); 1121 if (ret >= 0) { 1122 apr_table_setn(env, 1123 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1124 NULL), 1125 gnutls_pk_algorithm_get_name(ret)); 1126 } 1144 1127 1145 1128 } 1146 1129 1147 1130 /* TODO: Allow client sending a X.509 certificate chain */ 1148 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) 1149 { 1150 const gnutls_datum_t *cert_list;1151 unsigned int cert_list_size, status;1152 int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;1153 unsigned int ch_size = 0; 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 } 1131 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) { 1132 const gnutls_datum_t *cert_list; 1133 unsigned int cert_list_size, status; 1134 int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret; 1135 unsigned int ch_size = 0; 1136 1137 union { 1138 gnutls_x509_crt_t x509[MAX_CHAIN_SIZE]; 1139 gnutls_openpgp_crt_t pgp; 1140 } cert; 1141 apr_time_t expiration_time, cur_time; 1142 1143 if (r == NULL || ctxt == NULL || ctxt->session == NULL) 1144 return HTTP_FORBIDDEN; 1145 1146 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1147 cert_list = 1148 gnutls_certificate_get_peers(ctxt->session, &cert_list_size); 1149 1150 if (cert_list == NULL || cert_list_size == 0) { 1151 /* It is perfectly OK for a client not to send a certificate if on REQUEST mode 1152 */ 1153 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST) 1154 return OK; 1155 1156 /* no certificate provided by the client, but one was required. */ 1157 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1158 "GnuTLS: Failed to Verify Peer: " 1159 "Client did not submit a certificate"); 1160 return HTTP_FORBIDDEN; 1161 } 1162 1163 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1164 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1165 "GnuTLS: A Chain of %d certificate(s) was provided for validation", 1166 cert_list_size); 1167 1168 for (ch_size = 0; ch_size < cert_list_size; ch_size++) { 1169 gnutls_x509_crt_init(&cert.x509[ch_size]); 1170 rv = gnutls_x509_crt_import(cert.x509[ch_size], 1171 &cert_list[ch_size], 1172 GNUTLS_X509_FMT_DER); 1173 // When failure to import, leave the loop 1174 if (rv != GNUTLS_E_SUCCESS) { 1175 if (ch_size < 1) { 1176 ap_log_rerror(APLOG_MARK, 1177 APLOG_INFO, 0, r, 1178 "GnuTLS: Failed to Verify Peer: " 1179 "Failed to import peer certificates."); 1180 ret = HTTP_FORBIDDEN; 1181 goto exit; 1182 } 1183 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1184 "GnuTLS: Failed to import some peer certificates. Using %d certificates", 1185 ch_size); 1186 rv = GNUTLS_E_SUCCESS; 1187 break; 1188 } 1189 } 1190 } else if (gnutls_certificate_type_get(ctxt->session) == 1191 GNUTLS_CRT_OPENPGP) { 1192 if (cert_list_size > 1) { 1193 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1194 "GnuTLS: Failed to Verify Peer: " 1195 "Chained Client Certificates are not supported."); 1196 return HTTP_FORBIDDEN; 1197 } 1198 1199 gnutls_openpgp_crt_init(&cert.pgp); 1200 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], 1201 GNUTLS_OPENPGP_FMT_RAW); 1202 1203 } else 1204 return HTTP_FORBIDDEN; 1205 1206 if (rv < 0) { 1207 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1208 "GnuTLS: Failed to Verify Peer: " 1209 "Failed to import peer certificates."); 1210 ret = HTTP_FORBIDDEN; 1211 goto exit; 1212 } 1213 1214 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1215 apr_time_ansi_put(&expiration_time, 1216 gnutls_x509_crt_get_expiration_time 1217 (cert.x509[0])); 1218 1219 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1220 "GnuTLS: Verifying list of %d certificate(s)", 1221 ch_size); 1222 rv = gnutls_x509_crt_list_verify(cert.x509, ch_size, 1223 ctxt->sc->ca_list, 1224 ctxt->sc->ca_list_size, 1225 NULL, 0, 0, &status); 1226 } else { 1227 apr_time_ansi_put(&expiration_time, 1228 gnutls_openpgp_crt_get_expiration_time 1229 (cert.pgp)); 1230 1231 rv = gnutls_openpgp_crt_verify_ring(cert.pgp, 1232 ctxt->sc->pgp_list, 0, 1233 &status); 1234 } 1235 1236 if (rv < 0) { 1237 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1238 "GnuTLS: Failed to Verify Peer certificate: (%d) %s", 1239 rv, gnutls_strerror(rv)); 1240 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND) 1241 ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r, 1242 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?"); 1243 ret = HTTP_FORBIDDEN; 1244 goto exit; 1245 } 1246 1247 /* TODO: X509 CRL Verification. */ 1248 /* May add later if anyone needs it. 1249 */ 1250 /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */ 1251 1252 cur_time = apr_time_now(); 1253 1254 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 1255 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1256 "GnuTLS: Could not find Signer for Peer Certificate"); 1257 } 1258 1259 if (status & GNUTLS_CERT_SIGNER_NOT_CA) { 1260 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1261 "GnuTLS: Peer's Certificate signer is not a CA"); 1262 } 1263 1264 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 1265 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1266 "GnuTLS: Peer's Certificate is using insecure algorithms"); 1267 } 1268 1269 if (status & GNUTLS_CERT_EXPIRED 1270 || status & GNUTLS_CERT_NOT_ACTIVATED) { 1271 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1272 "GnuTLS: Peer's Certificate signer is expired or not yet activated"); 1273 } 1274 1275 if (status & GNUTLS_CERT_INVALID) { 1276 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1277 "GnuTLS: Peer Certificate is invalid."); 1278 } else if (status & GNUTLS_CERT_REVOKED) { 1279 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1280 "GnuTLS: Peer Certificate is revoked."); 1281 } 1282 1283 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 1284 mgs_add_common_cert_vars(r, cert.x509[0], 1, 1285 ctxt-> 1286 sc->export_certificates_enabled); 1287 else if (gnutls_certificate_type_get(ctxt->session) == 1288 GNUTLS_CRT_OPENPGP) 1289 mgs_add_common_pgpcert_vars(r, cert.pgp, 1, 1290 ctxt-> 1291 sc->export_certificates_enabled); 1292 1293 { 1294 /* days remaining */ 1295 unsigned long remain = 1296 (apr_time_sec(expiration_time) - 1297 apr_time_sec(cur_time)) / 86400; 1298 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN", 1299 apr_psprintf(r->pool, "%lu", remain)); 1300 } 1301 1302 if (status == 0) { 1303 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", 1304 "SUCCESS"); 1305 ret = OK; 1306 } else { 1307 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", 1308 "FAILED"); 1309 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST) 1310 ret = OK; 1311 else 1312 ret = HTTP_FORBIDDEN; 1313 } 1314 1315 exit: 1316 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1317 int i; 1318 for (i = 0; i < ch_size; i++) { 1319 gnutls_x509_crt_deinit(cert.x509[i]); 1320 } 1321 } else if (gnutls_certificate_type_get(ctxt->session) == 1322 GNUTLS_CRT_OPENPGP) 1323 gnutls_openpgp_crt_deinit(cert.pgp); 1324 return ret; 1325 1326 1327 }
Note: See TracChangeset
for help on using the changeset viewer.