source: valtobtest/subversion-1.6.2/subversion/libsvn_subr/win32_crypto.c @ 3

Last change on this file since 3 was 3, checked in by valtob, 15 years ago

subversion source 1.6.2 as test

File size: 15.0 KB
Line 
1/*
2 * win32_crypto.c: win32 providers for SVN_AUTH_*
3 *
4 * ====================================================================
5 * Copyright (c) 2003-2006, 2008 CollabNet.  All rights reserved.
6 *
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution.  The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
12 *
13 * This software consists of voluntary contributions made by many
14 * individuals.  For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
17 */
18
19/* ==================================================================== */
20
21#if defined(WIN32) && !defined(__MINGW32__)
22
23/*** Includes. ***/
24
25#include <apr_pools.h>
26#include "svn_auth.h"
27#include "svn_error.h"
28#include "svn_utf.h"
29#include "svn_config.h"
30#include "svn_user.h"
31
32#include "private/svn_auth_private.h"
33
34#include "svn_private_config.h"
35
36#include <wincrypt.h>
37#include <apr_base64.h>
38
39/*-----------------------------------------------------------------------*/
40/* Windows simple provider, encrypts the password on Win2k and later.    */
41/*-----------------------------------------------------------------------*/
42
43/* The description string that's combined with unencrypted data by the
44   Windows CryptoAPI. Used during decryption to verify that the
45   encrypted data were valid. */
46static const WCHAR description[] = L"auth_svn.simple.wincrypt";
47
48/* Implementation of svn_auth__password_set_t that encrypts
49   the incoming password using the Windows CryptoAPI. */
50static svn_boolean_t
51windows_password_encrypter(apr_hash_t *creds,
52                           const char *realmstring,
53                           const char *username,
54                           const char *in,
55                           apr_hash_t *parameters,
56                           svn_boolean_t non_interactive,
57                           apr_pool_t *pool)
58{
59  DATA_BLOB blobin;
60  DATA_BLOB blobout;
61  svn_boolean_t crypted;
62
63  blobin.cbData = strlen(in);
64  blobin.pbData = (BYTE*) in;
65  crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
66                             CRYPTPROTECT_UI_FORBIDDEN, &blobout);
67  if (crypted)
68    {
69      char *coded = apr_palloc(pool, apr_base64_encode_len(blobout.cbData));
70      apr_base64_encode(coded, blobout.pbData, blobout.cbData);
71      crypted = svn_auth__simple_password_set(creds, realmstring, username,
72                                              coded, parameters,
73                                              non_interactive, pool);
74      LocalFree(blobout.pbData);
75    }
76
77  return crypted;
78}
79
80/* Implementation of svn_auth__password_get_t that decrypts
81   the incoming password using the Windows CryptoAPI and verifies its
82   validity. */
83static svn_boolean_t
84windows_password_decrypter(const char **out,
85                           apr_hash_t *creds,
86                           const char *realmstring,
87                           const char *username,
88                           apr_hash_t *parameters,
89                           svn_boolean_t non_interactive,
90                           apr_pool_t *pool)
91{
92  DATA_BLOB blobin;
93  DATA_BLOB blobout;
94  LPWSTR descr;
95  svn_boolean_t decrypted;
96  char *in;
97
98  if (!svn_auth__simple_password_get(&in, creds, realmstring, username,
99                                     parameters, non_interactive, pool))
100    return FALSE;
101
102  blobin.cbData = strlen(in);
103  blobin.pbData = apr_palloc(pool, apr_base64_decode_len(in));
104  apr_base64_decode(blobin.pbData, in);
105  decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
106                                 CRYPTPROTECT_UI_FORBIDDEN, &blobout);
107  if (decrypted)
108    {
109      if (0 == lstrcmpW(descr, description))
110        *out = apr_pstrndup(pool, blobout.pbData, blobout.cbData);
111      else
112        decrypted = FALSE;
113      LocalFree(blobout.pbData);
114      LocalFree(descr);
115    }
116
117  return decrypted;
118}
119
120/* Get cached encrypted credentials from the simple provider's cache. */
121static svn_error_t *
122windows_simple_first_creds(void **credentials,
123                           void **iter_baton,
124                           void *provider_baton,
125                           apr_hash_t *parameters,
126                           const char *realmstring,
127                           apr_pool_t *pool)
128{
129  return svn_auth__simple_first_creds_helper(credentials,
130                                             iter_baton,
131                                             provider_baton,
132                                             parameters,
133                                             realmstring,
134                                             windows_password_decrypter,
135                                             SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
136                                             pool);
137}
138
139/* Save encrypted credentials to the simple provider's cache. */
140static svn_error_t *
141windows_simple_save_creds(svn_boolean_t *saved,
142                          void *credentials,
143                          void *provider_baton,
144                          apr_hash_t *parameters,
145                          const char *realmstring,
146                          apr_pool_t *pool)
147{
148  return svn_auth__simple_save_creds_helper(saved, credentials,
149                                            provider_baton,
150                                            parameters,
151                                            realmstring,
152                                            windows_password_encrypter,
153                                            SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
154                                            pool);
155}
156
157static const svn_auth_provider_t windows_simple_provider = {
158  SVN_AUTH_CRED_SIMPLE,
159  windows_simple_first_creds,
160  NULL,
161  windows_simple_save_creds
162};
163
164
165/* Public API */
166void
167svn_auth_get_windows_simple_provider(svn_auth_provider_object_t **provider,
168                                     apr_pool_t *pool)
169{
170  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
171
172  po->vtable = &windows_simple_provider;
173  *provider = po;
174}
175
176
177/*-----------------------------------------------------------------------*/
178/* Windows SSL server trust provider, validates ssl certificate using    */
179/* CryptoApi.                                                            */
180/*-----------------------------------------------------------------------*/
181
182/* Implementation of svn_auth__password_set_t that encrypts
183   the incoming password using the Windows CryptoAPI. */
184static svn_boolean_t
185windows_ssl_client_cert_pw_encrypter(apr_hash_t *creds,
186                                     const char *realmstring,
187                                     const char *username,
188                                     const char *in,
189                                     apr_hash_t *parameters,
190                                     svn_boolean_t non_interactive,
191                                     apr_pool_t *pool)
192{
193  DATA_BLOB blobin;
194  DATA_BLOB blobout;
195  svn_boolean_t crypted;
196
197  blobin.cbData = strlen(in);
198  blobin.pbData = (BYTE*) in;
199  crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
200                             CRYPTPROTECT_UI_FORBIDDEN, &blobout);
201  if (crypted)
202    {
203      char *coded = apr_palloc(pool, apr_base64_encode_len(blobout.cbData));
204      apr_base64_encode(coded, blobout.pbData, blobout.cbData);
205      crypted = svn_auth__ssl_client_cert_pw_set(creds, realmstring, username,
206                                                 coded, parameters,
207                                                 non_interactive, pool);
208      LocalFree(blobout.pbData);
209    }
210
211  return crypted;
212}
213
214/* Implementation of svn_auth__password_get_t that decrypts
215   the incoming password using the Windows CryptoAPI and verifies its
216   validity. */
217static svn_boolean_t
218windows_ssl_client_cert_pw_decrypter(const char **out,
219                                     apr_hash_t *creds,
220                                     const char *realmstring,
221                                     const char *username,
222                                     apr_hash_t *parameters,
223                                     svn_boolean_t non_interactive,
224                                     apr_pool_t *pool)
225{
226  DATA_BLOB blobin;
227  DATA_BLOB blobout;
228  LPWSTR descr;
229  svn_boolean_t decrypted;
230  char *in;
231
232  if (!svn_auth__ssl_client_cert_pw_get(&in, creds, realmstring, username,
233                                        parameters, non_interactive, pool))
234    return FALSE;
235
236  blobin.cbData = strlen(in);
237  blobin.pbData = apr_palloc(pool, apr_base64_decode_len(in));
238  apr_base64_decode(blobin.pbData, in);
239  decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
240                                 CRYPTPROTECT_UI_FORBIDDEN, &blobout);
241  if (decrypted)
242    {
243      if (0 == lstrcmpW(descr, description))
244        *out = apr_pstrndup(pool, blobout.pbData, blobout.cbData);
245      else
246        decrypted = FALSE;
247      LocalFree(blobout.pbData);
248      LocalFree(descr);
249    }
250
251  return decrypted;
252}
253
254/* Get cached encrypted credentials from the simple provider's cache. */
255static svn_error_t *
256windows_ssl_client_cert_pw_first_creds(void **credentials,
257                                       void **iter_baton,
258                                       void *provider_baton,
259                                       apr_hash_t *parameters,
260                                       const char *realmstring,
261                                       apr_pool_t *pool)
262{
263    return svn_auth__ssl_client_cert_pw_file_first_creds_helper
264              (credentials,
265               iter_baton,
266               provider_baton,
267               parameters,
268               realmstring,
269               windows_ssl_client_cert_pw_decrypter,
270               SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
271               pool);
272}
273
274/* Save encrypted credentials to the simple provider's cache. */
275static svn_error_t *
276windows_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
277                                      void *credentials,
278                                      void *provider_baton,
279                                      apr_hash_t *parameters,
280                                      const char *realmstring,
281                                      apr_pool_t *pool)
282{
283    return svn_auth__ssl_client_cert_pw_file_save_creds_helper
284              (saved,
285               credentials,
286               provider_baton,
287               parameters,
288               realmstring,
289               windows_ssl_client_cert_pw_encrypter,
290               SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
291               pool);
292}
293
294static const svn_auth_provider_t windows_ssl_client_cert_pw_provider = {
295  SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
296  windows_ssl_client_cert_pw_first_creds,
297  NULL,
298  windows_ssl_client_cert_pw_save_creds
299};
300
301
302/* Public API */
303void
304svn_auth_get_windows_ssl_client_cert_pw_provider
305   (svn_auth_provider_object_t **provider,
306    apr_pool_t *pool)
307{
308  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
309
310  po->vtable = &windows_ssl_client_cert_pw_provider;
311  *provider = po;
312}
313
314
315/*-----------------------------------------------------------------------*/
316/* Windows SSL server trust provider, validates ssl certificate using    */
317/* CryptoApi.                                                            */
318/*-----------------------------------------------------------------------*/
319
320/* Helper for windows_ssl_server_trust_first_credentials for validating
321 * certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
322 * certificate considered as valid.
323 */
324static svn_error_t *
325windows_validate_certificate(svn_boolean_t *ok_p,
326                             const char *ascii_cert,
327                             apr_pool_t *pool)
328{
329  PCCERT_CONTEXT cert_context = NULL;
330  CERT_CHAIN_PARA chain_para;
331  PCCERT_CHAIN_CONTEXT chain_context = NULL;
332  int cert_len;
333  char *binary_cert;
334
335  *ok_p = FALSE;
336
337  /* Use apr-util as CryptStringToBinaryA is available only on XP+. */
338  binary_cert = apr_palloc(pool,
339                           apr_base64_decode_len(ascii_cert));
340  cert_len = apr_base64_decode(binary_cert, ascii_cert);
341
342  /* Parse the certificate into a context. */
343  cert_context = CertCreateCertificateContext
344    (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, binary_cert, cert_len);
345
346  if (cert_context)
347    {
348      /* Retrieve the certificate chain of the certificate
349         (a certificate without a valid root does not have a chain). */
350      memset(&chain_para, 0, sizeof(chain_para));
351      chain_para.cbSize = sizeof(chain_para);
352
353      if (CertGetCertificateChain(NULL, cert_context, NULL, NULL, &chain_para,
354                                  CERT_CHAIN_CACHE_END_CERT,
355                                  NULL, &chain_context))
356        {
357          if (chain_context->rgpChain[0]->TrustStatus.dwErrorStatus
358              == CERT_TRUST_NO_ERROR)
359            {
360              /* Windows think the certificate is valid. */
361              *ok_p = TRUE;
362            }
363
364          CertFreeCertificateChain(chain_context);
365        }
366      CertFreeCertificateContext(cert_context);
367    }
368
369  return SVN_NO_ERROR;
370}
371
372/* Retrieve ssl server CA failure overrides (if any) from CryptoApi. */
373static svn_error_t *
374windows_ssl_server_trust_first_credentials(void **credentials,
375                                           void **iter_baton,
376                                           void *provider_baton,
377                                           apr_hash_t *parameters,
378                                           const char *realmstring,
379                                           apr_pool_t *pool)
380{
381  apr_uint32_t *failures = apr_hash_get(parameters,
382                                        SVN_AUTH_PARAM_SSL_SERVER_FAILURES,
383                                        APR_HASH_KEY_STRING);
384  const svn_auth_ssl_server_cert_info_t *cert_info =
385    apr_hash_get(parameters,
386                 SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
387                 APR_HASH_KEY_STRING);
388
389  *credentials = NULL;
390  *iter_baton = NULL;
391
392  /* We can accept only unknown certificate authority. */
393  if (*failures & SVN_AUTH_SSL_UNKNOWNCA)
394    {
395      svn_boolean_t ok;
396
397      SVN_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
398
399      /* Windows thinks that certificate is ok. */
400      if (ok)
401        {
402          /* Clear failure flag. */
403          *failures &= ~SVN_AUTH_SSL_UNKNOWNCA;
404        }
405    }
406
407  /* If all failures are cleared now, we return the creds */
408  if (! *failures)
409    {
410      svn_auth_cred_ssl_server_trust_t *creds =
411        apr_pcalloc(pool, sizeof(*creds));
412      creds->may_save = FALSE; /* No need to save it. */
413      *credentials = creds;
414    }
415
416  return SVN_NO_ERROR;
417}
418
419static const svn_auth_provider_t windows_server_trust_provider = {
420  SVN_AUTH_CRED_SSL_SERVER_TRUST,
421  windows_ssl_server_trust_first_credentials,
422  NULL,
423  NULL,
424};
425
426/* Public API */
427void
428svn_auth_get_windows_ssl_server_trust_provider
429  (svn_auth_provider_object_t **provider, apr_pool_t *pool)
430{
431  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
432
433  po->vtable = &windows_server_trust_provider;
434  *provider = po;
435}
436
437#endif /* WIN32 */
Note: See TracBrowser for help on using the repository browser.