2 * win32_crypto.c: win32 providers for SVN_AUTH_*
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 /* prevent "empty compilation unit" warning on e.g. UNIX */
25 typedef int win32_crypto__dummy;
27 /* ==================================================================== */
29 #if defined(WIN32) && !defined(__MINGW32__)
33 #include <apr_pools.h>
34 #include <apr_base64.h>
36 #include "svn_error.h"
39 #include "svn_config.h"
41 #include "svn_base64.h"
44 #include "private/svn_auth_private.h"
46 #include "svn_private_config.h"
51 /* The description string that's combined with unencrypted data by the
52 Windows CryptoAPI. Used during decryption to verify that the
53 encrypted data were valid. */
54 static const WCHAR description[] = L"auth_svn.simple.wincrypt";
57 /* Return a copy of ORIG, encrypted using the Windows CryptoAPI and
58 allocated from POOL. */
60 encrypt_data(const svn_string_t *orig,
65 const svn_string_t *crypted = NULL;
67 blobin.cbData = orig->len;
68 blobin.pbData = (BYTE *)orig->data;
69 if (CryptProtectData(&blobin, description, NULL, NULL, NULL,
70 CRYPTPROTECT_UI_FORBIDDEN, &blobout))
72 crypted = svn_string_ncreate((const char *)blobout.pbData,
73 blobout.cbData, pool);
74 LocalFree(blobout.pbData);
79 /* Return a copy of CRYPTED, decrypted using the Windows CryptoAPI and
80 allocated from POOL. */
82 decrypt_data(const svn_string_t *crypted,
88 const svn_string_t *orig = NULL;
90 blobin.cbData = crypted->len;
91 blobin.pbData = (BYTE *)crypted->data;
92 if (CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
93 CRYPTPROTECT_UI_FORBIDDEN, &blobout))
95 if (0 == lstrcmpW(descr, description))
96 orig = svn_string_ncreate((const char *)blobout.pbData,
97 blobout.cbData, pool);
98 LocalFree(blobout.pbData);
105 /*-----------------------------------------------------------------------*/
106 /* Windows simple provider, encrypts the password on Win2k and later. */
107 /*-----------------------------------------------------------------------*/
109 /* Implementation of svn_auth__password_set_t that encrypts
110 the incoming password using the Windows CryptoAPI. */
112 windows_password_encrypter(svn_boolean_t *done,
114 const char *realmstring,
115 const char *username,
117 apr_hash_t *parameters,
118 svn_boolean_t non_interactive,
121 const svn_string_t *coded;
123 coded = encrypt_data(svn_string_create(in, pool), pool);
126 coded = svn_base64_encode_string2(coded, FALSE, pool);
127 SVN_ERR(svn_auth__simple_password_set(done, creds, realmstring, username,
128 coded->data, parameters,
129 non_interactive, pool));
135 /* Implementation of svn_auth__password_get_t that decrypts
136 the incoming password using the Windows CryptoAPI and verifies its
139 windows_password_decrypter(svn_boolean_t *done,
142 const char *realmstring,
143 const char *username,
144 apr_hash_t *parameters,
145 svn_boolean_t non_interactive,
148 const svn_string_t *orig;
151 SVN_ERR(svn_auth__simple_password_get(done, &in, creds, realmstring, username,
152 parameters, non_interactive, pool));
156 orig = svn_base64_decode_string(svn_string_create(in, pool), pool);
157 orig = decrypt_data(orig, pool);
170 /* Get cached encrypted credentials from the simple provider's cache. */
172 windows_simple_first_creds(void **credentials,
174 void *provider_baton,
175 apr_hash_t *parameters,
176 const char *realmstring,
179 return svn_auth__simple_creds_cache_get(credentials,
184 windows_password_decrypter,
185 SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
189 /* Save encrypted credentials to the simple provider's cache. */
191 windows_simple_save_creds(svn_boolean_t *saved,
193 void *provider_baton,
194 apr_hash_t *parameters,
195 const char *realmstring,
198 return svn_auth__simple_creds_cache_set(saved, credentials,
202 windows_password_encrypter,
203 SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
207 static const svn_auth_provider_t windows_simple_provider = {
208 SVN_AUTH_CRED_SIMPLE,
209 windows_simple_first_creds,
211 windows_simple_save_creds
217 svn_auth__get_windows_simple_provider(svn_auth_provider_object_t **provider,
220 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
222 po->vtable = &windows_simple_provider;
227 /*-----------------------------------------------------------------------*/
228 /* Windows SSL server trust provider, validates ssl certificate using */
230 /*-----------------------------------------------------------------------*/
232 /* Implementation of svn_auth__password_set_t that encrypts
233 the incoming password using the Windows CryptoAPI. */
235 windows_ssl_client_cert_pw_encrypter(svn_boolean_t *done,
237 const char *realmstring,
238 const char *username,
240 apr_hash_t *parameters,
241 svn_boolean_t non_interactive,
244 const svn_string_t *coded;
246 coded = encrypt_data(svn_string_create(in, pool), pool);
249 coded = svn_base64_encode_string2(coded, FALSE, pool);
250 SVN_ERR(svn_auth__ssl_client_cert_pw_set(done, creds, realmstring,
251 username, coded->data,
252 parameters, non_interactive,
259 /* Implementation of svn_auth__password_get_t that decrypts
260 the incoming password using the Windows CryptoAPI and verifies its
263 windows_ssl_client_cert_pw_decrypter(svn_boolean_t *done,
266 const char *realmstring,
267 const char *username,
268 apr_hash_t *parameters,
269 svn_boolean_t non_interactive,
272 const svn_string_t *orig;
275 SVN_ERR(svn_auth__ssl_client_cert_pw_get(done, &in, creds, realmstring,
276 username, parameters,
277 non_interactive, pool));
281 orig = svn_base64_decode_string(svn_string_create(in, pool), pool);
282 orig = decrypt_data(orig, pool);
295 /* Get cached encrypted credentials from the simple provider's cache. */
297 windows_ssl_client_cert_pw_first_creds(void **credentials,
299 void *provider_baton,
300 apr_hash_t *parameters,
301 const char *realmstring,
304 return svn_auth__ssl_client_cert_pw_cache_get(
305 credentials, iter_baton, provider_baton, parameters, realmstring,
306 windows_ssl_client_cert_pw_decrypter,
307 SVN_AUTH__WINCRYPT_PASSWORD_TYPE, pool);
310 /* Save encrypted credentials to the simple provider's cache. */
312 windows_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
314 void *provider_baton,
315 apr_hash_t *parameters,
316 const char *realmstring,
319 return svn_auth__ssl_client_cert_pw_cache_set(
320 saved, credentials, provider_baton, parameters, realmstring,
321 windows_ssl_client_cert_pw_encrypter,
322 SVN_AUTH__WINCRYPT_PASSWORD_TYPE, pool);
325 static const svn_auth_provider_t windows_ssl_client_cert_pw_provider = {
326 SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
327 windows_ssl_client_cert_pw_first_creds,
329 windows_ssl_client_cert_pw_save_creds
335 svn_auth__get_windows_ssl_client_cert_pw_provider
336 (svn_auth_provider_object_t **provider,
339 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
341 po->vtable = &windows_ssl_client_cert_pw_provider;
346 /*-----------------------------------------------------------------------*/
347 /* Windows SSL server trust provider, validates ssl certificate using */
349 /*-----------------------------------------------------------------------*/
351 /* Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
352 * Returns NULL on error.
354 static PCCERT_CONTEXT
355 certcontext_from_base64(const char *base64_cert, apr_pool_t *pool)
357 PCCERT_CONTEXT cert_context = NULL;
361 /* Use apr-util as CryptStringToBinaryA is available only on XP+. */
362 binary_cert = apr_palloc(pool,
363 apr_base64_decode_len(base64_cert));
364 cert_len = apr_base64_decode((char*)binary_cert, base64_cert);
366 /* Parse the certificate into a context. */
367 cert_context = CertCreateCertificateContext
368 (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, binary_cert, cert_len);
373 /* Helper for windows_ssl_server_trust_first_credentials for validating
374 * certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
375 * certificate considered as valid.
378 windows_validate_certificate(svn_boolean_t *ok_p,
379 const char *ascii_cert,
382 PCCERT_CONTEXT cert_context = NULL;
383 CERT_CHAIN_PARA chain_para;
384 PCCERT_CHAIN_CONTEXT chain_context = NULL;
388 /* Parse the certificate into a context. */
389 cert_context = certcontext_from_base64(ascii_cert, pool);
393 /* Retrieve the certificate chain of the certificate
394 (a certificate without a valid root does not have a chain). */
395 memset(&chain_para, 0, sizeof(chain_para));
396 chain_para.cbSize = sizeof(chain_para);
398 if (CertGetCertificateChain(NULL, cert_context, NULL, NULL, &chain_para,
399 CERT_CHAIN_CACHE_END_CERT |
400 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
401 NULL, &chain_context))
403 CERT_CHAIN_POLICY_PARA policy_para;
404 CERT_CHAIN_POLICY_STATUS policy_status;
406 policy_para.cbSize = sizeof(policy_para);
407 policy_para.dwFlags = 0;
408 policy_para.pvExtraPolicyPara = NULL;
410 policy_status.cbSize = sizeof(policy_status);
412 if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
413 chain_context, &policy_para,
416 if (policy_status.dwError == S_OK)
418 /* Windows thinks the certificate is valid. */
423 CertFreeCertificateChain(chain_context);
425 CertFreeCertificateContext(cert_context);
431 /* Retrieve ssl server CA failure overrides (if any) from CryptoApi. */
433 windows_ssl_server_trust_first_credentials(void **credentials,
435 void *provider_baton,
436 apr_hash_t *parameters,
437 const char *realmstring,
440 apr_uint32_t *failure_ptr = svn_hash_gets(parameters,
441 SVN_AUTH_PARAM_SSL_SERVER_FAILURES);
442 apr_uint32_t failures = *failure_ptr;
443 const svn_auth_ssl_server_cert_info_t *cert_info =
444 svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO);
449 /* We can accept only unknown certificate authority. */
450 if (failures & SVN_AUTH_SSL_UNKNOWNCA)
454 SVN_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
456 /* Windows thinks that certificate is ok. */
459 /* Clear failure flag. */
460 failures &= ~SVN_AUTH_SSL_UNKNOWNCA;
464 /* If all failures are cleared now, we return the creds */
467 svn_auth_cred_ssl_server_trust_t *creds =
468 apr_pcalloc(pool, sizeof(*creds));
469 creds->accepted_failures = *failure_ptr & ~failures;
470 creds->may_save = FALSE; /* No need to save it. */
471 *credentials = creds;
477 static const svn_auth_provider_t windows_server_trust_provider = {
478 SVN_AUTH_CRED_SSL_SERVER_TRUST,
479 windows_ssl_server_trust_first_credentials,
486 svn_auth__get_windows_ssl_server_trust_provider
487 (svn_auth_provider_object_t **provider, apr_pool_t *pool)
489 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
491 po->vtable = &windows_server_trust_provider;
495 static const svn_auth_provider_t windows_server_authority_provider = {
496 SVN_AUTH_CRED_SSL_SERVER_AUTHORITY,
497 windows_ssl_server_trust_first_credentials,
504 svn_auth__get_windows_ssl_server_authority_provider(
505 svn_auth_provider_object_t **provider,
508 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
510 po->vtable = &windows_server_authority_provider;