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