269
270
svn_auth_iterstate_t *state;
270
271
const char *realmstring;
271
272
apr_uint32_t svn_failures;
272
apr_hash_t *issuer, *subject, *serf_cert;
273
apr_array_header_t *san;
274
apr_hash_t *subject = NULL;
275
apr_hash_t *serf_cert = NULL;
275
277
int found_matching_hostname = 0;
277
/* Implicitly approve any non-server certs. */
278
if (serf_ssl_cert_depth(cert) > 0)
279
svn_failures = (ssl_convert_serf_failures(failures)
280
| conn->server_cert_failures);
282
if (serf_ssl_cert_depth(cert) == 0)
281
conn->server_cert_failures |= ssl_convert_serf_failures(failures);
284
/* If the depth is 0, the hostname must match the certificate.
286
### This should really be handled by serf, which should pass an error
287
for this case, but that has backwards compatibility issues. */
288
apr_array_header_t *san;
290
serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
292
san = svn_hash_gets(serf_cert, "subjectAltName");
293
/* Try to find matching server name via subjectAltName first... */
296
for (i = 0; i < san->nelts; i++) {
297
const char *s = APR_ARRAY_IDX(san, i, const char*);
298
if (apr_fnmatch(s, conn->session->session_url.hostname,
299
APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
301
found_matching_hostname = 1;
307
/* Match server certificate CN with the hostname of the server */
308
if (!found_matching_hostname)
310
const char *hostname = NULL;
312
subject = serf_ssl_cert_subject(cert, scratch_pool);
315
hostname = svn_hash_gets(subject, "CN");
318
|| apr_fnmatch(hostname, conn->session->session_url.hostname,
319
APR_FNM_PERIOD | APR_FNM_CASE_BLIND) != APR_SUCCESS)
321
svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
285
329
/* Extract the info from the certificate */
286
subject = serf_ssl_cert_subject(cert, scratch_pool);
331
subject = serf_ssl_cert_subject(cert, scratch_pool);
287
332
issuer = serf_ssl_cert_issuer(cert, scratch_pool);
288
serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
334
serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
290
336
cert_info.hostname = svn_hash_gets(subject, "CN");
291
san = svn_hash_gets(serf_cert, "subjectAltName");
292
337
cert_info.fingerprint = svn_hash_gets(serf_cert, "sha1");
293
338
if (! cert_info.fingerprint)
294
339
cert_info.fingerprint = apr_pstrdup(scratch_pool, "<unknown>");
301
346
cert_info.issuer_dname = convert_organisation_to_str(issuer, scratch_pool);
302
347
cert_info.ascii_cert = serf_ssl_cert_export(cert, scratch_pool);
304
svn_failures = (ssl_convert_serf_failures(failures)
305
| conn->server_cert_failures);
307
/* Try to find matching server name via subjectAltName first... */
310
for (i = 0; i < san->nelts; i++) {
311
char *s = APR_ARRAY_IDX(san, i, char*);
312
if (apr_fnmatch(s, conn->session->session_url.hostname,
313
APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
315
found_matching_hostname = 1;
316
cert_info.hostname = s;
322
/* Match server certificate CN with the hostname of the server */
323
if (!found_matching_hostname && cert_info.hostname)
349
/* Handle any non-server certs. */
350
if (serf_ssl_cert_depth(cert) > 0)
325
if (apr_fnmatch(cert_info.hostname, conn->session->session_url.hostname,
326
APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
328
svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
354
svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
355
SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
358
svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
359
SVN_AUTH_PARAM_SSL_SERVER_FAILURES,
362
realmstring = apr_psprintf(scratch_pool, "AUTHORITY:%s",
363
cert_info.fingerprint);
365
err = svn_auth_first_credentials(&creds, &state,
366
SVN_AUTH_CRED_SSL_SERVER_AUTHORITY,
368
conn->session->wc_callbacks->auth_baton,
371
svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
372
SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
374
svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
375
SVN_AUTH_PARAM_SSL_SERVER_FAILURES, NULL);
379
if (err->apr_err != SVN_ERR_AUTHN_NO_PROVIDER)
380
return svn_error_trace(err);
382
/* No provider registered that handles server authorities */
383
svn_error_clear(err);
389
server_creds = creds;
390
SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
392
svn_failures &= ~server_creds->accepted_failures;
396
conn->server_cert_failures |= svn_failures;
332
401
svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
349
418
server_creds = creds;
419
svn_failures &= ~server_creds->accepted_failures;
350
420
SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
423
while (svn_failures && creds)
425
SVN_ERR(svn_auth_next_credentials(&creds, state, scratch_pool));
429
server_creds = creds;
430
svn_failures &= ~server_creds->accepted_failures;
431
SVN_ERR(svn_auth_save_credentials(state, scratch_pool));
353
435
svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
354
436
SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
438
/* Are there non accepted failures left? */
358
441
svn_stringbuf_t *errmsg;