~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/crypto.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * crypto.c :  cryptographic routines
 
3
 *
 
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
 
12
 *
 
13
 *      http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
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
 
20
 *    under the License.
 
21
 * ====================================================================
 
22
 */
 
23
 
 
24
#include "crypto.h"
 
25
 
 
26
#ifdef SVN_HAVE_CRYPTO
 
27
#include <apr_random.h>
 
28
#include <apr_crypto.h>
 
29
#endif /* SVN_HAVE_CRYPTO */
 
30
 
 
31
#include "svn_types.h"
 
32
#include "svn_checksum.h"
 
33
 
 
34
#include "svn_private_config.h"
 
35
#include "private/svn_atomic.h"
 
36
 
 
37
 
 
38
/* 1000 iterations is the recommended minimum, per RFC 2898, section 4.2.  */
 
39
#define NUM_ITERATIONS 1000
 
40
 
 
41
 
 
42
/* Size (in bytes) of the random data we'll prepend to encrypted data. */
 
43
#define RANDOM_PREFIX_LEN 4
 
44
 
 
45
 
 
46
/* A structure for containing Subversion's cryptography-related bits
 
47
   (so we can avoid passing around APR-isms outside this module). */
 
48
struct svn_crypto__ctx_t {
 
49
#ifdef SVN_HAVE_CRYPTO
 
50
  apr_crypto_t *crypto;  /* APR cryptography context. */
 
51
 
 
52
#if 0
 
53
  /* ### For now, we will use apr_generate_random_bytes(). If we need
 
54
     ### more strength, then we can set this member using
 
55
     ### apr_random_standard_new(), then use
 
56
     ### apr_generate_random_bytes() to generate entropy for seeding
 
57
     ### apr_random_t. See httpd/server/core.c:ap_init_rng()  */
 
58
  apr_random_t *rand;
 
59
#endif /* 0 */
 
60
#else /* SVN_HAVE_CRYPTO */
 
61
  int unused_but_required_to_satisfy_c_compilers;
 
62
#endif /* SVN_HAVE_CRYPTO */
 
63
};
 
64
 
 
65
 
 
66
 
 
67
/*** Helper Functions ***/
 
68
#ifdef SVN_HAVE_CRYPTO
 
69
 
 
70
 
 
71
/* One-time initialization of the cryptography subsystem. */
 
72
static volatile svn_atomic_t crypto_init_state = 0;
 
73
 
 
74
 
 
75
#define CRYPTO_INIT(scratch_pool) \
 
76
  SVN_ERR(svn_atomic__init_once(&crypto_init_state, \
 
77
                                crypto_init, NULL, (scratch_pool)))
 
78
 
 
79
 
 
80
/* Initialize the APR cryptography subsystem (if available), using
 
81
   ANY_POOL's ancestor root pool for the registration of cleanups,
 
82
   shutdowns, etc.   */
 
83
/* Don't call this function directly!  Use svn_atomic__init_once(). */
 
84
static svn_error_t *
 
85
crypto_init(void *baton, apr_pool_t *any_pool)
 
86
{
 
87
  /* NOTE: this function will locate the topmost ancestor of ANY_POOL
 
88
     for its cleanup handlers. We don't have to worry about ANY_POOL
 
89
     being cleared.  */
 
90
  apr_status_t apr_err = apr_crypto_init(any_pool);
 
91
  if (apr_err)
 
92
    return svn_error_wrap_apr(apr_err,
 
93
                              _("Failed to initialize cryptography "
 
94
                                "subsystem"));
 
95
 
 
96
  return SVN_NO_ERROR;
 
97
}
 
98
 
 
99
 
 
100
/* If APU_ERR is non-NULL, create and return a Subversion error using
 
101
   APR_ERR and APU_ERR. */
 
102
static svn_error_t *
 
103
err_from_apu_err(apr_status_t apr_err,
 
104
                 const apu_err_t *apu_err)
 
105
{
 
106
  if (apu_err)
 
107
    return svn_error_createf(apr_err, NULL,
 
108
                             _("code (%d), reason (\"%s\"), msg (\"%s\")"),
 
109
                             apu_err->rc,
 
110
                             apu_err->reason ? apu_err->reason : "",
 
111
                             apu_err->msg ? apu_err->msg : "");
 
112
  return SVN_NO_ERROR;
 
113
}
 
114
 
 
115
 
 
116
/* Generate a Subversion error which describes the state reflected by
 
117
   APR_ERR and any crypto errors registered with CTX. */
 
118
static svn_error_t *
 
119
crypto_error_create(svn_crypto__ctx_t *ctx,
 
120
                    apr_status_t apr_err,
 
121
                    const char *msg)
 
122
{
 
123
  const apu_err_t *apu_err;
 
124
  apr_status_t rv = apr_crypto_error(&apu_err, ctx->crypto);
 
125
  svn_error_t *child;
 
126
 
 
127
  /* Ugh. The APIs are a bit slippery, so be wary.  */
 
128
  if (apr_err == APR_SUCCESS)
 
129
    apr_err = APR_EGENERAL;
 
130
 
 
131
  if (rv == APR_SUCCESS)
 
132
    child = err_from_apu_err(apr_err, apu_err);
 
133
  else
 
134
    child = svn_error_wrap_apr(rv, _("Fetching error from APR"));
 
135
 
 
136
  return svn_error_create(apr_err, child, msg);
 
137
}
 
138
 
 
139
 
 
140
/* Set RAND_BYTES to a block of bytes containing random data RAND_LEN
 
141
   long and allocated from RESULT_POOL. */
 
142
static svn_error_t *
 
143
get_random_bytes(const unsigned char **rand_bytes,
 
144
                 svn_crypto__ctx_t *ctx,
 
145
                 apr_size_t rand_len,
 
146
                 apr_pool_t *result_pool)
 
147
{
 
148
  apr_status_t apr_err;
 
149
  unsigned char *bytes;
 
150
 
 
151
  bytes = apr_palloc(result_pool, rand_len);
 
152
  apr_err = apr_generate_random_bytes(bytes, rand_len);
 
153
  if (apr_err != APR_SUCCESS)
 
154
    return svn_error_wrap_apr(apr_err, _("Error obtaining random data"));
 
155
 
 
156
  *rand_bytes = bytes;
 
157
  return SVN_NO_ERROR;
 
158
}
 
159
 
 
160
 
 
161
/* Return an svn_string_t allocated from RESULT_POOL, with its .data
 
162
   and .len members set to DATA and LEN, respective.
 
163
 
 
164
   WARNING: No lifetime management of DATA is offered here, so you
 
165
   probably want to ensure that that information is allocated in a
 
166
   sufficiently long-lived pool (such as, for example, RESULT_POOL). */
 
167
static const svn_string_t *
 
168
wrap_as_string(const unsigned char *data,
 
169
               apr_size_t len,
 
170
               apr_pool_t *result_pool)
 
171
{
 
172
  svn_string_t *s = apr_palloc(result_pool, sizeof(*s));
 
173
 
 
174
  s->data = (const char *)data;  /* better already be in RESULT_POOL  */
 
175
  s->len = len;
 
176
  return s;
 
177
}
 
178
 
 
179
 
 
180
#endif /* SVN_HAVE_CRYPTO */
 
181
 
 
182
 
 
183
 
 
184
/*** Semi-public APIs ***/
 
185
 
 
186
/* Return TRUE iff Subversion's cryptographic support is available. */
 
187
svn_boolean_t svn_crypto__is_available(void)
 
188
{
 
189
#ifdef SVN_HAVE_CRYPTO
 
190
  return TRUE;
 
191
#else /* SVN_HAVE_CRYPTO */
 
192
  return FALSE;
 
193
#endif /* SVN_HAVE_CRYPTO */
 
194
}
 
195
 
 
196
 
 
197
/* Set CTX to a Subversion cryptography context allocated from
 
198
   RESULT_POOL.  */
 
199
svn_error_t *
 
200
svn_crypto__context_create(svn_crypto__ctx_t **ctx,
 
201
                           apr_pool_t *result_pool)
 
202
{
 
203
#ifdef SVN_HAVE_CRYPTO
 
204
  apr_status_t apr_err;
 
205
  const apu_err_t *apu_err = NULL;
 
206
  apr_crypto_t *apr_crypto;
 
207
  const apr_crypto_driver_t *driver;
 
208
 
 
209
  CRYPTO_INIT(result_pool);
 
210
 
 
211
  /* Load the crypto driver.
 
212
 
 
213
     ### TODO: For the sake of flexibility, should we use
 
214
     ### APU_CRYPTO_RECOMMENDED_DRIVER instead of hard coding
 
215
     ### "openssl" here?
 
216
 
 
217
     NOTE: Potential bugs in get_driver() imply we might get
 
218
     APR_SUCCESS and NULL.  Sigh. Just be a little more careful in
 
219
     error generation here.  */
 
220
  apr_err = apr_crypto_get_driver(&driver, "openssl", NULL, &apu_err,
 
221
                                  result_pool);
 
222
  if (apr_err != APR_SUCCESS)
 
223
    return svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
 
224
                            _("OpenSSL crypto driver error"));
 
225
  if (driver == NULL)
 
226
    return svn_error_create(APR_EGENERAL,
 
227
                            err_from_apu_err(APR_EGENERAL, apu_err),
 
228
                            _("Bad return value while loading crypto "
 
229
                              "driver"));
 
230
 
 
231
  apr_err = apr_crypto_make(&apr_crypto, driver, NULL, result_pool);
 
232
  if (apr_err != APR_SUCCESS || apr_crypto == NULL)
 
233
    return svn_error_create(apr_err, NULL,
 
234
                            _("Error creating OpenSSL crypto context"));
 
235
 
 
236
  /* Allocate and initialize our crypto context. */
 
237
  *ctx = apr_palloc(result_pool, sizeof(**ctx));
 
238
  (*ctx)->crypto = apr_crypto;
 
239
 
 
240
  return SVN_NO_ERROR;
 
241
#else /* SVN_HAVE_CRYPTO */
 
242
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
243
                          "Cryptographic support is not available");
 
244
#endif /* SVN_HAVE_CRYPTO */
 
245
}
 
246
 
 
247
 
 
248
svn_error_t *
 
249
svn_crypto__encrypt_password(const svn_string_t **ciphertext,
 
250
                             const svn_string_t **iv,
 
251
                             const svn_string_t **salt,
 
252
                             svn_crypto__ctx_t *ctx,
 
253
                             const char *password,
 
254
                             const svn_string_t *master,
 
255
                             apr_pool_t *result_pool,
 
256
                             apr_pool_t *scratch_pool)
 
257
{
 
258
#ifdef SVN_HAVE_CRYPTO
 
259
  svn_error_t *err = SVN_NO_ERROR;
 
260
  const unsigned char *salt_vector;
 
261
  const unsigned char *iv_vector;
 
262
  apr_size_t iv_len;
 
263
  apr_crypto_key_t *key = NULL;
 
264
  apr_status_t apr_err;
 
265
  const unsigned char *prefix;
 
266
  apr_crypto_block_t *block_ctx = NULL;
 
267
  apr_size_t block_size;
 
268
  unsigned char *assembled;
 
269
  apr_size_t password_len, assembled_len = 0;
 
270
  apr_size_t result_len;
 
271
  unsigned char *result;
 
272
  apr_size_t ignored_result_len = 0;
 
273
 
 
274
  SVN_ERR_ASSERT(ctx != NULL);
 
275
 
 
276
  /* Generate the salt. */
 
277
#define SALT_LEN 8
 
278
  SVN_ERR(get_random_bytes(&salt_vector, ctx, SALT_LEN, result_pool));
 
279
 
 
280
  /* Initialize the passphrase.  */
 
281
  apr_err = apr_crypto_passphrase(&key, &iv_len,
 
282
                                  master->data, master->len,
 
283
                                  salt_vector, SALT_LEN,
 
284
                                  APR_KEY_AES_256, APR_MODE_CBC,
 
285
                                  FALSE /* doPad */, NUM_ITERATIONS,
 
286
                                  ctx->crypto,
 
287
                                  scratch_pool);
 
288
  if (apr_err != APR_SUCCESS)
 
289
    return svn_error_trace(crypto_error_create(
 
290
                               ctx, apr_err,
 
291
                               _("Error creating derived key")));
 
292
  if (! key)
 
293
    return svn_error_create(APR_EGENERAL, NULL,
 
294
                            _("Error creating derived key"));
 
295
  if (iv_len == 0)
 
296
    return svn_error_create(APR_EGENERAL, NULL,
 
297
                            _("Unexpected IV length returned"));
 
298
 
 
299
  /* Generate the proper length IV.  */
 
300
  SVN_ERR(get_random_bytes(&iv_vector, ctx, iv_len, result_pool));
 
301
 
 
302
  /* Initialize block encryption. */
 
303
  apr_err = apr_crypto_block_encrypt_init(&block_ctx, &iv_vector, key,
 
304
                                          &block_size, scratch_pool);
 
305
  if ((apr_err != APR_SUCCESS) || (! block_ctx))
 
306
    return svn_error_trace(crypto_error_create(
 
307
                             ctx, apr_err,
 
308
                             _("Error initializing block encryption")));
 
309
 
 
310
  /* Generate a 4-byte prefix. */
 
311
  SVN_ERR(get_random_bytes(&prefix, ctx, RANDOM_PREFIX_LEN, scratch_pool));
 
312
 
 
313
  /* Combine our prefix, original password, and appropriate padding.
 
314
     We won't bother padding if the prefix and password combined
 
315
     perfectly align on the block boundary.  If they don't,
 
316
     however, we'll drop a NUL byte after the password and pad with
 
317
     random stuff after that to the block boundary. */
 
318
  password_len = strlen(password);
 
319
  assembled_len = RANDOM_PREFIX_LEN + password_len;
 
320
  if ((assembled_len % block_size) == 0)
 
321
    {
 
322
      assembled = apr_palloc(scratch_pool, assembled_len);
 
323
      memcpy(assembled, prefix, RANDOM_PREFIX_LEN);
 
324
      memcpy(assembled + RANDOM_PREFIX_LEN, password, password_len);
 
325
    }
 
326
  else
 
327
    {
 
328
      const unsigned char *padding;
 
329
      apr_size_t pad_len = block_size - (assembled_len % block_size) - 1;
 
330
 
 
331
      SVN_ERR(get_random_bytes(&padding, ctx, pad_len, scratch_pool));
 
332
      assembled_len = assembled_len + 1 + pad_len;
 
333
      assembled = apr_palloc(scratch_pool, assembled_len);
 
334
      memcpy(assembled, prefix, RANDOM_PREFIX_LEN);
 
335
      memcpy(assembled + RANDOM_PREFIX_LEN, password, password_len);
 
336
      *(assembled + RANDOM_PREFIX_LEN + password_len) = '\0';
 
337
      memcpy(assembled + RANDOM_PREFIX_LEN + password_len + 1,
 
338
             padding, pad_len);
 
339
    }
 
340
 
 
341
  /* Get the length that we need to allocate.  */
 
342
  apr_err = apr_crypto_block_encrypt(NULL, &result_len, assembled,
 
343
                                     assembled_len, block_ctx);
 
344
  if (apr_err != APR_SUCCESS)
 
345
    {
 
346
      err = crypto_error_create(ctx, apr_err,
 
347
                                _("Error fetching result length"));
 
348
      goto cleanup;
 
349
    }
 
350
 
 
351
  /* Allocate our result buffer.  */
 
352
  result = apr_palloc(result_pool, result_len);
 
353
 
 
354
  /* Encrypt the block. */
 
355
  apr_err = apr_crypto_block_encrypt(&result, &result_len, assembled,
 
356
                                     assembled_len, block_ctx);
 
357
  if (apr_err != APR_SUCCESS)
 
358
    {
 
359
      err = crypto_error_create(ctx, apr_err,
 
360
                                _("Error during block encryption"));
 
361
      goto cleanup;
 
362
    }
 
363
 
 
364
  /* Finalize the block encryption. Since we padded everything, this should
 
365
     not produce any more encrypted output.  */
 
366
  apr_err = apr_crypto_block_encrypt_finish(NULL,
 
367
                                            &ignored_result_len,
 
368
                                            block_ctx);
 
369
  if (apr_err != APR_SUCCESS)
 
370
    {
 
371
      err = crypto_error_create(ctx, apr_err,
 
372
                                _("Error finalizing block encryption"));
 
373
      goto cleanup;
 
374
    }
 
375
 
 
376
  *ciphertext = wrap_as_string(result, result_len, result_pool);
 
377
  *iv = wrap_as_string(iv_vector, iv_len, result_pool);
 
378
  *salt = wrap_as_string(salt_vector, SALT_LEN, result_pool);
 
379
 
 
380
 cleanup:
 
381
  apr_crypto_block_cleanup(block_ctx);
 
382
  return err;
 
383
#else /* SVN_HAVE_CRYPTO */
 
384
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
385
                          "Cryptographic support is not available");
 
386
#endif /* SVN_HAVE_CRYPTO */
 
387
}
 
388
 
 
389
 
 
390
svn_error_t *
 
391
svn_crypto__decrypt_password(const char **plaintext,
 
392
                             svn_crypto__ctx_t *ctx,
 
393
                             const svn_string_t *ciphertext,
 
394
                             const svn_string_t *iv,
 
395
                             const svn_string_t *salt,
 
396
                             const svn_string_t *master,
 
397
                             apr_pool_t *result_pool,
 
398
                             apr_pool_t *scratch_pool)
 
399
{
 
400
#ifdef SVN_HAVE_CRYPTO
 
401
  svn_error_t *err = SVN_NO_ERROR;
 
402
  apr_status_t apr_err;
 
403
  apr_crypto_block_t *block_ctx = NULL;
 
404
  apr_size_t block_size, iv_len;
 
405
  apr_crypto_key_t *key = NULL;
 
406
  unsigned char *result;
 
407
  apr_size_t result_len = 0, final_len = 0;
 
408
 
 
409
  /* Initialize the passphrase.  */
 
410
  apr_err = apr_crypto_passphrase(&key, &iv_len,
 
411
                                  master->data, master->len,
 
412
                                  (unsigned char *)salt->data, salt->len,
 
413
                                  APR_KEY_AES_256, APR_MODE_CBC,
 
414
                                  FALSE /* doPad */, NUM_ITERATIONS,
 
415
                                  ctx->crypto, scratch_pool);
 
416
  if (apr_err != APR_SUCCESS)
 
417
    return svn_error_trace(crypto_error_create(
 
418
                               ctx, apr_err,
 
419
                               _("Error creating derived key")));
 
420
  if (! key)
 
421
    return svn_error_create(APR_EGENERAL, NULL,
 
422
                            _("Error creating derived key"));
 
423
  if (iv_len == 0)
 
424
    return svn_error_create(APR_EGENERAL, NULL,
 
425
                            _("Unexpected IV length returned"));
 
426
  if (iv_len != iv->len)
 
427
    return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
 
428
                            _("Provided IV has incorrect length"));
 
429
 
 
430
  apr_err = apr_crypto_block_decrypt_init(&block_ctx, &block_size,
 
431
                                          (unsigned char *)iv->data,
 
432
                                          key, scratch_pool);
 
433
  if ((apr_err != APR_SUCCESS) || (! block_ctx))
 
434
    return svn_error_trace(crypto_error_create(
 
435
                             ctx, apr_err,
 
436
                             _("Error initializing block decryption")));
 
437
 
 
438
  apr_err = apr_crypto_block_decrypt(NULL, &result_len,
 
439
                                     (unsigned char *)ciphertext->data,
 
440
                                     ciphertext->len, block_ctx);
 
441
  if (apr_err != APR_SUCCESS)
 
442
    {
 
443
      err = crypto_error_create(ctx, apr_err,
 
444
                                _("Error fetching result length"));
 
445
      goto cleanup;
 
446
    }
 
447
 
 
448
  result = apr_palloc(scratch_pool, result_len);
 
449
  apr_err = apr_crypto_block_decrypt(&result, &result_len,
 
450
                                     (unsigned char *)ciphertext->data,
 
451
                                     ciphertext->len, block_ctx);
 
452
  if (apr_err != APR_SUCCESS)
 
453
    {
 
454
      err = crypto_error_create(ctx, apr_err,
 
455
                                _("Error during block decryption"));
 
456
      goto cleanup;
 
457
    }
 
458
 
 
459
  apr_err = apr_crypto_block_decrypt_finish(result + result_len, &final_len,
 
460
                                            block_ctx);
 
461
  if (apr_err != APR_SUCCESS)
 
462
    {
 
463
      err = crypto_error_create(ctx, apr_err,
 
464
                                _("Error finalizing block decryption"));
 
465
      goto cleanup;
 
466
    }
 
467
 
 
468
  /* Copy the non-random bits of the resulting plaintext, skipping the
 
469
     prefix and ignoring any trailing padding. */
 
470
  *plaintext = apr_pstrndup(result_pool,
 
471
                            (const char *)(result + RANDOM_PREFIX_LEN),
 
472
                            result_len + final_len - RANDOM_PREFIX_LEN);
 
473
 
 
474
 cleanup:
 
475
  apr_crypto_block_cleanup(block_ctx);
 
476
  return err;
 
477
#else /* SVN_HAVE_CRYPTO */
 
478
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
479
                          "Cryptographic support is not available");
 
480
#endif /* SVN_HAVE_CRYPTO */
 
481
}
 
482
 
 
483
 
 
484
svn_error_t *
 
485
svn_crypto__generate_secret_checktext(const svn_string_t **ciphertext,
 
486
                                      const svn_string_t **iv,
 
487
                                      const svn_string_t **salt,
 
488
                                      const char **checktext,
 
489
                                      svn_crypto__ctx_t *ctx,
 
490
                                      const svn_string_t *master,
 
491
                                      apr_pool_t *result_pool,
 
492
                                      apr_pool_t *scratch_pool)
 
493
{
 
494
#ifdef SVN_HAVE_CRYPTO
 
495
  svn_error_t *err = SVN_NO_ERROR;
 
496
  const unsigned char *salt_vector;
 
497
  const unsigned char *iv_vector;
 
498
  const unsigned char *stuff_vector;
 
499
  apr_size_t iv_len;
 
500
  apr_crypto_key_t *key = NULL;
 
501
  apr_status_t apr_err;
 
502
  apr_crypto_block_t *block_ctx = NULL;
 
503
  apr_size_t block_size;
 
504
  apr_size_t result_len;
 
505
  unsigned char *result;
 
506
  apr_size_t ignored_result_len = 0;
 
507
  apr_size_t stuff_len;
 
508
  svn_checksum_t *stuff_sum;
 
509
 
 
510
  SVN_ERR_ASSERT(ctx != NULL);
 
511
 
 
512
  /* Generate the salt. */
 
513
  SVN_ERR(get_random_bytes(&salt_vector, ctx, SALT_LEN, result_pool));
 
514
 
 
515
  /* Initialize the passphrase.  */
 
516
  apr_err = apr_crypto_passphrase(&key, &iv_len,
 
517
                                  master->data, master->len,
 
518
                                  salt_vector, SALT_LEN,
 
519
                                  APR_KEY_AES_256, APR_MODE_CBC,
 
520
                                  FALSE /* doPad */, NUM_ITERATIONS,
 
521
                                  ctx->crypto,
 
522
                                  scratch_pool);
 
523
  if (apr_err != APR_SUCCESS)
 
524
    return svn_error_trace(crypto_error_create(
 
525
                               ctx, apr_err,
 
526
                               _("Error creating derived key")));
 
527
  if (! key)
 
528
    return svn_error_create(APR_EGENERAL, NULL,
 
529
                            _("Error creating derived key"));
 
530
  if (iv_len == 0)
 
531
    return svn_error_create(APR_EGENERAL, NULL,
 
532
                            _("Unexpected IV length returned"));
 
533
 
 
534
  /* Generate the proper length IV.  */
 
535
  SVN_ERR(get_random_bytes(&iv_vector, ctx, iv_len, result_pool));
 
536
 
 
537
  /* Initialize block encryption. */
 
538
  apr_err = apr_crypto_block_encrypt_init(&block_ctx, &iv_vector, key,
 
539
                                          &block_size, scratch_pool);
 
540
  if ((apr_err != APR_SUCCESS) || (! block_ctx))
 
541
    return svn_error_trace(crypto_error_create(
 
542
                             ctx, apr_err,
 
543
                             _("Error initializing block encryption")));
 
544
 
 
545
  /* Generate a blob of random data, block-aligned per the
 
546
     requirements of the encryption algorithm, but with a minimum size
 
547
     of our choosing.  */
 
548
#define MIN_STUFF_LEN 32
 
549
  if (MIN_STUFF_LEN % block_size)
 
550
    stuff_len = MIN_STUFF_LEN + (block_size - (MIN_STUFF_LEN % block_size));
 
551
  else
 
552
    stuff_len = MIN_STUFF_LEN;
 
553
  SVN_ERR(get_random_bytes(&stuff_vector, ctx, stuff_len, scratch_pool));
 
554
 
 
555
  /* ### FIXME:  This should be a SHA-256.  */
 
556
  SVN_ERR(svn_checksum(&stuff_sum, svn_checksum_sha1, stuff_vector,
 
557
                       stuff_len, scratch_pool));
 
558
 
 
559
  /* Get the length that we need to allocate.  */
 
560
  apr_err = apr_crypto_block_encrypt(NULL, &result_len, stuff_vector,
 
561
                                     stuff_len, block_ctx);
 
562
  if (apr_err != APR_SUCCESS)
 
563
    {
 
564
      err = crypto_error_create(ctx, apr_err,
 
565
                                _("Error fetching result length"));
 
566
      goto cleanup;
 
567
    }
 
568
 
 
569
  /* Allocate our result buffer.  */
 
570
  result = apr_palloc(result_pool, result_len);
 
571
 
 
572
  /* Encrypt the block. */
 
573
  apr_err = apr_crypto_block_encrypt(&result, &result_len, stuff_vector,
 
574
                                     stuff_len, block_ctx);
 
575
  if (apr_err != APR_SUCCESS)
 
576
    {
 
577
      err = crypto_error_create(ctx, apr_err,
 
578
                                _("Error during block encryption"));
 
579
      goto cleanup;
 
580
    }
 
581
 
 
582
  /* Finalize the block encryption. Since we padded everything, this should
 
583
     not produce any more encrypted output.  */
 
584
  apr_err = apr_crypto_block_encrypt_finish(NULL,
 
585
                                            &ignored_result_len,
 
586
                                            block_ctx);
 
587
  if (apr_err != APR_SUCCESS)
 
588
    {
 
589
      err = crypto_error_create(ctx, apr_err,
 
590
                                _("Error finalizing block encryption"));
 
591
      goto cleanup;
 
592
    }
 
593
 
 
594
  *ciphertext = wrap_as_string(result, result_len, result_pool);
 
595
  *iv = wrap_as_string(iv_vector, iv_len, result_pool);
 
596
  *salt = wrap_as_string(salt_vector, SALT_LEN, result_pool);
 
597
  *checktext = svn_checksum_to_cstring(stuff_sum, result_pool);
 
598
 
 
599
 cleanup:
 
600
  apr_crypto_block_cleanup(block_ctx);
 
601
  return err;
 
602
#else /* SVN_HAVE_CRYPTO */
 
603
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
604
                          "Cryptographic support is not available");
 
605
#endif /* SVN_HAVE_CRYPTO */
 
606
}
 
607
 
 
608
 
 
609
svn_error_t *
 
610
svn_crypto__verify_secret(svn_boolean_t *is_valid,
 
611
                          svn_crypto__ctx_t *ctx,
 
612
                          const svn_string_t *master,
 
613
                          const svn_string_t *ciphertext,
 
614
                          const svn_string_t *iv,
 
615
                          const svn_string_t *salt,
 
616
                          const char *checktext,
 
617
                          apr_pool_t *scratch_pool)
 
618
{
 
619
#ifdef SVN_HAVE_CRYPTO
 
620
  svn_error_t *err = SVN_NO_ERROR;
 
621
  apr_status_t apr_err;
 
622
  apr_crypto_block_t *block_ctx = NULL;
 
623
  apr_size_t block_size, iv_len;
 
624
  apr_crypto_key_t *key = NULL;
 
625
  unsigned char *result;
 
626
  apr_size_t result_len = 0, final_len = 0;
 
627
  svn_checksum_t *result_sum;
 
628
 
 
629
  *is_valid = FALSE;
 
630
 
 
631
  /* Initialize the passphrase.  */
 
632
  apr_err = apr_crypto_passphrase(&key, &iv_len,
 
633
                                  master->data, master->len,
 
634
                                  (unsigned char *)salt->data, salt->len,
 
635
                                  APR_KEY_AES_256, APR_MODE_CBC,
 
636
                                  FALSE /* doPad */, NUM_ITERATIONS,
 
637
                                  ctx->crypto, scratch_pool);
 
638
  if (apr_err != APR_SUCCESS)
 
639
    return svn_error_trace(crypto_error_create(
 
640
                               ctx, apr_err,
 
641
                               _("Error creating derived key")));
 
642
  if (! key)
 
643
    return svn_error_create(APR_EGENERAL, NULL,
 
644
                            _("Error creating derived key"));
 
645
  if (iv_len == 0)
 
646
    return svn_error_create(APR_EGENERAL, NULL,
 
647
                            _("Unexpected IV length returned"));
 
648
  if (iv_len != iv->len)
 
649
    return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
 
650
                            _("Provided IV has incorrect length"));
 
651
 
 
652
  apr_err = apr_crypto_block_decrypt_init(&block_ctx, &block_size,
 
653
                                          (unsigned char *)iv->data,
 
654
                                          key, scratch_pool);
 
655
  if ((apr_err != APR_SUCCESS) || (! block_ctx))
 
656
    return svn_error_trace(crypto_error_create(
 
657
                             ctx, apr_err,
 
658
                             _("Error initializing block decryption")));
 
659
 
 
660
  apr_err = apr_crypto_block_decrypt(NULL, &result_len,
 
661
                                     (unsigned char *)ciphertext->data,
 
662
                                     ciphertext->len, block_ctx);
 
663
  if (apr_err != APR_SUCCESS)
 
664
    {
 
665
      err = crypto_error_create(ctx, apr_err,
 
666
                                _("Error fetching result length"));
 
667
      goto cleanup;
 
668
    }
 
669
 
 
670
  result = apr_palloc(scratch_pool, result_len);
 
671
  apr_err = apr_crypto_block_decrypt(&result, &result_len,
 
672
                                     (unsigned char *)ciphertext->data,
 
673
                                     ciphertext->len, block_ctx);
 
674
  if (apr_err != APR_SUCCESS)
 
675
    {
 
676
      err = crypto_error_create(ctx, apr_err,
 
677
                                _("Error during block decryption"));
 
678
      goto cleanup;
 
679
    }
 
680
 
 
681
  apr_err = apr_crypto_block_decrypt_finish(result + result_len, &final_len,
 
682
                                            block_ctx);
 
683
  if (apr_err != APR_SUCCESS)
 
684
    {
 
685
      err = crypto_error_create(ctx, apr_err,
 
686
                                _("Error finalizing block decryption"));
 
687
      goto cleanup;
 
688
    }
 
689
 
 
690
  /* ### FIXME:  This should be a SHA-256.  */
 
691
  SVN_ERR(svn_checksum(&result_sum, svn_checksum_sha1, result,
 
692
                       result_len + final_len, scratch_pool));
 
693
 
 
694
  *is_valid = strcmp(checktext,
 
695
                     svn_checksum_to_cstring(result_sum, scratch_pool)) == 0;
 
696
 
 
697
 cleanup:
 
698
  apr_crypto_block_cleanup(block_ctx);
 
699
  return err;
 
700
#else /* SVN_HAVE_CRYPTO */
 
701
  *is_valid = FALSE;
 
702
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
703
                          "Cryptographic support is not available");
 
704
#endif /* SVN_HAVE_CRYPTO */
 
705
}