2 * ssl_server_trust_providers.c: providers for
3 * SVN_AUTH_CRED_SSL_SERVER_TRUST
5 * ====================================================================
6 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
8 * This software is licensed as described in the file COPYING, which
9 * you should have received as part of this distribution. The terms
10 * are also available at http://subversion.tigris.org/license-1.html.
11 * If newer versions of this license are posted there, you may use a
12 * newer version instead, at your option.
14 * This software consists of voluntary contributions made by many
15 * individuals. For exact contribution history, see the revision
16 * history and logs, available at http://subversion.tigris.org/.
17 * ====================================================================
20 /* ==================================================================== */
26 #include <apr_pools.h>
28 #include "svn_error.h"
29 #include "svn_config.h"
32 /*-----------------------------------------------------------------------*/
34 /*-----------------------------------------------------------------------*/
36 /* The keys that will be stored on disk */
37 #define SVN_AUTH__AUTHFILE_ASCII_CERT_KEY "ascii_cert"
38 #define SVN_AUTH__AUTHFILE_FAILURES_KEY "failures"
41 /* retieve ssl server CA failure overrides (if any) from servers
44 ssl_server_trust_file_first_credentials(void **credentials
,
47 apr_hash_t
*parameters
,
48 const char *realmstring
,
51 apr_uint32_t
*failures
= apr_hash_get(parameters
,
52 SVN_AUTH_PARAM_SSL_SERVER_FAILURES
,
54 const svn_auth_ssl_server_cert_info_t
*cert_info
=
55 apr_hash_get(parameters
,
56 SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO
,
58 apr_hash_t
*creds_hash
= NULL
;
59 const char *config_dir
;
60 svn_error_t
*error
= SVN_NO_ERROR
;
65 /* Check if this is a permanently accepted certificate */
66 config_dir
= apr_hash_get(parameters
,
67 SVN_AUTH_PARAM_CONFIG_DIR
,
70 svn_config_read_auth_data(&creds_hash
, SVN_AUTH_CRED_SSL_SERVER_TRUST
,
71 realmstring
, config_dir
, pool
);
72 svn_error_clear(error
);
73 if (! error
&& creds_hash
)
75 svn_string_t
*trusted_cert
, *this_cert
, *failstr
;
76 apr_uint32_t last_failures
= 0;
78 trusted_cert
= apr_hash_get(creds_hash
,
79 SVN_AUTH__AUTHFILE_ASCII_CERT_KEY
,
81 this_cert
= svn_string_create(cert_info
->ascii_cert
, pool
);
82 failstr
= apr_hash_get(creds_hash
,
83 SVN_AUTH__AUTHFILE_FAILURES_KEY
,
89 unsigned long tmp_ulong
= strtoul(failstr
->data
, &endptr
, 10);
92 last_failures
= (apr_uint32_t
) tmp_ulong
;
95 /* If the cert is trusted and there are no new failures, we
96 * accept it by clearing all failures. */
98 svn_string_compare(this_cert
, trusted_cert
) &&
99 (*failures
& ~last_failures
) == 0)
105 /* If all failures are cleared now, we return the creds */
108 svn_auth_cred_ssl_server_trust_t
*creds
=
109 apr_pcalloc(pool
, sizeof(*creds
));
110 creds
->may_save
= FALSE
; /* No need to save it again... */
111 *credentials
= creds
;
119 ssl_server_trust_file_save_credentials(svn_boolean_t
*saved
,
121 void *provider_baton
,
122 apr_hash_t
*parameters
,
123 const char *realmstring
,
126 svn_auth_cred_ssl_server_trust_t
*creds
= credentials
;
127 const svn_auth_ssl_server_cert_info_t
*cert_info
;
128 apr_hash_t
*creds_hash
= NULL
;
129 const char *config_dir
;
131 if (! creds
->may_save
)
134 config_dir
= apr_hash_get(parameters
,
135 SVN_AUTH_PARAM_CONFIG_DIR
,
136 APR_HASH_KEY_STRING
);
138 cert_info
= apr_hash_get(parameters
,
139 SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO
,
140 APR_HASH_KEY_STRING
);
142 creds_hash
= apr_hash_make(pool
);
143 apr_hash_set(creds_hash
,
144 SVN_AUTH__AUTHFILE_ASCII_CERT_KEY
,
146 svn_string_create(cert_info
->ascii_cert
, pool
));
147 apr_hash_set(creds_hash
,
148 SVN_AUTH__AUTHFILE_FAILURES_KEY
,
150 svn_string_createf(pool
, "%lu", (unsigned long)
151 creds
->accepted_failures
));
153 SVN_ERR(svn_config_write_auth_data(creds_hash
,
154 SVN_AUTH_CRED_SSL_SERVER_TRUST
,
163 static const svn_auth_provider_t ssl_server_trust_file_provider
= {
164 SVN_AUTH_CRED_SSL_SERVER_TRUST
,
165 &ssl_server_trust_file_first_credentials
,
167 &ssl_server_trust_file_save_credentials
,
171 /*** Public API to SSL file providers. ***/
173 svn_auth_get_ssl_server_trust_file_provider
174 (svn_auth_provider_object_t
**provider
, apr_pool_t
*pool
)
176 svn_auth_provider_object_t
*po
= apr_pcalloc(pool
, sizeof(*po
));
178 po
->vtable
= &ssl_server_trust_file_provider
;
183 /*-----------------------------------------------------------------------*/
184 /* Prompt provider */
185 /*-----------------------------------------------------------------------*/
187 /* Baton type for prompting to verify server ssl creds.
188 There is no iteration baton type. */
191 svn_auth_ssl_server_trust_prompt_func_t prompt_func
;
193 } ssl_server_trust_prompt_provider_baton_t
;
197 ssl_server_trust_prompt_first_cred(void **credentials_p
,
199 void *provider_baton
,
200 apr_hash_t
*parameters
,
201 const char *realmstring
,
204 ssl_server_trust_prompt_provider_baton_t
*pb
= provider_baton
;
205 apr_uint32_t
*failures
= apr_hash_get(parameters
,
206 SVN_AUTH_PARAM_SSL_SERVER_FAILURES
,
207 APR_HASH_KEY_STRING
);
208 const char *no_auth_cache
= apr_hash_get(parameters
,
209 SVN_AUTH_PARAM_NO_AUTH_CACHE
,
210 APR_HASH_KEY_STRING
);
211 const svn_auth_ssl_server_cert_info_t
*cert_info
=
212 apr_hash_get(parameters
,
213 SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO
,
214 APR_HASH_KEY_STRING
);
216 SVN_ERR(pb
->prompt_func((svn_auth_cred_ssl_server_trust_t
**)
217 credentials_p
, pb
->prompt_baton
, realmstring
,
218 *failures
, cert_info
, ! no_auth_cache
&&
219 ! (*failures
& SVN_AUTH_SSL_OTHER
), pool
));
226 static const svn_auth_provider_t ssl_server_trust_prompt_provider
= {
227 SVN_AUTH_CRED_SSL_SERVER_TRUST
,
228 ssl_server_trust_prompt_first_cred
,
234 /*** Public API to SSL prompting providers. ***/
236 svn_auth_get_ssl_server_trust_prompt_provider
237 (svn_auth_provider_object_t
**provider
,
238 svn_auth_ssl_server_trust_prompt_func_t prompt_func
,
242 svn_auth_provider_object_t
*po
= apr_pcalloc(pool
, sizeof(*po
));
243 ssl_server_trust_prompt_provider_baton_t
*pb
=
244 apr_palloc(pool
, sizeof(*pb
));
245 pb
->prompt_func
= prompt_func
;
246 pb
->prompt_baton
= prompt_baton
;
247 po
->vtable
= &ssl_server_trust_prompt_provider
;
248 po
->provider_baton
= pb
;
253 /*-----------------------------------------------------------------------*/
254 /* Windows SSL server trust provider, validates ssl certificate using */
256 /*-----------------------------------------------------------------------*/
258 #if defined(WIN32) && !defined(__MINGW32__)
259 #include <wincrypt.h>
260 #include <apr_base64.h>
262 /* Retrieve ssl server CA failure overrides (if any) from CryptoApi. */
264 windows_ssl_server_trust_first_credentials(void **credentials
,
266 void *provider_baton
,
267 apr_hash_t
*parameters
,
268 const char *realmstring
,
271 typedef PCCERT_CONTEXT (WINAPI
*createcertcontext_fn_t
)(
272 DWORD dwCertEncodingType
,
273 const BYTE
*pbCertEncoded
,
274 DWORD cbCertEncoded
);
276 typedef BOOL (WINAPI
*getcertchain_fn_t
)(
277 HCERTCHAINENGINE hChainEngine
,
278 PCCERT_CONTEXT pCertContext
,
280 HCERTSTORE hAdditionalStore
,
281 PCERT_CHAIN_PARA pChainPara
,
284 PCCERT_CHAIN_CONTEXT
* ppChainContext
);
286 typedef VOID (WINAPI
*freecertchain_fn_t
)(
287 PCCERT_CHAIN_CONTEXT pChainContext
);
289 typedef BOOL (WINAPI
*freecertcontext_fn_t
)(
290 PCCERT_CONTEXT pCertContext
);
292 HINSTANCE cryptodll
= NULL
;
293 createcertcontext_fn_t createcertcontext
;
294 getcertchain_fn_t getcertchain
;
295 freecertchain_fn_t freecertchain
;
296 freecertcontext_fn_t freecertcontext
;
297 PCCERT_CONTEXT cert_context
= NULL
;
298 CERT_CHAIN_PARA chain_para
;
299 PCCERT_CHAIN_CONTEXT chain_context
= NULL
;
300 svn_boolean_t ok
= TRUE
;
302 apr_uint32_t
*failures
= apr_hash_get(parameters
,
303 SVN_AUTH_PARAM_SSL_SERVER_FAILURES
,
304 APR_HASH_KEY_STRING
);
305 const svn_auth_ssl_server_cert_info_t
*cert_info
=
306 apr_hash_get(parameters
,
307 SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO
,
308 APR_HASH_KEY_STRING
);
310 if (*failures
& ~SVN_AUTH_SSL_UNKNOWNCA
)
312 /* give up, go on to next provider; the only thing we can accept
313 is an unknown certificate authority. */
319 /* In case anyone wonders why we use LoadLibraryA here: This will
320 always work on Win9x/Me, whilst LoadLibraryW may not. */
321 cryptodll
= LoadLibraryA("Crypt32.dll");
325 /* give up, go on to next provider. */
331 (createcertcontext_fn_t
)GetProcAddress(cryptodll
,
332 "CertCreateCertificateContext");
334 (getcertchain_fn_t
)GetProcAddress(cryptodll
, "CertGetCertificateChain");
336 (freecertchain_fn_t
)GetProcAddress(cryptodll
, "CertFreeCertificateChain");
338 (freecertcontext_fn_t
)GetProcAddress(cryptodll
,
339 "CertFreeCertificateContext");
341 if (!createcertcontext
|| !getcertchain
|| !freecertchain
350 /* Use apr-util as CryptStringToBinaryA is available only on XP+. */
351 binary_cert
= apr_palloc(pool
,
352 apr_base64_decode_len(cert_info
->ascii_cert
));
353 cert_len
= apr_base64_decode(binary_cert
, cert_info
->ascii_cert
);
355 /* Parse the certificate into a context. */
356 cert_context
= createcertcontext
357 (X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, binary_cert
, cert_len
);
360 ok
= FALSE
; /* Windows does not think the certificate is valid. */
365 /* Retrieve the certificate chain of the certificate
366 (a certificate without a valid root does not have a chain). */
367 memset(&chain_para
, 0, sizeof(chain_para
));
368 chain_para
.cbSize
= sizeof(chain_para
);
370 if (getcertchain(NULL
, cert_context
, NULL
, NULL
, &chain_para
,
371 CERT_CHAIN_CACHE_END_CERT
,
372 NULL
, &chain_context
))
374 if (chain_context
->rgpChain
[0]->TrustStatus
.dwErrorStatus
375 != CERT_TRUST_NO_ERROR
)
377 /* The certificate is not 100% valid, just fall back to the
378 Subversion certificate handling. */
388 freecertchain(chain_context
);
390 freecertcontext(cert_context
);
392 FreeLibrary(cryptodll
);
396 /* go on to next provider. */
402 svn_auth_cred_ssl_server_trust_t
*creds
=
403 apr_pcalloc(pool
, sizeof(*creds
));
404 creds
->may_save
= FALSE
; /* No need to save it. */
405 *credentials
= creds
;
412 static const svn_auth_provider_t windows_server_trust_provider
= {
413 SVN_AUTH_CRED_SSL_SERVER_TRUST
,
414 windows_ssl_server_trust_first_credentials
,
421 svn_auth_get_windows_ssl_server_trust_provider
422 (svn_auth_provider_object_t
**provider
, apr_pool_t
*pool
)
424 svn_auth_provider_object_t
*po
= apr_pcalloc(pool
, sizeof(*po
));
426 po
->vtable
= &windows_server_trust_provider
;