summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_subr/win32_crypto.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2013-06-18 02:07:41 +0000
committerpeter <peter@FreeBSD.org>2013-06-18 02:07:41 +0000
commitd25dac7fcc6acc838b71bbda8916fd9665c709ab (patch)
tree135691142dc0e75a5e5d97b5074d03436435b8e0 /subversion/libsvn_subr/win32_crypto.c
downloadFreeBSD-src-d25dac7fcc6acc838b71bbda8916fd9665c709ab.zip
FreeBSD-src-d25dac7fcc6acc838b71bbda8916fd9665c709ab.tar.gz
Import trimmed svn-1.8.0-rc3
Diffstat (limited to 'subversion/libsvn_subr/win32_crypto.c')
-rw-r--r--subversion/libsvn_subr/win32_crypto.c492
1 files changed, 492 insertions, 0 deletions
diff --git a/subversion/libsvn_subr/win32_crypto.c b/subversion/libsvn_subr/win32_crypto.c
new file mode 100644
index 0000000..a7e3828
--- /dev/null
+++ b/subversion/libsvn_subr/win32_crypto.c
@@ -0,0 +1,492 @@
+/*
+ * win32_crypto.c: win32 providers for SVN_AUTH_*
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+/* prevent "empty compilation unit" warning on e.g. UNIX */
+typedef int win32_crypto__dummy;
+
+/* ==================================================================== */
+
+#if defined(WIN32) && !defined(__MINGW32__)
+
+/*** Includes. ***/
+
+#include <apr_pools.h>
+#include <apr_base64.h>
+#include "svn_auth.h"
+#include "svn_error.h"
+#include "svn_hash.h"
+#include "svn_utf.h"
+#include "svn_config.h"
+#include "svn_user.h"
+#include "svn_base64.h"
+
+#include "private/svn_auth_private.h"
+
+#include "svn_private_config.h"
+
+#include <wincrypt.h>
+
+
+/* The description string that's combined with unencrypted data by the
+ Windows CryptoAPI. Used during decryption to verify that the
+ encrypted data were valid. */
+static const WCHAR description[] = L"auth_svn.simple.wincrypt";
+
+
+/* Return a copy of ORIG, encrypted using the Windows CryptoAPI and
+ allocated from POOL. */
+const svn_string_t *
+encrypt_data(const svn_string_t *orig,
+ apr_pool_t *pool)
+{
+ DATA_BLOB blobin;
+ DATA_BLOB blobout;
+ const svn_string_t *crypted = NULL;
+
+ blobin.cbData = orig->len;
+ blobin.pbData = (BYTE *)orig->data;
+ if (CryptProtectData(&blobin, description, NULL, NULL, NULL,
+ CRYPTPROTECT_UI_FORBIDDEN, &blobout))
+ {
+ crypted = svn_string_ncreate((const char *)blobout.pbData,
+ blobout.cbData, pool);
+ LocalFree(blobout.pbData);
+ }
+ return crypted;
+}
+
+/* Return a copy of CRYPTED, decrypted using the Windows CryptoAPI and
+ allocated from POOL. */
+const svn_string_t *
+decrypt_data(const svn_string_t *crypted,
+ apr_pool_t *pool)
+{
+ DATA_BLOB blobin;
+ DATA_BLOB blobout;
+ LPWSTR descr;
+ const svn_string_t *orig = NULL;
+
+ blobin.cbData = crypted->len;
+ blobin.pbData = (BYTE *)crypted->data;
+ if (CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
+ CRYPTPROTECT_UI_FORBIDDEN, &blobout))
+ {
+ if (0 == lstrcmpW(descr, description))
+ orig = svn_string_ncreate((const char *)blobout.pbData,
+ blobout.cbData, pool);
+ LocalFree(blobout.pbData);
+ LocalFree(descr);
+ }
+ return orig;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Windows simple provider, encrypts the password on Win2k and later. */
+/*-----------------------------------------------------------------------*/
+
+/* Implementation of svn_auth__password_set_t that encrypts
+ the incoming password using the Windows CryptoAPI. */
+static svn_error_t *
+windows_password_encrypter(svn_boolean_t *done,
+ apr_hash_t *creds,
+ const char *realmstring,
+ const char *username,
+ const char *in,
+ apr_hash_t *parameters,
+ svn_boolean_t non_interactive,
+ apr_pool_t *pool)
+{
+ const svn_string_t *coded;
+
+ coded = encrypt_data(svn_string_create(in, pool), pool);
+ if (coded)
+ {
+ coded = svn_base64_encode_string2(coded, FALSE, pool);
+ SVN_ERR(svn_auth__simple_password_set(done, creds, realmstring, username,
+ coded->data, parameters,
+ non_interactive, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Implementation of svn_auth__password_get_t that decrypts
+ the incoming password using the Windows CryptoAPI and verifies its
+ validity. */
+static svn_error_t *
+windows_password_decrypter(svn_boolean_t *done,
+ const char **out,
+ apr_hash_t *creds,
+ const char *realmstring,
+ const char *username,
+ apr_hash_t *parameters,
+ svn_boolean_t non_interactive,
+ apr_pool_t *pool)
+{
+ const svn_string_t *orig;
+ const char *in;
+
+ SVN_ERR(svn_auth__simple_password_get(done, &in, creds, realmstring, username,
+ parameters, non_interactive, pool));
+ if (!*done)
+ return SVN_NO_ERROR;
+
+ orig = svn_base64_decode_string(svn_string_create(in, pool), pool);
+ orig = decrypt_data(orig, pool);
+ if (orig)
+ {
+ *out = orig->data;
+ *done = TRUE;
+ }
+ else
+ {
+ *done = FALSE;
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Get cached encrypted credentials from the simple provider's cache. */
+static svn_error_t *
+windows_simple_first_creds(void **credentials,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__simple_creds_cache_get(credentials,
+ iter_baton,
+ provider_baton,
+ parameters,
+ realmstring,
+ windows_password_decrypter,
+ SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
+ pool);
+}
+
+/* Save encrypted credentials to the simple provider's cache. */
+static svn_error_t *
+windows_simple_save_creds(svn_boolean_t *saved,
+ void *credentials,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__simple_creds_cache_set(saved, credentials,
+ provider_baton,
+ parameters,
+ realmstring,
+ windows_password_encrypter,
+ SVN_AUTH__WINCRYPT_PASSWORD_TYPE,
+ pool);
+}
+
+static const svn_auth_provider_t windows_simple_provider = {
+ SVN_AUTH_CRED_SIMPLE,
+ windows_simple_first_creds,
+ NULL,
+ windows_simple_save_creds
+};
+
+
+/* Public API */
+void
+svn_auth_get_windows_simple_provider(svn_auth_provider_object_t **provider,
+ apr_pool_t *pool)
+{
+ svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+ po->vtable = &windows_simple_provider;
+ *provider = po;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Windows SSL server trust provider, validates ssl certificate using */
+/* CryptoApi. */
+/*-----------------------------------------------------------------------*/
+
+/* Implementation of svn_auth__password_set_t that encrypts
+ the incoming password using the Windows CryptoAPI. */
+static svn_error_t *
+windows_ssl_client_cert_pw_encrypter(svn_boolean_t *done,
+ apr_hash_t *creds,
+ const char *realmstring,
+ const char *username,
+ const char *in,
+ apr_hash_t *parameters,
+ svn_boolean_t non_interactive,
+ apr_pool_t *pool)
+{
+ const svn_string_t *coded;
+
+ coded = encrypt_data(svn_string_create(in, pool), pool);
+ if (coded)
+ {
+ coded = svn_base64_encode_string2(coded, FALSE, pool);
+ SVN_ERR(svn_auth__ssl_client_cert_pw_set(done, creds, realmstring,
+ username, coded->data,
+ parameters, non_interactive,
+ pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Implementation of svn_auth__password_get_t that decrypts
+ the incoming password using the Windows CryptoAPI and verifies its
+ validity. */
+static svn_error_t *
+windows_ssl_client_cert_pw_decrypter(svn_boolean_t *done,
+ const char **out,
+ apr_hash_t *creds,
+ const char *realmstring,
+ const char *username,
+ apr_hash_t *parameters,
+ svn_boolean_t non_interactive,
+ apr_pool_t *pool)
+{
+ const svn_string_t *orig;
+ const char *in;
+
+ SVN_ERR(svn_auth__ssl_client_cert_pw_get(done, &in, creds, realmstring,
+ username, parameters,
+ non_interactive, pool));
+ if (!*done)
+ return SVN_NO_ERROR;
+
+ orig = svn_base64_decode_string(svn_string_create(in, pool), pool);
+ orig = decrypt_data(orig, pool);
+ if (orig)
+ {
+ *out = orig->data;
+ *done = TRUE;
+ }
+ else
+ {
+ *done = FALSE;
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Get cached encrypted credentials from the simple provider's cache. */
+static svn_error_t *
+windows_ssl_client_cert_pw_first_creds(void **credentials,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__ssl_client_cert_pw_cache_get(
+ credentials, iter_baton, provider_baton, parameters, realmstring,
+ windows_ssl_client_cert_pw_decrypter,
+ SVN_AUTH__WINCRYPT_PASSWORD_TYPE, pool);
+}
+
+/* Save encrypted credentials to the simple provider's cache. */
+static svn_error_t *
+windows_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
+ void *credentials,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__ssl_client_cert_pw_cache_set(
+ saved, credentials, provider_baton, parameters, realmstring,
+ windows_ssl_client_cert_pw_encrypter,
+ SVN_AUTH__WINCRYPT_PASSWORD_TYPE, pool);
+}
+
+static const svn_auth_provider_t windows_ssl_client_cert_pw_provider = {
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+ windows_ssl_client_cert_pw_first_creds,
+ NULL,
+ windows_ssl_client_cert_pw_save_creds
+};
+
+
+/* Public API */
+void
+svn_auth_get_windows_ssl_client_cert_pw_provider
+ (svn_auth_provider_object_t **provider,
+ apr_pool_t *pool)
+{
+ svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+ po->vtable = &windows_ssl_client_cert_pw_provider;
+ *provider = po;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Windows SSL server trust provider, validates ssl certificate using */
+/* CryptoApi. */
+/*-----------------------------------------------------------------------*/
+
+/* Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
+ * Returns NULL on error.
+ */
+static PCCERT_CONTEXT
+certcontext_from_base64(const char *base64_cert, apr_pool_t *pool)
+{
+ PCCERT_CONTEXT cert_context = NULL;
+ int cert_len;
+ BYTE *binary_cert;
+
+ /* Use apr-util as CryptStringToBinaryA is available only on XP+. */
+ binary_cert = apr_palloc(pool,
+ apr_base64_decode_len(base64_cert));
+ cert_len = apr_base64_decode((char*)binary_cert, base64_cert);
+
+ /* Parse the certificate into a context. */
+ cert_context = CertCreateCertificateContext
+ (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, binary_cert, cert_len);
+
+ return cert_context;
+}
+
+/* Helper for windows_ssl_server_trust_first_credentials for validating
+ * certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
+ * certificate considered as valid.
+ */
+static svn_error_t *
+windows_validate_certificate(svn_boolean_t *ok_p,
+ const char *ascii_cert,
+ apr_pool_t *pool)
+{
+ PCCERT_CONTEXT cert_context = NULL;
+ CERT_CHAIN_PARA chain_para;
+ PCCERT_CHAIN_CONTEXT chain_context = NULL;
+
+ *ok_p = FALSE;
+
+ /* Parse the certificate into a context. */
+ cert_context = certcontext_from_base64(ascii_cert, pool);
+
+ if (cert_context)
+ {
+ /* Retrieve the certificate chain of the certificate
+ (a certificate without a valid root does not have a chain). */
+ memset(&chain_para, 0, sizeof(chain_para));
+ chain_para.cbSize = sizeof(chain_para);
+
+ if (CertGetCertificateChain(NULL, cert_context, NULL, NULL, &chain_para,
+ CERT_CHAIN_CACHE_END_CERT |
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
+ NULL, &chain_context))
+ {
+ CERT_CHAIN_POLICY_PARA policy_para;
+ CERT_CHAIN_POLICY_STATUS policy_status;
+
+ policy_para.cbSize = sizeof(policy_para);
+ policy_para.dwFlags = 0;
+ policy_para.pvExtraPolicyPara = NULL;
+
+ policy_status.cbSize = sizeof(policy_status);
+
+ if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
+ chain_context, &policy_para,
+ &policy_status))
+ {
+ if (policy_status.dwError == S_OK)
+ {
+ /* Windows thinks the certificate is valid. */
+ *ok_p = TRUE;
+ }
+ }
+
+ CertFreeCertificateChain(chain_context);
+ }
+ CertFreeCertificateContext(cert_context);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Retrieve ssl server CA failure overrides (if any) from CryptoApi. */
+static svn_error_t *
+windows_ssl_server_trust_first_credentials(void **credentials,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ apr_uint32_t *failures = svn_hash_gets(parameters,
+ SVN_AUTH_PARAM_SSL_SERVER_FAILURES);
+ const svn_auth_ssl_server_cert_info_t *cert_info =
+ svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO);
+
+ *credentials = NULL;
+ *iter_baton = NULL;
+
+ /* We can accept only unknown certificate authority. */
+ if (*failures & SVN_AUTH_SSL_UNKNOWNCA)
+ {
+ svn_boolean_t ok;
+
+ SVN_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
+
+ /* Windows thinks that certificate is ok. */
+ if (ok)
+ {
+ /* Clear failure flag. */
+ *failures &= ~SVN_AUTH_SSL_UNKNOWNCA;
+ }
+ }
+
+ /* If all failures are cleared now, we return the creds */
+ if (! *failures)
+ {
+ svn_auth_cred_ssl_server_trust_t *creds =
+ apr_pcalloc(pool, sizeof(*creds));
+ creds->may_save = FALSE; /* No need to save it. */
+ *credentials = creds;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static const svn_auth_provider_t windows_server_trust_provider = {
+ SVN_AUTH_CRED_SSL_SERVER_TRUST,
+ windows_ssl_server_trust_first_credentials,
+ NULL,
+ NULL,
+};
+
+/* Public API */
+void
+svn_auth_get_windows_ssl_server_trust_provider
+ (svn_auth_provider_object_t **provider, apr_pool_t *pool)
+{
+ svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+ po->vtable = &windows_server_trust_provider;
+ *provider = po;
+}
+
+#endif /* WIN32 */
OpenPOWER on IntegriCloud