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

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/x509parse.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  X.509 certificate and private key decoding
 
3
 *
 
4
 *  Based on XySSL: Copyright (C) 2006-2008   Christophe Devine
 
5
 *
 
6
 *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
 
7
 *
 
8
 *  All rights reserved.
 
9
 *
 
10
 *  Redistribution and use in source and binary forms, with or without
 
11
 *  modification, are permitted provided that the following conditions
 
12
 *  are met:
 
13
 *
 
14
 *    * Redistributions of source code must retain the above copyright
 
15
 *    notice, this list of conditions and the following disclaimer.
 
16
 *    * Redistributions in binary form must reproduce the above copyright
 
17
 *    notice, this list of conditions and the following disclaimer in the
 
18
 *    documentation and/or other materials provided with the distribution.
 
19
 *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
 
20
 *    may be used to endorse or promote products derived from this software
 
21
 *    without specific prior written permission.
 
22
 *
 
23
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
24
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
25
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 
26
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
27
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
28
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 
29
 *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
30
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
31
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
32
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
33
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
34
 */
 
35
/*
 
36
 *  The ITU-T X.509 standard defines a certificate format for PKI.
 
37
 *
 
38
 *  http://www.ietf.org/rfc/rfc5280.txt
 
39
 *  http://www.ietf.org/rfc/rfc3279.txt
 
40
 *  http://www.ietf.org/rfc/rfc6818.txt
 
41
 *
 
42
 *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
 
43
 *
 
44
 *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
 
45
 *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
 
46
 */
 
47
 
 
48
#include <apr_pools.h>
 
49
#include <apr_tables.h>
 
50
#include "svn_hash.h"
 
51
#include "svn_string.h"
 
52
#include "svn_time.h"
 
53
#include "svn_checksum.h"
 
54
#include "svn_utf.h"
 
55
#include "svn_ctype.h"
 
56
#include "private/svn_utf_private.h"
 
57
#include "private/svn_string_private.h"
 
58
 
 
59
#include "x509.h"
 
60
 
 
61
#include <string.h>
 
62
#include <stdio.h>
 
63
 
 
64
/*
 
65
 * ASN.1 DER decoding routines
 
66
 */
 
67
static svn_error_t *
 
68
asn1_get_len(const unsigned char **p, const unsigned char *end,
 
69
             ptrdiff_t *len)
 
70
{
 
71
  if ((end - *p) < 1)
 
72
    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
73
 
 
74
  if ((**p & 0x80) == 0)
 
75
    *len = *(*p)++;
 
76
  else
 
77
    switch (**p & 0x7F)
 
78
      {
 
79
      case 1:
 
80
        if ((end - *p) < 2)
 
81
          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
82
 
 
83
        *len = (*p)[1];
 
84
        (*p) += 2;
 
85
        break;
 
86
 
 
87
      case 2:
 
88
        if ((end - *p) < 3)
 
89
          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
90
 
 
91
        *len = ((*p)[1] << 8) | (*p)[2];
 
92
        (*p) += 3;
 
93
        break;
 
94
 
 
95
      default:
 
96
        return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
 
97
        break;
 
98
      }
 
99
 
 
100
  if (*len > (end - *p))
 
101
    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
102
 
 
103
  return SVN_NO_ERROR;
 
104
}
 
105
 
 
106
static svn_error_t *
 
107
asn1_get_tag(const unsigned char **p,
 
108
             const unsigned char *end, ptrdiff_t *len, int tag)
 
109
{
 
110
  if ((end - *p) < 1)
 
111
    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
112
 
 
113
  if (**p != tag)
 
114
    return svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
 
115
 
 
116
  (*p)++;
 
117
 
 
118
  return svn_error_trace(asn1_get_len(p, end, len));
 
119
}
 
120
 
 
121
static svn_error_t *
 
122
asn1_get_int(const unsigned char **p, const unsigned char *end, int *val)
 
123
{
 
124
  ptrdiff_t len;
 
125
 
 
126
  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_INTEGER));
 
127
 
 
128
  /* Reject bit patterns that would overflow the output and those that
 
129
     represent negative values. */
 
130
  if (len > (int)sizeof(int) || (**p & 0x80) != 0)
 
131
    return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
 
132
 
 
133
  *val = 0;
 
134
 
 
135
  while (len-- > 0) {
 
136
    /* This would be undefined for bit-patterns of negative values. */
 
137
    *val = (*val << 8) | **p;
 
138
    (*p)++;
 
139
  }
 
140
 
 
141
  return SVN_NO_ERROR;
 
142
}
 
143
 
 
144
static svn_boolean_t
 
145
equal(const void *left, apr_size_t left_len,
 
146
      const void *right, apr_size_t right_len)
 
147
{
 
148
  if (left_len != right_len)
 
149
    return FALSE;
 
150
 
 
151
  return memcmp(left, right, right_len) == 0;
 
152
}
 
153
 
 
154
static svn_boolean_t
 
155
oids_equal(x509_buf *left, x509_buf *right)
 
156
{
 
157
  return equal(left->p, left->len,
 
158
               right->p, right->len);
 
159
}
 
160
 
 
161
/*
 
162
 *  Version   ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
 
163
 */
 
164
static svn_error_t *
 
165
x509_get_version(const unsigned char **p, const unsigned char *end, int *ver)
 
166
{
 
167
  svn_error_t *err;
 
168
  ptrdiff_t len;
 
169
 
 
170
  /*
 
171
   * As defined in the Basic Certificate fields:
 
172
   *   version         [0]  EXPLICIT Version DEFAULT v1,
 
173
   * the version is the context specific tag 0.
 
174
   */
 
175
  err = asn1_get_tag(p, end, &len,
 
176
                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0);
 
177
  if (err)
 
178
    {
 
179
      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
 
180
        {
 
181
          svn_error_clear(err);
 
182
          *ver = 0;
 
183
          return SVN_NO_ERROR;
 
184
        }
 
185
 
 
186
      return svn_error_trace(err);
 
187
    }
 
188
 
 
189
  end = *p + len;
 
190
 
 
191
  err = asn1_get_int(p, end, ver);
 
192
  if (err)
 
193
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
 
194
 
 
195
  if (*p != end)
 
196
    {
 
197
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
198
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
 
199
    }
 
200
 
 
201
  return SVN_NO_ERROR;
 
202
}
 
203
 
 
204
/*
 
205
 *  CertificateSerialNumber   ::=  INTEGER
 
206
 */
 
207
static svn_error_t *
 
208
x509_get_serial(const unsigned char **p,
 
209
                const unsigned char *end, x509_buf * serial)
 
210
{
 
211
  svn_error_t *err;
 
212
 
 
213
  if ((end - *p) < 1)
 
214
    {
 
215
      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
216
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
 
217
    }
 
218
 
 
219
  if (**p != (ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2) &&
 
220
      **p != ASN1_INTEGER)
 
221
    {
 
222
      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
 
223
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
 
224
    }
 
225
 
 
226
  serial->tag = *(*p)++;
 
227
 
 
228
  err = asn1_get_len(p, end, &serial->len);
 
229
  if (err)
 
230
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
 
231
 
 
232
  serial->p = *p;
 
233
  *p += serial->len;
 
234
 
 
235
  return SVN_NO_ERROR;
 
236
}
 
237
 
 
238
/*
 
239
 *  AlgorithmIdentifier   ::=  SEQUENCE  {
 
240
 *     algorithm         OBJECT IDENTIFIER,
 
241
 *     parameters        ANY DEFINED BY algorithm OPTIONAL  }
 
242
 */
 
243
static svn_error_t *
 
244
x509_get_alg(const unsigned char **p, const unsigned char *end, x509_buf * alg)
 
245
{
 
246
  svn_error_t *err;
 
247
  ptrdiff_t len;
 
248
 
 
249
  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
250
  if (err)
 
251
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
 
252
 
 
253
  end = *p + len;
 
254
  alg->tag = **p;
 
255
 
 
256
  err = asn1_get_tag(p, end, &alg->len, ASN1_OID);
 
257
  if (err)
 
258
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
 
259
 
 
260
  alg->p = *p;
 
261
  *p += alg->len;
 
262
 
 
263
  if (*p == end)
 
264
    return SVN_NO_ERROR;
 
265
 
 
266
  /*
 
267
   * assume the algorithm parameters must be NULL
 
268
   */
 
269
  err = asn1_get_tag(p, end, &len, ASN1_NULL);
 
270
  if (err)
 
271
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
 
272
 
 
273
  if (*p != end)
 
274
    {
 
275
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
276
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
 
277
    }
 
278
 
 
279
  return SVN_NO_ERROR;
 
280
}
 
281
 
 
282
/*
 
283
 *  AttributeTypeAndValue ::= SEQUENCE {
 
284
 *    type     AttributeType,
 
285
 *    value     AttributeValue }
 
286
 *
 
287
 *  AttributeType ::= OBJECT IDENTIFIER
 
288
 *
 
289
 *  AttributeValue ::= ANY DEFINED BY AttributeType
 
290
 */
 
291
static svn_error_t *
 
292
x509_get_attribute(const unsigned char **p, const unsigned char *end,
 
293
                   x509_name *cur, apr_pool_t *result_pool)
 
294
{
 
295
  svn_error_t *err;
 
296
  ptrdiff_t len;
 
297
  x509_buf *oid;
 
298
  x509_buf *val;
 
299
 
 
300
  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
301
  if (err)
 
302
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
303
 
 
304
  end = *p + len;
 
305
 
 
306
  oid = &cur->oid;
 
307
 
 
308
  err = asn1_get_tag(p, end, &oid->len, ASN1_OID);
 
309
  if (err)
 
310
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
311
 
 
312
  oid->tag = ASN1_OID;
 
313
  oid->p = *p;
 
314
  *p += oid->len;
 
315
 
 
316
  if ((end - *p) < 1)
 
317
    {
 
318
      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
 
319
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
320
    }
 
321
 
 
322
  if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
 
323
      **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
 
324
      **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING)
 
325
    {
 
326
      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
 
327
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
328
    }
 
329
 
 
330
  val = &cur->val;
 
331
  val->tag = *(*p)++;
 
332
 
 
333
  err = asn1_get_len(p, end, &val->len);
 
334
  if (err)
 
335
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
336
 
 
337
  val->p = *p;
 
338
  *p += val->len;
 
339
 
 
340
  cur->next = NULL;
 
341
 
 
342
  if (*p != end)
 
343
    {
 
344
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
345
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
346
    }
 
347
 
 
348
  return SVN_NO_ERROR;
 
349
}
 
350
 
 
351
/*
 
352
 *   RelativeDistinguishedName ::=
 
353
 *   SET SIZE (1..MAX) OF AttributeTypeAndValue
 
354
 */
 
355
static svn_error_t *
 
356
x509_get_name(const unsigned char **p, const unsigned char *name_end,
 
357
              x509_name *name, apr_pool_t *result_pool)
 
358
{
 
359
  svn_error_t *err;
 
360
  ptrdiff_t len;
 
361
  const unsigned char *set_end;
 
362
  x509_name *cur = NULL;
 
363
 
 
364
  err = asn1_get_tag(p, name_end, &len, ASN1_CONSTRUCTED | ASN1_SET);
 
365
  if (err)
 
366
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
 
367
 
 
368
  set_end = *p + len;
 
369
 
 
370
  /*
 
371
   * iterate until the end of the SET is reached
 
372
   */
 
373
  while (*p < set_end)
 
374
    {
 
375
      if (!cur)
 
376
        {
 
377
          cur = name;
 
378
        }
 
379
      else
 
380
        {
 
381
          cur->next = apr_palloc(result_pool, sizeof(x509_name));
 
382
          cur = cur->next;
 
383
        }
 
384
      SVN_ERR(x509_get_attribute(p, set_end, cur, result_pool));
 
385
    }
 
386
 
 
387
  /*
 
388
   * recurse until end of SEQUENCE (name) is reached
 
389
   */
 
390
  if (*p == name_end)
 
391
    return SVN_NO_ERROR;
 
392
 
 
393
  cur->next = apr_palloc(result_pool, sizeof(x509_name));
 
394
 
 
395
  return svn_error_trace(x509_get_name(p, name_end, cur->next, result_pool));
 
396
}
 
397
 
 
398
/* Retrieve the date from the X.509 cert data between *P and END in either
 
399
 * UTCTime or GeneralizedTime format (as defined in RFC 5280 s. 4.1.2.5.1 and
 
400
 * 4.1.2.5.2 respectively) and place the result in WHEN using  SCRATCH_POOL
 
401
 * for temporary allocations. */
 
402
static svn_error_t *
 
403
x509_get_date(apr_time_t *when,
 
404
              const unsigned char **p,
 
405
              const unsigned char *end,
 
406
              apr_pool_t *scratch_pool)
 
407
{
 
408
  svn_error_t *err;
 
409
  apr_status_t ret;
 
410
  int tag;
 
411
  ptrdiff_t len;
 
412
  char *date;
 
413
  apr_time_exp_t xt = { 0 };
 
414
  char tz;
 
415
 
 
416
  err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME);
 
417
  if (err && err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
 
418
    {
 
419
      svn_error_clear(err);
 
420
      err = asn1_get_tag(p, end, &len, ASN1_GENERALIZED_TIME);
 
421
      tag = ASN1_GENERALIZED_TIME;
 
422
    }
 
423
  else
 
424
    {
 
425
      tag = ASN1_UTC_TIME;
 
426
    }
 
427
  if (err)
 
428
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
 
429
 
 
430
  date = apr_pstrndup(scratch_pool, (const char *) *p, len);
 
431
  switch (tag)
 
432
    {
 
433
    case ASN1_UTC_TIME:
 
434
      if (sscanf(date, "%2d%2d%2d%2d%2d%2d%c",
 
435
                 &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
 
436
                 &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
 
437
        return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
 
438
 
 
439
      /* UTCTime only provides a 2 digit year.  X.509 specifies that years
 
440
       * greater than or equal to 50 must be interpreted as 19YY and years
 
441
       * less than 50 be interpreted as 20YY.  This format is not used for
 
442
       * years greater than 2049. apr_time_exp_t wants years as the number
 
443
       * of years since 1900, so don't convert to 4 digits here. */
 
444
      xt.tm_year += 100 * (xt.tm_year < 50);
 
445
      break;
 
446
 
 
447
    case ASN1_GENERALIZED_TIME:
 
448
      if (sscanf(date, "%4d%2d%2d%2d%2d%2d%c",
 
449
                 &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
 
450
                 &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
 
451
        return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
 
452
 
 
453
      /* GeneralizedTime has the full 4 digit year.  But apr_time_exp_t
 
454
       * wants years as the number of years since 1900. */
 
455
      xt.tm_year -= 1900;
 
456
      break;
 
457
 
 
458
    default:
 
459
      /* shouldn't ever get here because we should error out above in the
 
460
       * asn1_get_tag() bits but doesn't hurt to be extra paranoid. */
 
461
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
 
462
      break;
 
463
    }
 
464
 
 
465
  /* check that the timezone is GMT
 
466
   * ASN.1 allows for the timezone to be specified but X.509 says it must
 
467
   * always be GMT.  A little bit of extra paranoia here seems like a good
 
468
   * idea. */
 
469
  if (tz != 'Z')
 
470
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
 
471
 
 
472
  /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */
 
473
  xt.tm_mon -= 1;
 
474
 
 
475
  ret = apr_time_exp_gmt_get(when, &xt);
 
476
  if (ret)
 
477
    return svn_error_wrap_apr(ret, NULL);
 
478
 
 
479
  *p += len;
 
480
 
 
481
  return SVN_NO_ERROR;
 
482
}
 
483
 
 
484
/*
 
485
 *  Validity ::= SEQUENCE {
 
486
 *     notBefore    Time,
 
487
 *     notAfter    Time }
 
488
 *
 
489
 *  Time ::= CHOICE {
 
490
 *     utcTime    UTCTime,
 
491
 *     generalTime  GeneralizedTime }
 
492
 */
 
493
static svn_error_t *
 
494
x509_get_dates(apr_time_t *from,
 
495
               apr_time_t *to,
 
496
               const unsigned char **p,
 
497
               const unsigned char *end,
 
498
               apr_pool_t *scratch_pool)
 
499
{
 
500
  svn_error_t *err;
 
501
  ptrdiff_t len;
 
502
 
 
503
  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
504
  if (err)
 
505
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
 
506
 
 
507
  end = *p + len;
 
508
 
 
509
  SVN_ERR(x509_get_date(from, p, end, scratch_pool));
 
510
 
 
511
  SVN_ERR(x509_get_date(to, p, end, scratch_pool));
 
512
 
 
513
  if (*p != end)
 
514
    {
 
515
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
516
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
 
517
    }
 
518
 
 
519
  return SVN_NO_ERROR;
 
520
}
 
521
 
 
522
static svn_error_t *
 
523
x509_get_sig(const unsigned char **p, const unsigned char *end, x509_buf * sig)
 
524
{
 
525
  svn_error_t *err;
 
526
  ptrdiff_t len;
 
527
 
 
528
  err = asn1_get_tag(p, end, &len, ASN1_BIT_STRING);
 
529
  if (err)
 
530
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, err, NULL);
 
531
 
 
532
  sig->tag = ASN1_BIT_STRING;
 
533
 
 
534
  if (--len < 1 || *(*p)++ != 0)
 
535
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, NULL, NULL);
 
536
 
 
537
  sig->len = len;
 
538
  sig->p = *p;
 
539
 
 
540
  *p += len;
 
541
 
 
542
  return SVN_NO_ERROR;
 
543
}
 
544
 
 
545
/*
 
546
 * X.509 v2/v3 unique identifier (not parsed)
 
547
 */
 
548
static svn_error_t *
 
549
x509_get_uid(const unsigned char **p,
 
550
             const unsigned char *end, x509_buf * uid, int n)
 
551
{
 
552
  svn_error_t *err;
 
553
 
 
554
  if (*p == end)
 
555
    return SVN_NO_ERROR;
 
556
 
 
557
  err = asn1_get_tag(p, end, &uid->len,
 
558
                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n);
 
559
  if (err)
 
560
    {
 
561
      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
 
562
        {
 
563
          svn_error_clear(err);
 
564
          return SVN_NO_ERROR;
 
565
        }
 
566
 
 
567
      return svn_error_trace(err);
 
568
    }
 
569
 
 
570
  uid->tag = ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n;
 
571
  uid->p = *p;
 
572
  *p += uid->len;
 
573
 
 
574
  return SVN_NO_ERROR;
 
575
}
 
576
 
 
577
/*
 
578
 * X.509 v3 extensions (not parsed)
 
579
 */
 
580
static svn_error_t *
 
581
x509_get_ext(apr_array_header_t *dnsnames,
 
582
             const unsigned char **p,
 
583
             const unsigned char *end)
 
584
{
 
585
  svn_error_t *err;
 
586
  ptrdiff_t len;
 
587
 
 
588
  if (*p == end)
 
589
    return SVN_NO_ERROR;
 
590
 
 
591
  err = asn1_get_tag(p, end, &len,
 
592
                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3);
 
593
  if (err)
 
594
    {
 
595
      /* If there aren't extensions that's ok they aren't required */
 
596
      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
 
597
        {
 
598
          svn_error_clear(err);
 
599
          return SVN_NO_ERROR;
 
600
        }
 
601
 
 
602
      return svn_error_trace(err);
 
603
    }
 
604
 
 
605
  end = *p + len;
 
606
 
 
607
  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE));
 
608
 
 
609
  if (end != *p + len)
 
610
    {
 
611
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
612
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
 
613
    }
 
614
 
 
615
  while (*p < end)
 
616
    {
 
617
      ptrdiff_t ext_len;
 
618
      const unsigned char *ext_start, *sna_end;
 
619
      err = asn1_get_tag(p, end, &ext_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
620
      if (err)
 
621
        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
 
622
                                NULL);
 
623
      ext_start = *p;
 
624
 
 
625
      err = asn1_get_tag(p, end, &len, ASN1_OID);
 
626
      if (err)
 
627
        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
 
628
                                NULL);
 
629
 
 
630
      /* skip all extensions except SubjectAltName */
 
631
      if (!equal(*p, len,
 
632
                 OID_SUBJECT_ALT_NAME, sizeof(OID_SUBJECT_ALT_NAME) - 1))
 
633
        {
 
634
          *p += ext_len - (*p - ext_start);
 
635
          continue;
 
636
        }
 
637
      *p += len;
 
638
 
 
639
      err = asn1_get_tag(p, end, &len, ASN1_OCTET_STRING);
 
640
      if (err)
 
641
        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
 
642
                                NULL);
 
643
 
 
644
      /*   SubjectAltName ::= GeneralNames
 
645
 
 
646
           GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
 
647
 
 
648
           GeneralName ::= CHOICE {
 
649
                other Name                      [0]     OtherName,
 
650
                rfc822Name                      [1]     IA5String,
 
651
                dNSName                         [2]     IA5String,
 
652
                x400Address                     [3]     ORAddress,
 
653
                directoryName                   [4]     Name,
 
654
                ediPartyName                    [5]     EDIPartyName,
 
655
                uniformResourceIdentifier       [6]     IA5String,
 
656
                iPAddress                       [7]     OCTET STRING,
 
657
                registeredID                    [8]     OBJECT IDENTIFIER } */
 
658
      sna_end = *p + len;
 
659
 
 
660
      err = asn1_get_tag(p, sna_end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
661
      if (err)
 
662
        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
 
663
                                NULL);
 
664
 
 
665
      if (sna_end != *p + len)
 
666
        {
 
667
          err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
668
          return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
 
669
        }
 
670
 
 
671
      while (*p < sna_end)
 
672
        {
 
673
          err = asn1_get_tag(p, sna_end, &len, ASN1_CONTEXT_SPECIFIC |
 
674
                             ASN1_PRIMITIVE | 2);
 
675
          if (err)
 
676
            {
 
677
              /* not not a dNSName */
 
678
              if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
 
679
                {
 
680
                  svn_error_clear(err);
 
681
                  /* need to skip the tag and then find the length to
 
682
                   * skip to ignore this SNA entry. */
 
683
                  (*p)++;
 
684
                  SVN_ERR(asn1_get_len(p, sna_end, &len));
 
685
                  *p += len;
 
686
                  continue;
 
687
                }
 
688
 
 
689
              return svn_error_trace(err);
 
690
            }
 
691
          else
 
692
            {
 
693
              /* We found a dNSName entry */
 
694
              x509_buf *dnsname = apr_palloc(dnsnames->pool,
 
695
                                             sizeof(x509_buf));
 
696
              dnsname->tag = ASN1_IA5_STRING; /* implicit based on dNSName */
 
697
              dnsname->len = len;
 
698
              dnsname->p = *p;
 
699
              APR_ARRAY_PUSH(dnsnames, x509_buf *) = dnsname;
 
700
            }
 
701
 
 
702
          *p += len;
 
703
        }
 
704
 
 
705
    }
 
706
 
 
707
  return SVN_NO_ERROR;
 
708
}
 
709
 
 
710
/* Escape all non-ascii or control characters similar to
 
711
 * svn_xml_fuzzy_escape() and svn_utf_cstring_from_utf8_fuzzy().
 
712
 * All of the encoding formats somewhat overlap with ascii (BMPString
 
713
 * and UniversalString are actually always wider so you'll end up
 
714
 * with a bunch of escaped nul bytes, but ideally we don't get here
 
715
 * for those).  The result is always a nul-terminated C string. */
 
716
static const char *
 
717
fuzzy_escape(const svn_string_t *src, apr_pool_t *result_pool)
 
718
{
 
719
  const char *end = src->data + src->len;
 
720
  const char *p = src->data, *q;
 
721
  svn_stringbuf_t *outstr;
 
722
  char escaped_char[6]; /* ? \ u u u \0 */
 
723
 
 
724
  for (q = p; q < end; q++)
 
725
    {
 
726
      if (!svn_ctype_isascii(*q) || svn_ctype_iscntrl(*q))
 
727
        break;
 
728
    }
 
729
 
 
730
  if (q == end)
 
731
    return src->data;
 
732
 
 
733
  outstr = svn_stringbuf_create_empty(result_pool);
 
734
  while (1)
 
735
    {
 
736
      q = p;
 
737
 
 
738
      /* Traverse till either unsafe character or eos. */
 
739
      while (q < end && svn_ctype_isascii(*q) && !svn_ctype_iscntrl(*q))
 
740
        q++;
 
741
 
 
742
      /* copy chunk before marker */
 
743
      svn_stringbuf_appendbytes(outstr, p, q - p);
 
744
 
 
745
      if (q == end)
 
746
        break;
 
747
 
 
748
      apr_snprintf(escaped_char, sizeof(escaped_char), "?\\%03u",
 
749
                   (unsigned char) *q);
 
750
      svn_stringbuf_appendcstr(outstr, escaped_char);
 
751
 
 
752
      p = q + 1;
 
753
    }
 
754
 
 
755
  return outstr->data;
 
756
}
 
757
 
 
758
/* Escape only NUL characters from a string that is presumed to
 
759
 * be UTF-8 encoded and return a nul-terminated C string. */
 
760
static const char *
 
761
nul_escape(const svn_string_t *src, apr_pool_t *result_pool)
 
762
{
 
763
  const char *end = src->data + src->len;
 
764
  const char *p = src->data, *q;
 
765
  svn_stringbuf_t *outstr;
 
766
 
 
767
  for (q = p; q < end; q++)
 
768
    {
 
769
      if (*q == '\0')
 
770
        break;
 
771
    }
 
772
 
 
773
  if (q == end)
 
774
    return src->data;
 
775
 
 
776
  outstr = svn_stringbuf_create_empty(result_pool);
 
777
  while (1)
 
778
    {
 
779
      q = p;
 
780
 
 
781
      /* Traverse till either unsafe character or eos. */
 
782
      while (q < end && *q != '\0')
 
783
        q++;
 
784
 
 
785
      /* copy chunk before marker */
 
786
      svn_stringbuf_appendbytes(outstr, p, q - p);
 
787
 
 
788
      if (q == end)
 
789
        break;
 
790
 
 
791
      svn_stringbuf_appendcstr(outstr, "?\\000");
 
792
 
 
793
      p = q + 1;
 
794
    }
 
795
 
 
796
  return outstr->data;
 
797
}
 
798
 
 
799
 
 
800
/* Convert an ISO-8859-1 (Latin-1) string to UTF-8.
 
801
   ISO-8859-1 is a strict subset of Unicode. */
 
802
static svn_error_t *
 
803
latin1_to_utf8(const svn_string_t **result, const svn_string_t *src,
 
804
               apr_pool_t *result_pool)
 
805
{
 
806
  apr_int32_t *ucs4buf;
 
807
  svn_membuf_t resultbuf;
 
808
  apr_size_t length;
 
809
  apr_size_t i;
 
810
  svn_string_t *res;
 
811
 
 
812
  ucs4buf = apr_palloc(result_pool, src->len * sizeof(*ucs4buf));
 
813
  for (i = 0; i < src->len; ++i)
 
814
    ucs4buf[i] = (unsigned char)(src->data[i]);
 
815
 
 
816
  svn_membuf__create(&resultbuf, 2 * src->len, result_pool);
 
817
  SVN_ERR(svn_utf__encode_ucs4_string(
 
818
              &resultbuf, ucs4buf, src->len, &length));
 
819
 
 
820
  res = apr_palloc(result_pool, sizeof(*res));
 
821
  res->data = resultbuf.data;
 
822
  res->len = length;
 
823
  *result = res;
 
824
  return SVN_NO_ERROR;
 
825
}
 
826
 
 
827
/* Make a best effort to convert a X.509 name to a UTF-8 encoded
 
828
 * string and return it.  If we can't properly convert just do a
 
829
 * fuzzy conversion so we have something to display. */
 
830
static const char *
 
831
x509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool)
 
832
{
 
833
  const svn_string_t *src_string;
 
834
  const svn_string_t *utf8_string;
 
835
  svn_error_t *err;
 
836
 
 
837
  src_string = svn_string_ncreate((const char *)name->val.p,
 
838
                                  name->val.len,
 
839
                                  result_pool);
 
840
  switch (name->val.tag)
 
841
    {
 
842
    case ASN1_UTF8_STRING:
 
843
      if (svn_utf__is_valid(src_string->data, src_string->len))
 
844
        return nul_escape(src_string, result_pool);
 
845
      else
 
846
        /* not a valid UTF-8 string, who knows what it is,
 
847
         * so run it through the fuzzy_escape code.  */
 
848
        return fuzzy_escape(src_string, result_pool);
 
849
      break;
 
850
 
 
851
      /* Both BMP and UNIVERSAL should always be in Big Endian (aka
 
852
       * network byte order).  But rumor has it that there are certs
 
853
       * out there with other endianess and even Byte Order Marks.
 
854
       * If we actually run into these, we might need to do something
 
855
       * about it. */
 
856
 
 
857
    case ASN1_BMP_STRING:
 
858
      if (0 != src_string->len % sizeof(apr_uint16_t))
 
859
          return fuzzy_escape(src_string, result_pool);
 
860
      err = svn_utf__utf16_to_utf8(&utf8_string,
 
861
                                   (const void*)(src_string->data),
 
862
                                   src_string->len / sizeof(apr_uint16_t),
 
863
                                   TRUE, result_pool, result_pool);
 
864
      break;
 
865
 
 
866
    case ASN1_UNIVERSAL_STRING:
 
867
      if (0 != src_string->len % sizeof(apr_int32_t))
 
868
          return fuzzy_escape(src_string, result_pool);
 
869
      err = svn_utf__utf32_to_utf8(&utf8_string,
 
870
                                   (const void*)(src_string->data),
 
871
                                   src_string->len / sizeof(apr_int32_t),
 
872
                                   TRUE, result_pool, result_pool);
 
873
      break;
 
874
 
 
875
      /* Despite what all the IETF, ISO, ITU bits say everything out
 
876
       * on the Internet that I can find treats this as ISO-8859-1.
 
877
       * Even the name is misleading, it's not actually T.61.  All the
 
878
       * gory details can be found in the Character Sets section of:
 
879
       * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
 
880
       */
 
881
    case ASN1_T61_STRING:
 
882
      err = latin1_to_utf8(&utf8_string, src_string, result_pool);
 
883
      break;
 
884
 
 
885
      /* This leaves two types out there in the wild.  PrintableString,
 
886
       * which is just a subset of ASCII and IA5 which is ASCII (though
 
887
       * 0x24 '$' and 0x23 '#' may be defined with differnet symbols
 
888
       * depending on the location, in practice it seems everyone just
 
889
       * treats it as ASCII).  Since these are just ASCII run through
 
890
       * the fuzzy_escape code to deal with anything that isn't actually
 
891
       * ASCII.  There shouldn't be any other types here but if we find
 
892
       * a cert with some other encoding, the best we can do is the
 
893
       * fuzzy_escape().  Note: Technically IA5 isn't valid in this
 
894
       * context, however in the real world it may pop up. */
 
895
    default:
 
896
      return fuzzy_escape(src_string, result_pool);
 
897
    }
 
898
 
 
899
  if (err)
 
900
    {
 
901
      svn_error_clear(err);
 
902
      return fuzzy_escape(src_string, result_pool);
 
903
    }
 
904
 
 
905
  return nul_escape(utf8_string, result_pool);
 
906
}
 
907
 
 
908
static svn_error_t *
 
909
x509_name_to_certinfo(apr_array_header_t **result,
 
910
                      const x509_name *dn,
 
911
                      apr_pool_t *scratch_pool,
 
912
                      apr_pool_t *result_pool)
 
913
{
 
914
  const x509_name *name = dn;
 
915
 
 
916
  *result = apr_array_make(result_pool, 6, sizeof(svn_x509_name_attr_t *));
 
917
 
 
918
  while (name != NULL) {
 
919
    svn_x509_name_attr_t *attr = apr_palloc(result_pool, sizeof(svn_x509_name_attr_t));
 
920
 
 
921
    attr->oid_len = name->oid.len;
 
922
    attr->oid = apr_palloc(result_pool, attr->oid_len);
 
923
    memcpy(attr->oid, name->oid.p, attr->oid_len);
 
924
    attr->utf8_value = x509name_to_utf8_string(name, result_pool);
 
925
    if (!attr->utf8_value)
 
926
      /* this should never happen */
 
927
      attr->utf8_value = apr_pstrdup(result_pool, "??");
 
928
    APR_ARRAY_PUSH(*result, const svn_x509_name_attr_t *) = attr;
 
929
 
 
930
    name = name->next;
 
931
  }
 
932
 
 
933
  return SVN_NO_ERROR;
 
934
}
 
935
 
 
936
static svn_boolean_t
 
937
is_hostname(const char *str)
 
938
{
 
939
  apr_size_t i, len = strlen(str);
 
940
 
 
941
  for (i = 0; i < len; i++)
 
942
    {
 
943
      char c = str[i];
 
944
 
 
945
      /* '-' is only legal when not at the start or end of a label */
 
946
      if (c == '-')
 
947
        {
 
948
          if (i + 1 != len)
 
949
            {
 
950
              if (str[i + 1] == '.')
 
951
                return FALSE; /* '-' preceeds a '.' */
 
952
            }
 
953
          else
 
954
            return FALSE; /* '-' is at end of string */
 
955
 
 
956
          /* determine the previous character. */
 
957
          if (i == 0)
 
958
            return FALSE; /* '-' is at start of string */
 
959
          else
 
960
            if (str[i - 1] == '.')
 
961
              return FALSE; /* '-' follows a '.' */
 
962
        }
 
963
      else if (c != '*' && c != '.' && !svn_ctype_isalnum(c))
 
964
        return FALSE; /* some character not allowed */
 
965
    }
 
966
 
 
967
  return TRUE;
 
968
}
 
969
 
 
970
static const char *
 
971
x509parse_get_cn(apr_array_header_t *subject)
 
972
{
 
973
  int i;
 
974
 
 
975
  for (i = 0; i < subject->nelts; ++i)
 
976
    {
 
977
      const svn_x509_name_attr_t *attr = APR_ARRAY_IDX(subject, i, const svn_x509_name_attr_t *);
 
978
      if (equal(attr->oid, attr->oid_len,
 
979
                SVN_X509_OID_COMMON_NAME, sizeof(SVN_X509_OID_COMMON_NAME) - 1))
 
980
        return attr->utf8_value;
 
981
    }
 
982
 
 
983
  return NULL;
 
984
}
 
985
 
 
986
 
 
987
static void
 
988
x509parse_get_hostnames(svn_x509_certinfo_t *ci, x509_cert *crt,
 
989
                        apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 
990
{
 
991
  ci->hostnames = NULL;
 
992
 
 
993
  if (crt->dnsnames->nelts > 0)
 
994
    {
 
995
      int i;
 
996
 
 
997
      ci->hostnames = apr_array_make(result_pool, crt->dnsnames->nelts,
 
998
                                     sizeof(const char*));
 
999
 
 
1000
      /* Subject Alt Names take priority */
 
1001
      for (i = 0; i < crt->dnsnames->nelts; i++)
 
1002
        {
 
1003
          x509_buf *dnsname = APR_ARRAY_IDX(crt->dnsnames, i, x509_buf *);
 
1004
          const svn_string_t *temp = svn_string_ncreate((const char *)dnsname->p,
 
1005
                                                        dnsname->len,
 
1006
                                                        scratch_pool);
 
1007
 
 
1008
          APR_ARRAY_PUSH(ci->hostnames, const char*)
 
1009
            = fuzzy_escape(temp, result_pool);
 
1010
        }
 
1011
    }
 
1012
  else
 
1013
    {
 
1014
      /* no SAN then get the hostname from the CommonName on the cert */
 
1015
      const char *utf8_value;
 
1016
 
 
1017
      utf8_value = x509parse_get_cn(ci->subject);
 
1018
 
 
1019
      if (utf8_value && is_hostname(utf8_value))
 
1020
        {
 
1021
          ci->hostnames = apr_array_make(result_pool, 1, sizeof(const char*));
 
1022
          APR_ARRAY_PUSH(ci->hostnames, const char*) = utf8_value;
 
1023
        }
 
1024
    }
 
1025
}
 
1026
 
 
1027
/*
 
1028
 * Parse one certificate.
 
1029
 */
 
1030
svn_error_t *
 
1031
svn_x509_parse_cert(svn_x509_certinfo_t **certinfo,
 
1032
                    const char *buf,
 
1033
                    apr_size_t buflen,
 
1034
                    apr_pool_t *result_pool,
 
1035
                    apr_pool_t *scratch_pool)
 
1036
{
 
1037
  svn_error_t *err;
 
1038
  ptrdiff_t len;
 
1039
  const unsigned char *p;
 
1040
  const unsigned char *end;
 
1041
  x509_cert *crt;
 
1042
  svn_x509_certinfo_t *ci;
 
1043
 
 
1044
  crt = apr_pcalloc(scratch_pool, sizeof(*crt));
 
1045
  p = (const unsigned char *)buf;
 
1046
  len = buflen;
 
1047
  end = p + len;
 
1048
 
 
1049
  /*
 
1050
   * Certificate  ::=      SEQUENCE  {
 
1051
   *              tbsCertificate           TBSCertificate,
 
1052
   *              signatureAlgorithm       AlgorithmIdentifier,
 
1053
   *              signatureValue           BIT STRING      }
 
1054
   */
 
1055
  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
1056
  if (err)
 
1057
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1058
 
 
1059
  if (len != (end - p))
 
1060
    {
 
1061
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
1062
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1063
    }
 
1064
 
 
1065
  /*
 
1066
   * TBSCertificate  ::=  SEQUENCE  {
 
1067
   */
 
1068
  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
1069
  if (err)
 
1070
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1071
 
 
1072
  end = p + len;
 
1073
 
 
1074
  /*
 
1075
   * Version      ::=      INTEGER  {      v1(0), v2(1), v3(2)  }
 
1076
   *
 
1077
   * CertificateSerialNumber      ::=      INTEGER
 
1078
   *
 
1079
   * signature                    AlgorithmIdentifier
 
1080
   */
 
1081
  SVN_ERR(x509_get_version(&p, end, &crt->version));
 
1082
  SVN_ERR(x509_get_serial(&p, end, &crt->serial));
 
1083
  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid1));
 
1084
 
 
1085
  crt->version++;
 
1086
 
 
1087
  if (crt->version > 3)
 
1088
    return svn_error_create(SVN_ERR_X509_CERT_UNKNOWN_VERSION, NULL, NULL);
 
1089
 
 
1090
  /*
 
1091
   * issuer                               Name
 
1092
   */
 
1093
  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
1094
  if (err)
 
1095
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1096
 
 
1097
  SVN_ERR(x509_get_name(&p, p + len, &crt->issuer, scratch_pool));
 
1098
 
 
1099
  /*
 
1100
   * Validity ::= SEQUENCE {
 
1101
   *              notBefore          Time,
 
1102
   *              notAfter           Time }
 
1103
   *
 
1104
   */
 
1105
  SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end,
 
1106
                         scratch_pool));
 
1107
 
 
1108
  /*
 
1109
   * subject                              Name
 
1110
   */
 
1111
  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
1112
  if (err)
 
1113
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1114
 
 
1115
  SVN_ERR(x509_get_name(&p, p + len, &crt->subject, scratch_pool));
 
1116
 
 
1117
  /*
 
1118
   * SubjectPublicKeyInfo  ::=  SEQUENCE
 
1119
   *              algorithm                        AlgorithmIdentifier,
 
1120
   *              subjectPublicKey         BIT STRING      }
 
1121
   */
 
1122
  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
 
1123
  if (err)
 
1124
    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1125
 
 
1126
  /* Skip pubkey. */
 
1127
  p += len;
 
1128
 
 
1129
  /*
 
1130
   *      issuerUniqueID  [1]      IMPLICIT UniqueIdentifier OPTIONAL,
 
1131
   *                                               -- If present, version shall be v2 or v3
 
1132
   *      subjectUniqueID [2]      IMPLICIT UniqueIdentifier OPTIONAL,
 
1133
   *                                               -- If present, version shall be v2 or v3
 
1134
   *      extensions              [3]      EXPLICIT Extensions OPTIONAL
 
1135
   *                                               -- If present, version shall be v3
 
1136
   */
 
1137
  crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *));
 
1138
 
 
1139
  /* Try to parse issuerUniqueID, subjectUniqueID and extensions for *every*
 
1140
   * version (X.509 v1, v2 and v3), not just v2 or v3.  If they aren't present,
 
1141
   * we are fine, but we don't want to throw an error if they are.  v1 and v2
 
1142
   * certificates with the corresponding extra fields are ill-formed per RFC
 
1143
   * 5280 s. 4.1, but we suspect they could exist in the real world.  Other
 
1144
   * X.509 parsers (e.g., within OpenSSL or Microsoft CryptoAPI) aren't picky
 
1145
   * about these certificates, and we also allow them. */
 
1146
  SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1));
 
1147
  SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2));
 
1148
  SVN_ERR(x509_get_ext(crt->dnsnames, &p, end));
 
1149
 
 
1150
  if (p != end)
 
1151
    {
 
1152
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
1153
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1154
    }
 
1155
 
 
1156
  end = (const unsigned char*) buf + buflen;
 
1157
 
 
1158
  /*
 
1159
   *      signatureAlgorithm       AlgorithmIdentifier,
 
1160
   *      signatureValue           BIT STRING
 
1161
   */
 
1162
  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid2));
 
1163
 
 
1164
  if (!oids_equal(&crt->sig_oid1, &crt->sig_oid2))
 
1165
    return svn_error_create(SVN_ERR_X509_CERT_SIG_MISMATCH, NULL, NULL);
 
1166
 
 
1167
  SVN_ERR(x509_get_sig(&p, end, &crt->sig));
 
1168
 
 
1169
  if (p != end)
 
1170
    {
 
1171
      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
 
1172
      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
 
1173
    }
 
1174
 
 
1175
  ci = apr_pcalloc(result_pool, sizeof(*ci));
 
1176
 
 
1177
  /* Get the subject name */
 
1178
  SVN_ERR(x509_name_to_certinfo(&ci->subject, &crt->subject,
 
1179
                                scratch_pool, result_pool));
 
1180
 
 
1181
  /* Get the issuer name */
 
1182
  SVN_ERR(x509_name_to_certinfo(&ci->issuer, &crt->issuer,
 
1183
                                scratch_pool, result_pool));
 
1184
 
 
1185
  /* Copy the validity range */
 
1186
  ci->valid_from = crt->valid_from;
 
1187
  ci->valid_to = crt->valid_to;
 
1188
 
 
1189
  /* Calculate the SHA1 digest of the certificate, otherwise known as
 
1190
    the fingerprint */
 
1191
  SVN_ERR(svn_checksum(&ci->digest, svn_checksum_sha1, buf, buflen,
 
1192
                       result_pool));
 
1193
 
 
1194
  /* Construct the array of host names */
 
1195
  x509parse_get_hostnames(ci, crt, result_pool, scratch_pool);
 
1196
 
 
1197
  *certinfo = ci;
 
1198
  return SVN_NO_ERROR;
 
1199
}
 
1200