[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: svn commit: r1307538 - in /subversion/trunk: build.conf subversion/libsvn_subr/crypto.c subversion/libsvn_subr/crypto.h subversion/svn/main.c subversion/tests/libsvn_subr/ subversion/tests/libsvn_subr/crypto-test.c

From: Daniel Shahaf <danielsh_at_elego.de>
Date: Sat, 31 Mar 2012 00:40:13 +0300

cmpilato_at_apache.org wrote on Fri, Mar 30, 2012 at 17:12:37 -0000:
> Author: cmpilato
> Date: Fri Mar 30 17:12:36 2012
> New Revision: 1307538
>
> URL: http://svn.apache.org/viewvc?rev=1307538&view=rev
> Log:
> For issue #4145 ("Master passphrase and encrypted credentials cache"),
> begin adding support for some cryptographic routines in Subversion.
>
> NOTE: The code thus far is no where near complete, but I want to get
> this into version control sooner rather than later.
>
> * subversion/libsvn_subr/crypto.h,
> * subversion/libsvn_subr/crypto.c
> New files, with incomplete and as-yet-unused functions in them.
>
> * subversion/svn/main.c
> (crypto_init): New function.
> (main): Call crypto_init().
>
> * build.conf
> (crypto-test): New section (for a new test binary, also added to
> other relevant bits of this configuration file.
>
> * subversion/tests/libsvn_subr
> Add 'crypto-test' to svn:ignores.
>
> * subversion/tests/libsvn_subr/crypto-test.c
> New skeletal test file.
>
> Added: subversion/trunk/subversion/libsvn_subr/crypto.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/crypto.c?rev=1307538&view=auto
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_subr/crypto.c (added)
> +++ subversion/trunk/subversion/libsvn_subr/crypto.c Fri Mar 30 17:12:36 2012
> @@ -0,0 +1,193 @@
> +/*
> + * crypto.c : cryptographic routines
> + *
> + * ====================================================================
> + * 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.
> + * ====================================================================
> + */
> +
> +#ifdef APU_HAVE_CRYPTO
> +
> +#include "crypto.h"
> +
> +#include <apr_random.h>
> +
> +
> +static svn_error_t *
> +get_random_bytes(void **rand_bytes,
> + apr_size_t rand_len,
> + apr_pool_t *pool)
> +{
> + apr_random_t *apr_rand;

Shouldn't you reuse this context as much as possible? (instead of
creating a new context every time)

> + apr_status_t apr_err;
> +
> + *rand_bytes = apr_palloc(pool, rand_len);
> + apr_rand = apr_random_standard_new(pool);

Can this call block? I assume it can't, but APR docs aren't explicit.

Do you need to call apr_random_add_entropy() somewhere? From code
inspection the code will just error out if that function hasn't been
called (that function is the only codepath that sets 'g->secure_started'
to '1').

> + apr_err = apr_random_secure_bytes(apr_rand, *rand_bytes, rand_len);
> + if (apr_err != APR_SUCCESS)
> + return svn_error_create(apr_err, NULL, _("Error obtaining random data"));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +svn_error_t *
> +svn_crypto__context_create(apr_crypto_t **crypto_ctx,
> + apr_pool_t *pool)
> +{
> + apr_status_t apr_err;
> + const apu_err_t *apu_err = NULL;
> + const apr_crypto_driver_t *driver;
> +
> + /* ### TODO: So much for abstraction. APR's wrappings around NSS
> + and OpenSSL aren't quite as opaque as I'd hoped, requiring us
> + to specify a driver type and then params to the driver. We
> + *could* use APU_CRYPTO_RECOMMENDED_DRIVER for the driver bit,
> + but we'd still have to then dynamically ask APR which driver
> + it used and then figure out the parameters to send to that
> + driver at apr_crypto_make() time. Or maybe I'm just
> + overlooking something... -- cmpilato */
> +
> + apr_err = apr_crypto_get_driver(&driver, "openssl", NULL, &apu_err, pool);
> + if ((apr_err != APR_SUCCESS) || (! driver))
> + return svn_error_createf(apr_err,
> + err_from_apu_err(apr_err, apu_err),

If the local variable APR_ERR has value APR_SUCCESS, you'll be creating
here an svn_error_t object whose APR_ERR member is APR_SUCCESS. Perhaps
return a more useful error code when (driver == NULL && ! apr_err)?

> + _("OpenSSL crypto driver error"));
> +
> + apr_err = apr_crypto_make(crypto_ctx, driver, "engine=openssl", pool);
> + if ((apr_err != APR_SUCCESS) || (! *crypto_ctx))
> + return svn_error_create(apr_err, NULL,
> + _("Error creating OpenSSL crypto context"));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +svn_error_t *
> +svn_crypto__encrypt_cstring(unsigned char **ciphertext,
> + apr_size_t *ciphertext_len,

svn_string_t **ciphertext ?

> + const unsigned char **iv,
> + apr_size_t *iv_len,
> + const unsigned char **salt,
> + apr_size_t *salt_len,
> + apr_crypto_t *crypto_ctx,
> + const char *plaintext,
> + const char *secret,
> + apr_pool_t *result_pool,
> + apr_pool_t *scratch_pool)
> +{
> + svn_error_t *err = SVN_NO_ERROR;
> + apr_crypto_key_t *key = NULL;
> + const apu_err_t *apu_err = NULL;

Could move this variable to block scope.

> + apr_status_t apr_err;
> + const unsigned char *prefix;
> + apr_crypto_block_t *block_ctx = NULL;
> + apr_size_t block_size = 0, encrypted_len = 0;
> +
> + SVN_ERR_ASSERT(crypto_ctx);
> +
> + /* Generate the salt. */
> + *salt_len = 8;
> + SVN_ERR(get_random_bytes((void **)salt, *salt_len, result_pool));
> +
> + /* Initialize the passphrase. */
> + apr_err = apr_crypto_passphrase(&key, NULL, secret, strlen(secret),
> + *salt, 8 /* salt_len */,
> + APR_KEY_AES_256, APR_MODE_CBC,
> + 1 /* doPad */, 4096, crypto_ctx,
> + scratch_pool);
> + if (apr_err != APR_SUCCESS)
> + {
> + apr_crypto_error(&apu_err, crypto_ctx);

Need to check the return value of apr_crypto_error() before
dereferencing APU_ERR in err_from_apu_err())

> + return svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
> + _("Error creating derived key"));
> + }
> +
> + /* Generate a 4-byte prefix. */
> + SVN_ERR(get_random_bytes((void **)&prefix, 4, scratch_pool));
> +
> + /* Initialize block encryption. */
> + apr_err = apr_crypto_block_encrypt_init(&block_ctx, iv, key, &block_size,
> + result_pool);
> + if ((apr_err != APR_SUCCESS) || (! block_ctx))
> + {
> + apr_crypto_error(&apu_err, crypto_ctx);
> + return svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
> + _("Error initializing block encryption"));
> + }
> +
> + /* ### FIXME: We need to actually use the prefix! */

Also, need to avoid adding 1 to strlen() below if it's a multiple of 16.

> +
> + /* Encrypt the block. */
> + apr_err = apr_crypto_block_encrypt(ciphertext, ciphertext_len,
> + (unsigned char *)plaintext,
> + strlen(plaintext) + 1, block_ctx);
> + if (apr_err != APR_SUCCESS)
> + {
> + apr_crypto_error(&apu_err, crypto_ctx);
> + err = svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
> + _("Error encrypting block"));
> + goto cleanup;
> + }
> +
> + /* Finalize the block encryption. */
> + apr_err = apr_crypto_block_encrypt_finish(*ciphertext + *ciphertext_len,
> + &encrypted_len, block_ctx);
> + if (apr_err != APR_SUCCESS)
> + {
> + apr_crypto_error(&apu_err, crypto_ctx);
> + err = svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
> + _("Error finalizing block encryption"));
> + goto cleanup;
> + }
> +
> + cleanup:
> + apr_crypto_block_cleanup(block_ctx);
> + return err;
> +}
Received on 2012-03-30 23:41:04 CEST

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.