1289177Speter/*
2289177Speter *  X.509 certificate and private key decoding
3289177Speter *
4289177Speter *  Based on XySSL: Copyright (C) 2006-2008   Christophe Devine
5289177Speter *
6289177Speter *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
7289177Speter *
8289177Speter *  All rights reserved.
9289177Speter *
10289177Speter *  Redistribution and use in source and binary forms, with or without
11289177Speter *  modification, are permitted provided that the following conditions
12289177Speter *  are met:
13289177Speter *
14289177Speter *    * Redistributions of source code must retain the above copyright
15289177Speter *    notice, this list of conditions and the following disclaimer.
16289177Speter *    * Redistributions in binary form must reproduce the above copyright
17289177Speter *    notice, this list of conditions and the following disclaimer in the
18289177Speter *    documentation and/or other materials provided with the distribution.
19289177Speter *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
20289177Speter *    may be used to endorse or promote products derived from this software
21289177Speter *    without specific prior written permission.
22289177Speter *
23289177Speter *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24289177Speter *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25289177Speter *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26289177Speter *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27289177Speter *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28289177Speter *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29289177Speter *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30289177Speter *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31289177Speter *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32289177Speter *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33289177Speter *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34289177Speter */
35289177Speter/*
36289177Speter *  The ITU-T X.509 standard defines a certificate format for PKI.
37289177Speter *
38289177Speter *  http://www.ietf.org/rfc/rfc5280.txt
39289177Speter *  http://www.ietf.org/rfc/rfc3279.txt
40289177Speter *  http://www.ietf.org/rfc/rfc6818.txt
41289177Speter *
42289177Speter *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
43289177Speter *
44289177Speter *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
45289177Speter *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
46289177Speter */
47289177Speter
48289177Speter#include <apr_pools.h>
49289177Speter#include <apr_tables.h>
50289177Speter#include "svn_hash.h"
51289177Speter#include "svn_string.h"
52289177Speter#include "svn_time.h"
53289177Speter#include "svn_checksum.h"
54289177Speter#include "svn_utf.h"
55289177Speter#include "svn_ctype.h"
56289177Speter#include "private/svn_utf_private.h"
57289177Speter#include "private/svn_string_private.h"
58289177Speter
59289177Speter#include "x509.h"
60289177Speter
61289177Speter#include <string.h>
62289177Speter#include <stdio.h>
63289177Speter
64289177Speter/*
65289177Speter * ASN.1 DER decoding routines
66289177Speter */
67289177Speterstatic svn_error_t *
68289177Speterasn1_get_len(const unsigned char **p, const unsigned char *end,
69289177Speter             ptrdiff_t *len)
70289177Speter{
71289177Speter  if ((end - *p) < 1)
72289177Speter    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
73289177Speter
74289177Speter  if ((**p & 0x80) == 0)
75289177Speter    *len = *(*p)++;
76289177Speter  else
77289177Speter    switch (**p & 0x7F)
78289177Speter      {
79289177Speter      case 1:
80289177Speter        if ((end - *p) < 2)
81289177Speter          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
82289177Speter
83289177Speter        *len = (*p)[1];
84289177Speter        (*p) += 2;
85289177Speter        break;
86289177Speter
87289177Speter      case 2:
88289177Speter        if ((end - *p) < 3)
89289177Speter          return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
90289177Speter
91289177Speter        *len = ((*p)[1] << 8) | (*p)[2];
92289177Speter        (*p) += 3;
93289177Speter        break;
94289177Speter
95289177Speter      default:
96289177Speter        return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
97289177Speter        break;
98289177Speter      }
99289177Speter
100289177Speter  if (*len > (end - *p))
101289177Speter    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
102289177Speter
103289177Speter  return SVN_NO_ERROR;
104289177Speter}
105289177Speter
106289177Speterstatic svn_error_t *
107289177Speterasn1_get_tag(const unsigned char **p,
108289177Speter             const unsigned char *end, ptrdiff_t *len, int tag)
109289177Speter{
110289177Speter  if ((end - *p) < 1)
111289177Speter    return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
112289177Speter
113289177Speter  if (**p != tag)
114289177Speter    return svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
115289177Speter
116289177Speter  (*p)++;
117289177Speter
118289177Speter  return svn_error_trace(asn1_get_len(p, end, len));
119289177Speter}
120289177Speter
121289177Speterstatic svn_error_t *
122289177Speterasn1_get_int(const unsigned char **p, const unsigned char *end, int *val)
123289177Speter{
124289177Speter  ptrdiff_t len;
125289177Speter
126289177Speter  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_INTEGER));
127289177Speter
128289177Speter  /* Reject bit patterns that would overflow the output and those that
129289177Speter     represent negative values. */
130289177Speter  if (len > (int)sizeof(int) || (**p & 0x80) != 0)
131289177Speter    return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL);
132289177Speter
133289177Speter  *val = 0;
134289177Speter
135289177Speter  while (len-- > 0) {
136289177Speter    /* This would be undefined for bit-patterns of negative values. */
137289177Speter    *val = (*val << 8) | **p;
138289177Speter    (*p)++;
139289177Speter  }
140289177Speter
141289177Speter  return SVN_NO_ERROR;
142289177Speter}
143289177Speter
144289177Speterstatic svn_boolean_t
145289177Speterequal(const void *left, apr_size_t left_len,
146289177Speter      const void *right, apr_size_t right_len)
147289177Speter{
148289177Speter  if (left_len != right_len)
149289177Speter    return FALSE;
150289177Speter
151289177Speter  return memcmp(left, right, right_len) == 0;
152289177Speter}
153289177Speter
154289177Speterstatic svn_boolean_t
155289177Speteroids_equal(x509_buf *left, x509_buf *right)
156289177Speter{
157289177Speter  return equal(left->p, left->len,
158289177Speter               right->p, right->len);
159289177Speter}
160289177Speter
161289177Speter/*
162289177Speter *  Version   ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
163289177Speter */
164289177Speterstatic svn_error_t *
165289177Speterx509_get_version(const unsigned char **p, const unsigned char *end, int *ver)
166289177Speter{
167289177Speter  svn_error_t *err;
168289177Speter  ptrdiff_t len;
169289177Speter
170289177Speter  /*
171289177Speter   * As defined in the Basic Certificate fields:
172289177Speter   *   version         [0]  EXPLICIT Version DEFAULT v1,
173289177Speter   * the version is the context specific tag 0.
174289177Speter   */
175289177Speter  err = asn1_get_tag(p, end, &len,
176289177Speter                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0);
177289177Speter  if (err)
178289177Speter    {
179289177Speter      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
180289177Speter        {
181289177Speter          svn_error_clear(err);
182289177Speter          *ver = 0;
183289177Speter          return SVN_NO_ERROR;
184289177Speter        }
185289177Speter
186289177Speter      return svn_error_trace(err);
187289177Speter    }
188289177Speter
189289177Speter  end = *p + len;
190289177Speter
191289177Speter  err = asn1_get_int(p, end, ver);
192289177Speter  if (err)
193289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
194289177Speter
195289177Speter  if (*p != end)
196289177Speter    {
197289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
198289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL);
199289177Speter    }
200289177Speter
201289177Speter  return SVN_NO_ERROR;
202289177Speter}
203289177Speter
204289177Speter/*
205289177Speter *  CertificateSerialNumber   ::=  INTEGER
206289177Speter */
207289177Speterstatic svn_error_t *
208289177Speterx509_get_serial(const unsigned char **p,
209289177Speter                const unsigned char *end, x509_buf * serial)
210289177Speter{
211289177Speter  svn_error_t *err;
212289177Speter
213289177Speter  if ((end - *p) < 1)
214289177Speter    {
215289177Speter      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
216289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
217289177Speter    }
218289177Speter
219289177Speter  if (**p != (ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2) &&
220289177Speter      **p != ASN1_INTEGER)
221289177Speter    {
222289177Speter      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
223289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
224289177Speter    }
225289177Speter
226289177Speter  serial->tag = *(*p)++;
227289177Speter
228289177Speter  err = asn1_get_len(p, end, &serial->len);
229289177Speter  if (err)
230289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL);
231289177Speter
232289177Speter  serial->p = *p;
233289177Speter  *p += serial->len;
234289177Speter
235289177Speter  return SVN_NO_ERROR;
236289177Speter}
237289177Speter
238289177Speter/*
239289177Speter *  AlgorithmIdentifier   ::=  SEQUENCE  {
240289177Speter *     algorithm         OBJECT IDENTIFIER,
241289177Speter *     parameters        ANY DEFINED BY algorithm OPTIONAL  }
242289177Speter */
243289177Speterstatic svn_error_t *
244289177Speterx509_get_alg(const unsigned char **p, const unsigned char *end, x509_buf * alg)
245289177Speter{
246289177Speter  svn_error_t *err;
247289177Speter  ptrdiff_t len;
248289177Speter
249289177Speter  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
250289177Speter  if (err)
251289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
252289177Speter
253289177Speter  end = *p + len;
254289177Speter  alg->tag = **p;
255289177Speter
256289177Speter  err = asn1_get_tag(p, end, &alg->len, ASN1_OID);
257289177Speter  if (err)
258289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
259289177Speter
260289177Speter  alg->p = *p;
261289177Speter  *p += alg->len;
262289177Speter
263289177Speter  if (*p == end)
264289177Speter    return SVN_NO_ERROR;
265289177Speter
266289177Speter  /*
267289177Speter   * assume the algorithm parameters must be NULL
268289177Speter   */
269289177Speter  err = asn1_get_tag(p, end, &len, ASN1_NULL);
270289177Speter  if (err)
271289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
272289177Speter
273289177Speter  if (*p != end)
274289177Speter    {
275289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
276289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL);
277289177Speter    }
278289177Speter
279289177Speter  return SVN_NO_ERROR;
280289177Speter}
281289177Speter
282289177Speter/*
283289177Speter *  AttributeTypeAndValue ::= SEQUENCE {
284289177Speter *    type     AttributeType,
285289177Speter *    value     AttributeValue }
286289177Speter *
287289177Speter *  AttributeType ::= OBJECT IDENTIFIER
288289177Speter *
289289177Speter *  AttributeValue ::= ANY DEFINED BY AttributeType
290289177Speter */
291289177Speterstatic svn_error_t *
292289177Speterx509_get_attribute(const unsigned char **p, const unsigned char *end,
293289177Speter                   x509_name *cur, apr_pool_t *result_pool)
294289177Speter{
295289177Speter  svn_error_t *err;
296289177Speter  ptrdiff_t len;
297289177Speter  x509_buf *oid;
298289177Speter  x509_buf *val;
299289177Speter
300289177Speter  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
301289177Speter  if (err)
302289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
303289177Speter
304289177Speter  end = *p + len;
305289177Speter
306289177Speter  oid = &cur->oid;
307289177Speter
308289177Speter  err = asn1_get_tag(p, end, &oid->len, ASN1_OID);
309289177Speter  if (err)
310289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
311289177Speter
312289177Speter  oid->tag = ASN1_OID;
313289177Speter  oid->p = *p;
314289177Speter  *p += oid->len;
315289177Speter
316289177Speter  if ((end - *p) < 1)
317289177Speter    {
318289177Speter      err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL);
319289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
320289177Speter    }
321289177Speter
322289177Speter  if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
323289177Speter      **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
324289177Speter      **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING)
325289177Speter    {
326289177Speter      err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL);
327289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
328289177Speter    }
329289177Speter
330289177Speter  val = &cur->val;
331289177Speter  val->tag = *(*p)++;
332289177Speter
333289177Speter  err = asn1_get_len(p, end, &val->len);
334289177Speter  if (err)
335289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
336289177Speter
337289177Speter  val->p = *p;
338289177Speter  *p += val->len;
339289177Speter
340289177Speter  cur->next = NULL;
341289177Speter
342289177Speter  if (*p != end)
343289177Speter    {
344289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
345289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
346289177Speter    }
347289177Speter
348289177Speter  return SVN_NO_ERROR;
349289177Speter}
350289177Speter
351289177Speter/*
352289177Speter *   RelativeDistinguishedName ::=
353289177Speter *   SET SIZE (1..MAX) OF AttributeTypeAndValue
354289177Speter */
355289177Speterstatic svn_error_t *
356289177Speterx509_get_name(const unsigned char **p, const unsigned char *name_end,
357289177Speter              x509_name *name, apr_pool_t *result_pool)
358289177Speter{
359289177Speter  svn_error_t *err;
360289177Speter  ptrdiff_t len;
361289177Speter  const unsigned char *set_end;
362289177Speter  x509_name *cur = NULL;
363289177Speter
364289177Speter  err = asn1_get_tag(p, name_end, &len, ASN1_CONSTRUCTED | ASN1_SET);
365289177Speter  if (err)
366289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL);
367289177Speter
368289177Speter  set_end = *p + len;
369289177Speter
370289177Speter  /*
371289177Speter   * iterate until the end of the SET is reached
372289177Speter   */
373289177Speter  while (*p < set_end)
374289177Speter    {
375289177Speter      if (!cur)
376289177Speter        {
377289177Speter          cur = name;
378289177Speter        }
379289177Speter      else
380289177Speter        {
381289177Speter          cur->next = apr_palloc(result_pool, sizeof(x509_name));
382289177Speter          cur = cur->next;
383289177Speter        }
384289177Speter      SVN_ERR(x509_get_attribute(p, set_end, cur, result_pool));
385289177Speter    }
386289177Speter
387289177Speter  /*
388289177Speter   * recurse until end of SEQUENCE (name) is reached
389289177Speter   */
390289177Speter  if (*p == name_end)
391289177Speter    return SVN_NO_ERROR;
392289177Speter
393289177Speter  cur->next = apr_palloc(result_pool, sizeof(x509_name));
394289177Speter
395289177Speter  return svn_error_trace(x509_get_name(p, name_end, cur->next, result_pool));
396289177Speter}
397289177Speter
398289177Speter/* Retrieve the date from the X.509 cert data between *P and END in either
399289177Speter * UTCTime or GeneralizedTime format (as defined in RFC 5280 s. 4.1.2.5.1 and
400289177Speter * 4.1.2.5.2 respectively) and place the result in WHEN using  SCRATCH_POOL
401289177Speter * for temporary allocations. */
402289177Speterstatic svn_error_t *
403289177Speterx509_get_date(apr_time_t *when,
404289177Speter              const unsigned char **p,
405289177Speter              const unsigned char *end,
406289177Speter              apr_pool_t *scratch_pool)
407289177Speter{
408289177Speter  svn_error_t *err;
409289177Speter  apr_status_t ret;
410289177Speter  int tag;
411289177Speter  ptrdiff_t len;
412289177Speter  char *date;
413289177Speter  apr_time_exp_t xt = { 0 };
414289177Speter  char tz;
415289177Speter
416289177Speter  err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME);
417289177Speter  if (err && err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
418289177Speter    {
419289177Speter      svn_error_clear(err);
420289177Speter      err = asn1_get_tag(p, end, &len, ASN1_GENERALIZED_TIME);
421289177Speter      tag = ASN1_GENERALIZED_TIME;
422289177Speter    }
423289177Speter  else
424289177Speter    {
425289177Speter      tag = ASN1_UTC_TIME;
426289177Speter    }
427289177Speter  if (err)
428289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
429289177Speter
430289177Speter  date = apr_pstrndup(scratch_pool, (const char *) *p, len);
431289177Speter  switch (tag)
432289177Speter    {
433289177Speter    case ASN1_UTC_TIME:
434289177Speter      if (sscanf(date, "%2d%2d%2d%2d%2d%2d%c",
435289177Speter                 &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
436289177Speter                 &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
437289177Speter        return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
438289177Speter
439289177Speter      /* UTCTime only provides a 2 digit year.  X.509 specifies that years
440289177Speter       * greater than or equal to 50 must be interpreted as 19YY and years
441289177Speter       * less than 50 be interpreted as 20YY.  This format is not used for
442289177Speter       * years greater than 2049. apr_time_exp_t wants years as the number
443289177Speter       * of years since 1900, so don't convert to 4 digits here. */
444289177Speter      xt.tm_year += 100 * (xt.tm_year < 50);
445289177Speter      break;
446289177Speter
447289177Speter    case ASN1_GENERALIZED_TIME:
448289177Speter      if (sscanf(date, "%4d%2d%2d%2d%2d%2d%c",
449289177Speter                 &xt.tm_year, &xt.tm_mon, &xt.tm_mday,
450289177Speter                 &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6)
451289177Speter        return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
452289177Speter
453289177Speter      /* GeneralizedTime has the full 4 digit year.  But apr_time_exp_t
454289177Speter       * wants years as the number of years since 1900. */
455289177Speter      xt.tm_year -= 1900;
456289177Speter      break;
457289177Speter
458289177Speter    default:
459289177Speter      /* shouldn't ever get here because we should error out above in the
460289177Speter       * asn1_get_tag() bits but doesn't hurt to be extra paranoid. */
461289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
462289177Speter      break;
463289177Speter    }
464289177Speter
465289177Speter  /* check that the timezone is GMT
466289177Speter   * ASN.1 allows for the timezone to be specified but X.509 says it must
467289177Speter   * always be GMT.  A little bit of extra paranoia here seems like a good
468289177Speter   * idea. */
469289177Speter  if (tz != 'Z')
470289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL);
471289177Speter
472289177Speter  /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */
473289177Speter  xt.tm_mon -= 1;
474289177Speter
475289177Speter  ret = apr_time_exp_gmt_get(when, &xt);
476289177Speter  if (ret)
477289177Speter    return svn_error_wrap_apr(ret, NULL);
478289177Speter
479289177Speter  *p += len;
480289177Speter
481289177Speter  return SVN_NO_ERROR;
482289177Speter}
483289177Speter
484289177Speter/*
485289177Speter *  Validity ::= SEQUENCE {
486289177Speter *     notBefore    Time,
487289177Speter *     notAfter    Time }
488289177Speter *
489289177Speter *  Time ::= CHOICE {
490289177Speter *     utcTime    UTCTime,
491289177Speter *     generalTime  GeneralizedTime }
492289177Speter */
493289177Speterstatic svn_error_t *
494289177Speterx509_get_dates(apr_time_t *from,
495289177Speter               apr_time_t *to,
496289177Speter               const unsigned char **p,
497289177Speter               const unsigned char *end,
498289177Speter               apr_pool_t *scratch_pool)
499289177Speter{
500289177Speter  svn_error_t *err;
501289177Speter  ptrdiff_t len;
502289177Speter
503289177Speter  err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
504289177Speter  if (err)
505289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
506289177Speter
507289177Speter  end = *p + len;
508289177Speter
509289177Speter  SVN_ERR(x509_get_date(from, p, end, scratch_pool));
510289177Speter
511289177Speter  SVN_ERR(x509_get_date(to, p, end, scratch_pool));
512289177Speter
513289177Speter  if (*p != end)
514289177Speter    {
515289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
516289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL);
517289177Speter    }
518289177Speter
519289177Speter  return SVN_NO_ERROR;
520289177Speter}
521289177Speter
522289177Speterstatic svn_error_t *
523289177Speterx509_get_sig(const unsigned char **p, const unsigned char *end, x509_buf * sig)
524289177Speter{
525289177Speter  svn_error_t *err;
526289177Speter  ptrdiff_t len;
527289177Speter
528289177Speter  err = asn1_get_tag(p, end, &len, ASN1_BIT_STRING);
529289177Speter  if (err)
530289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, err, NULL);
531289177Speter
532289177Speter  sig->tag = ASN1_BIT_STRING;
533289177Speter
534289177Speter  if (--len < 1 || *(*p)++ != 0)
535289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, NULL, NULL);
536289177Speter
537289177Speter  sig->len = len;
538289177Speter  sig->p = *p;
539289177Speter
540289177Speter  *p += len;
541289177Speter
542289177Speter  return SVN_NO_ERROR;
543289177Speter}
544289177Speter
545289177Speter/*
546289177Speter * X.509 v2/v3 unique identifier (not parsed)
547289177Speter */
548289177Speterstatic svn_error_t *
549289177Speterx509_get_uid(const unsigned char **p,
550289177Speter             const unsigned char *end, x509_buf * uid, int n)
551289177Speter{
552289177Speter  svn_error_t *err;
553289177Speter
554289177Speter  if (*p == end)
555289177Speter    return SVN_NO_ERROR;
556289177Speter
557289177Speter  err = asn1_get_tag(p, end, &uid->len,
558289177Speter                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n);
559289177Speter  if (err)
560289177Speter    {
561289177Speter      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
562289177Speter        {
563289177Speter          svn_error_clear(err);
564289177Speter          return SVN_NO_ERROR;
565289177Speter        }
566289177Speter
567289177Speter      return svn_error_trace(err);
568289177Speter    }
569289177Speter
570289177Speter  uid->tag = ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n;
571289177Speter  uid->p = *p;
572289177Speter  *p += uid->len;
573289177Speter
574289177Speter  return SVN_NO_ERROR;
575289177Speter}
576289177Speter
577289177Speter/*
578289177Speter * X.509 v3 extensions (not parsed)
579289177Speter */
580289177Speterstatic svn_error_t *
581289177Speterx509_get_ext(apr_array_header_t *dnsnames,
582289177Speter             const unsigned char **p,
583289177Speter             const unsigned char *end)
584289177Speter{
585289177Speter  svn_error_t *err;
586289177Speter  ptrdiff_t len;
587289177Speter
588289177Speter  if (*p == end)
589289177Speter    return SVN_NO_ERROR;
590289177Speter
591289177Speter  err = asn1_get_tag(p, end, &len,
592289177Speter                     ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3);
593289177Speter  if (err)
594289177Speter    {
595289177Speter      /* If there aren't extensions that's ok they aren't required */
596289177Speter      if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
597289177Speter        {
598289177Speter          svn_error_clear(err);
599289177Speter          return SVN_NO_ERROR;
600289177Speter        }
601289177Speter
602289177Speter      return svn_error_trace(err);
603289177Speter    }
604289177Speter
605289177Speter  end = *p + len;
606289177Speter
607289177Speter  SVN_ERR(asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE));
608289177Speter
609289177Speter  if (end != *p + len)
610289177Speter    {
611289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
612289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
613289177Speter    }
614289177Speter
615289177Speter  while (*p < end)
616289177Speter    {
617289177Speter      ptrdiff_t ext_len;
618289177Speter      const unsigned char *ext_start, *sna_end;
619289177Speter      err = asn1_get_tag(p, end, &ext_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
620289177Speter      if (err)
621289177Speter        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
622289177Speter                                NULL);
623289177Speter      ext_start = *p;
624289177Speter
625289177Speter      err = asn1_get_tag(p, end, &len, ASN1_OID);
626289177Speter      if (err)
627289177Speter        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
628289177Speter                                NULL);
629289177Speter
630289177Speter      /* skip all extensions except SubjectAltName */
631289177Speter      if (!equal(*p, len,
632289177Speter                 OID_SUBJECT_ALT_NAME, sizeof(OID_SUBJECT_ALT_NAME) - 1))
633289177Speter        {
634289177Speter          *p += ext_len - (*p - ext_start);
635289177Speter          continue;
636289177Speter        }
637289177Speter      *p += len;
638289177Speter
639289177Speter      err = asn1_get_tag(p, end, &len, ASN1_OCTET_STRING);
640289177Speter      if (err)
641289177Speter        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
642289177Speter                                NULL);
643289177Speter
644289177Speter      /*   SubjectAltName ::= GeneralNames
645289177Speter
646289177Speter           GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
647289177Speter
648289177Speter           GeneralName ::= CHOICE {
649289177Speter                other Name                      [0]     OtherName,
650289177Speter                rfc822Name                      [1]     IA5String,
651289177Speter                dNSName                         [2]     IA5String,
652289177Speter                x400Address                     [3]     ORAddress,
653289177Speter                directoryName                   [4]     Name,
654289177Speter                ediPartyName                    [5]     EDIPartyName,
655289177Speter                uniformResourceIdentifier       [6]     IA5String,
656289177Speter                iPAddress                       [7]     OCTET STRING,
657289177Speter                registeredID                    [8]     OBJECT IDENTIFIER } */
658289177Speter      sna_end = *p + len;
659289177Speter
660289177Speter      err = asn1_get_tag(p, sna_end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
661289177Speter      if (err)
662289177Speter        return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err,
663289177Speter                                NULL);
664289177Speter
665289177Speter      if (sna_end != *p + len)
666289177Speter        {
667289177Speter          err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
668289177Speter          return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL);
669289177Speter        }
670289177Speter
671289177Speter      while (*p < sna_end)
672289177Speter        {
673289177Speter          err = asn1_get_tag(p, sna_end, &len, ASN1_CONTEXT_SPECIFIC |
674289177Speter                             ASN1_PRIMITIVE | 2);
675289177Speter          if (err)
676289177Speter            {
677289177Speter              /* not not a dNSName */
678289177Speter              if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG)
679289177Speter                {
680289177Speter                  svn_error_clear(err);
681289177Speter                  /* need to skip the tag and then find the length to
682289177Speter                   * skip to ignore this SNA entry. */
683289177Speter                  (*p)++;
684289177Speter                  SVN_ERR(asn1_get_len(p, sna_end, &len));
685289177Speter                  *p += len;
686289177Speter                  continue;
687289177Speter                }
688289177Speter
689289177Speter              return svn_error_trace(err);
690289177Speter            }
691289177Speter          else
692289177Speter            {
693289177Speter              /* We found a dNSName entry */
694289177Speter              x509_buf *dnsname = apr_palloc(dnsnames->pool,
695289177Speter                                             sizeof(x509_buf));
696289177Speter              dnsname->tag = ASN1_IA5_STRING; /* implicit based on dNSName */
697289177Speter              dnsname->len = len;
698289177Speter              dnsname->p = *p;
699289177Speter              APR_ARRAY_PUSH(dnsnames, x509_buf *) = dnsname;
700289177Speter            }
701289177Speter
702289177Speter          *p += len;
703289177Speter        }
704289177Speter
705289177Speter    }
706289177Speter
707289177Speter  return SVN_NO_ERROR;
708289177Speter}
709289177Speter
710289177Speter/* Escape all non-ascii or control characters similar to
711289177Speter * svn_xml_fuzzy_escape() and svn_utf_cstring_from_utf8_fuzzy().
712289177Speter * All of the encoding formats somewhat overlap with ascii (BMPString
713289177Speter * and UniversalString are actually always wider so you'll end up
714289177Speter * with a bunch of escaped nul bytes, but ideally we don't get here
715289177Speter * for those).  The result is always a nul-terminated C string. */
716289177Speterstatic const char *
717289177Speterfuzzy_escape(const svn_string_t *src, apr_pool_t *result_pool)
718289177Speter{
719289177Speter  const char *end = src->data + src->len;
720289177Speter  const char *p = src->data, *q;
721289177Speter  svn_stringbuf_t *outstr;
722289177Speter  char escaped_char[6]; /* ? \ u u u \0 */
723289177Speter
724289177Speter  for (q = p; q < end; q++)
725289177Speter    {
726289177Speter      if (!svn_ctype_isascii(*q) || svn_ctype_iscntrl(*q))
727289177Speter        break;
728289177Speter    }
729289177Speter
730289177Speter  if (q == end)
731289177Speter    return src->data;
732289177Speter
733289177Speter  outstr = svn_stringbuf_create_empty(result_pool);
734289177Speter  while (1)
735289177Speter    {
736289177Speter      q = p;
737289177Speter
738289177Speter      /* Traverse till either unsafe character or eos. */
739289177Speter      while (q < end && svn_ctype_isascii(*q) && !svn_ctype_iscntrl(*q))
740289177Speter        q++;
741289177Speter
742289177Speter      /* copy chunk before marker */
743289177Speter      svn_stringbuf_appendbytes(outstr, p, q - p);
744289177Speter
745289177Speter      if (q == end)
746289177Speter        break;
747289177Speter
748289177Speter      apr_snprintf(escaped_char, sizeof(escaped_char), "?\\%03u",
749289177Speter                   (unsigned char) *q);
750289177Speter      svn_stringbuf_appendcstr(outstr, escaped_char);
751289177Speter
752289177Speter      p = q + 1;
753289177Speter    }
754289177Speter
755289177Speter  return outstr->data;
756289177Speter}
757289177Speter
758289177Speter/* Escape only NUL characters from a string that is presumed to
759289177Speter * be UTF-8 encoded and return a nul-terminated C string. */
760289177Speterstatic const char *
761289177Speternul_escape(const svn_string_t *src, apr_pool_t *result_pool)
762289177Speter{
763289177Speter  const char *end = src->data + src->len;
764289177Speter  const char *p = src->data, *q;
765289177Speter  svn_stringbuf_t *outstr;
766289177Speter
767289177Speter  for (q = p; q < end; q++)
768289177Speter    {
769289177Speter      if (*q == '\0')
770289177Speter        break;
771289177Speter    }
772289177Speter
773289177Speter  if (q == end)
774289177Speter    return src->data;
775289177Speter
776289177Speter  outstr = svn_stringbuf_create_empty(result_pool);
777289177Speter  while (1)
778289177Speter    {
779289177Speter      q = p;
780289177Speter
781289177Speter      /* Traverse till either unsafe character or eos. */
782289177Speter      while (q < end && *q != '\0')
783289177Speter        q++;
784289177Speter
785289177Speter      /* copy chunk before marker */
786289177Speter      svn_stringbuf_appendbytes(outstr, p, q - p);
787289177Speter
788289177Speter      if (q == end)
789289177Speter        break;
790289177Speter
791289177Speter      svn_stringbuf_appendcstr(outstr, "?\\000");
792289177Speter
793289177Speter      p = q + 1;
794289177Speter    }
795289177Speter
796289177Speter  return outstr->data;
797289177Speter}
798289177Speter
799289177Speter
800289177Speter/* Convert an ISO-8859-1 (Latin-1) string to UTF-8.
801289177Speter   ISO-8859-1 is a strict subset of Unicode. */
802289177Speterstatic svn_error_t *
803289177Speterlatin1_to_utf8(const svn_string_t **result, const svn_string_t *src,
804289177Speter               apr_pool_t *result_pool)
805289177Speter{
806289177Speter  apr_int32_t *ucs4buf;
807289177Speter  svn_membuf_t resultbuf;
808289177Speter  apr_size_t length;
809289177Speter  apr_size_t i;
810289177Speter  svn_string_t *res;
811289177Speter
812289177Speter  ucs4buf = apr_palloc(result_pool, src->len * sizeof(*ucs4buf));
813289177Speter  for (i = 0; i < src->len; ++i)
814289177Speter    ucs4buf[i] = (unsigned char)(src->data[i]);
815289177Speter
816289177Speter  svn_membuf__create(&resultbuf, 2 * src->len, result_pool);
817289177Speter  SVN_ERR(svn_utf__encode_ucs4_string(
818289177Speter              &resultbuf, ucs4buf, src->len, &length));
819289177Speter
820289177Speter  res = apr_palloc(result_pool, sizeof(*res));
821289177Speter  res->data = resultbuf.data;
822289177Speter  res->len = length;
823289177Speter  *result = res;
824289177Speter  return SVN_NO_ERROR;
825289177Speter}
826289177Speter
827289177Speter/* Make a best effort to convert a X.509 name to a UTF-8 encoded
828289177Speter * string and return it.  If we can't properly convert just do a
829289177Speter * fuzzy conversion so we have something to display. */
830289177Speterstatic const char *
831289177Speterx509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool)
832289177Speter{
833289177Speter  const svn_string_t *src_string;
834289177Speter  const svn_string_t *utf8_string;
835289177Speter  svn_error_t *err;
836289177Speter
837289177Speter  src_string = svn_string_ncreate((const char *)name->val.p,
838289177Speter                                  name->val.len,
839289177Speter                                  result_pool);
840289177Speter  switch (name->val.tag)
841289177Speter    {
842289177Speter    case ASN1_UTF8_STRING:
843289177Speter      if (svn_utf__is_valid(src_string->data, src_string->len))
844289177Speter        return nul_escape(src_string, result_pool);
845289177Speter      else
846289177Speter        /* not a valid UTF-8 string, who knows what it is,
847289177Speter         * so run it through the fuzzy_escape code.  */
848289177Speter        return fuzzy_escape(src_string, result_pool);
849289177Speter      break;
850289177Speter
851289177Speter      /* Both BMP and UNIVERSAL should always be in Big Endian (aka
852289177Speter       * network byte order).  But rumor has it that there are certs
853289177Speter       * out there with other endianess and even Byte Order Marks.
854289177Speter       * If we actually run into these, we might need to do something
855289177Speter       * about it. */
856289177Speter
857289177Speter    case ASN1_BMP_STRING:
858289177Speter      if (0 != src_string->len % sizeof(apr_uint16_t))
859289177Speter          return fuzzy_escape(src_string, result_pool);
860289177Speter      err = svn_utf__utf16_to_utf8(&utf8_string,
861289177Speter                                   (const void*)(src_string->data),
862289177Speter                                   src_string->len / sizeof(apr_uint16_t),
863289177Speter                                   TRUE, result_pool, result_pool);
864289177Speter      break;
865289177Speter
866289177Speter    case ASN1_UNIVERSAL_STRING:
867289177Speter      if (0 != src_string->len % sizeof(apr_int32_t))
868289177Speter          return fuzzy_escape(src_string, result_pool);
869289177Speter      err = svn_utf__utf32_to_utf8(&utf8_string,
870289177Speter                                   (const void*)(src_string->data),
871289177Speter                                   src_string->len / sizeof(apr_int32_t),
872289177Speter                                   TRUE, result_pool, result_pool);
873289177Speter      break;
874289177Speter
875289177Speter      /* Despite what all the IETF, ISO, ITU bits say everything out
876289177Speter       * on the Internet that I can find treats this as ISO-8859-1.
877289177Speter       * Even the name is misleading, it's not actually T.61.  All the
878289177Speter       * gory details can be found in the Character Sets section of:
879289177Speter       * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
880289177Speter       */
881289177Speter    case ASN1_T61_STRING:
882289177Speter      err = latin1_to_utf8(&utf8_string, src_string, result_pool);
883289177Speter      break;
884289177Speter
885289177Speter      /* This leaves two types out there in the wild.  PrintableString,
886289177Speter       * which is just a subset of ASCII and IA5 which is ASCII (though
887289177Speter       * 0x24 '$' and 0x23 '#' may be defined with differnet symbols
888289177Speter       * depending on the location, in practice it seems everyone just
889289177Speter       * treats it as ASCII).  Since these are just ASCII run through
890289177Speter       * the fuzzy_escape code to deal with anything that isn't actually
891289177Speter       * ASCII.  There shouldn't be any other types here but if we find
892289177Speter       * a cert with some other encoding, the best we can do is the
893289177Speter       * fuzzy_escape().  Note: Technically IA5 isn't valid in this
894289177Speter       * context, however in the real world it may pop up. */
895289177Speter    default:
896289177Speter      return fuzzy_escape(src_string, result_pool);
897289177Speter    }
898289177Speter
899289177Speter  if (err)
900289177Speter    {
901289177Speter      svn_error_clear(err);
902289177Speter      return fuzzy_escape(src_string, result_pool);
903289177Speter    }
904289177Speter
905289177Speter  return nul_escape(utf8_string, result_pool);
906289177Speter}
907289177Speter
908289177Speterstatic svn_error_t *
909289177Speterx509_name_to_certinfo(apr_array_header_t **result,
910289177Speter                      const x509_name *dn,
911289177Speter                      apr_pool_t *scratch_pool,
912289177Speter                      apr_pool_t *result_pool)
913289177Speter{
914289177Speter  const x509_name *name = dn;
915289177Speter
916289177Speter  *result = apr_array_make(result_pool, 6, sizeof(svn_x509_name_attr_t *));
917289177Speter
918289177Speter  while (name != NULL) {
919289177Speter    svn_x509_name_attr_t *attr = apr_palloc(result_pool, sizeof(svn_x509_name_attr_t));
920289177Speter
921289177Speter    attr->oid_len = name->oid.len;
922289177Speter    attr->oid = apr_palloc(result_pool, attr->oid_len);
923289177Speter    memcpy(attr->oid, name->oid.p, attr->oid_len);
924289177Speter    attr->utf8_value = x509name_to_utf8_string(name, result_pool);
925289177Speter    if (!attr->utf8_value)
926289177Speter      /* this should never happen */
927289177Speter      attr->utf8_value = apr_pstrdup(result_pool, "??");
928289177Speter    APR_ARRAY_PUSH(*result, const svn_x509_name_attr_t *) = attr;
929289177Speter
930289177Speter    name = name->next;
931289177Speter  }
932289177Speter
933289177Speter  return SVN_NO_ERROR;
934289177Speter}
935289177Speter
936289177Speterstatic svn_boolean_t
937289177Speteris_hostname(const char *str)
938289177Speter{
939289177Speter  apr_size_t i, len = strlen(str);
940289177Speter
941289177Speter  for (i = 0; i < len; i++)
942289177Speter    {
943289177Speter      char c = str[i];
944289177Speter
945289177Speter      /* '-' is only legal when not at the start or end of a label */
946289177Speter      if (c == '-')
947289177Speter        {
948289177Speter          if (i + 1 != len)
949289177Speter            {
950289177Speter              if (str[i + 1] == '.')
951289177Speter                return FALSE; /* '-' preceeds a '.' */
952289177Speter            }
953289177Speter          else
954289177Speter            return FALSE; /* '-' is at end of string */
955289177Speter
956289177Speter          /* determine the previous character. */
957289177Speter          if (i == 0)
958289177Speter            return FALSE; /* '-' is at start of string */
959289177Speter          else
960289177Speter            if (str[i - 1] == '.')
961289177Speter              return FALSE; /* '-' follows a '.' */
962289177Speter        }
963289177Speter      else if (c != '*' && c != '.' && !svn_ctype_isalnum(c))
964289177Speter        return FALSE; /* some character not allowed */
965289177Speter    }
966289177Speter
967289177Speter  return TRUE;
968289177Speter}
969289177Speter
970289177Speterstatic const char *
971289177Speterx509parse_get_cn(apr_array_header_t *subject)
972289177Speter{
973289177Speter  int i;
974289177Speter
975289177Speter  for (i = 0; i < subject->nelts; ++i)
976289177Speter    {
977289177Speter      const svn_x509_name_attr_t *attr = APR_ARRAY_IDX(subject, i, const svn_x509_name_attr_t *);
978289177Speter      if (equal(attr->oid, attr->oid_len,
979289177Speter                SVN_X509_OID_COMMON_NAME, sizeof(SVN_X509_OID_COMMON_NAME) - 1))
980289177Speter        return attr->utf8_value;
981289177Speter    }
982289177Speter
983289177Speter  return NULL;
984289177Speter}
985289177Speter
986289177Speter
987289177Speterstatic void
988289177Speterx509parse_get_hostnames(svn_x509_certinfo_t *ci, x509_cert *crt,
989289177Speter                        apr_pool_t *result_pool, apr_pool_t *scratch_pool)
990289177Speter{
991289177Speter  ci->hostnames = NULL;
992289177Speter
993289177Speter  if (crt->dnsnames->nelts > 0)
994289177Speter    {
995289177Speter      int i;
996289177Speter
997289177Speter      ci->hostnames = apr_array_make(result_pool, crt->dnsnames->nelts,
998289177Speter                                     sizeof(const char*));
999289177Speter
1000289177Speter      /* Subject Alt Names take priority */
1001289177Speter      for (i = 0; i < crt->dnsnames->nelts; i++)
1002289177Speter        {
1003289177Speter          x509_buf *dnsname = APR_ARRAY_IDX(crt->dnsnames, i, x509_buf *);
1004289177Speter          const svn_string_t *temp = svn_string_ncreate((const char *)dnsname->p,
1005289177Speter                                                        dnsname->len,
1006289177Speter                                                        scratch_pool);
1007289177Speter
1008289177Speter          APR_ARRAY_PUSH(ci->hostnames, const char*)
1009289177Speter            = fuzzy_escape(temp, result_pool);
1010289177Speter        }
1011289177Speter    }
1012289177Speter  else
1013289177Speter    {
1014289177Speter      /* no SAN then get the hostname from the CommonName on the cert */
1015289177Speter      const char *utf8_value;
1016289177Speter
1017289177Speter      utf8_value = x509parse_get_cn(ci->subject);
1018289177Speter
1019289177Speter      if (utf8_value && is_hostname(utf8_value))
1020289177Speter        {
1021289177Speter          ci->hostnames = apr_array_make(result_pool, 1, sizeof(const char*));
1022289177Speter          APR_ARRAY_PUSH(ci->hostnames, const char*) = utf8_value;
1023289177Speter        }
1024289177Speter    }
1025289177Speter}
1026289177Speter
1027289177Speter/*
1028289177Speter * Parse one certificate.
1029289177Speter */
1030289177Spetersvn_error_t *
1031289177Spetersvn_x509_parse_cert(svn_x509_certinfo_t **certinfo,
1032289177Speter                    const char *buf,
1033289177Speter                    apr_size_t buflen,
1034289177Speter                    apr_pool_t *result_pool,
1035289177Speter                    apr_pool_t *scratch_pool)
1036289177Speter{
1037289177Speter  svn_error_t *err;
1038289177Speter  ptrdiff_t len;
1039289177Speter  const unsigned char *p;
1040289177Speter  const unsigned char *end;
1041289177Speter  x509_cert *crt;
1042289177Speter  svn_x509_certinfo_t *ci;
1043289177Speter
1044289177Speter  crt = apr_pcalloc(scratch_pool, sizeof(*crt));
1045289177Speter  p = (const unsigned char *)buf;
1046289177Speter  len = buflen;
1047289177Speter  end = p + len;
1048289177Speter
1049289177Speter  /*
1050289177Speter   * Certificate  ::=      SEQUENCE  {
1051289177Speter   *              tbsCertificate           TBSCertificate,
1052289177Speter   *              signatureAlgorithm       AlgorithmIdentifier,
1053289177Speter   *              signatureValue           BIT STRING      }
1054289177Speter   */
1055289177Speter  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
1056289177Speter  if (err)
1057289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1058289177Speter
1059289177Speter  if (len != (end - p))
1060289177Speter    {
1061289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
1062289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1063289177Speter    }
1064289177Speter
1065289177Speter  /*
1066289177Speter   * TBSCertificate  ::=  SEQUENCE  {
1067289177Speter   */
1068289177Speter  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
1069289177Speter  if (err)
1070289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1071289177Speter
1072289177Speter  end = p + len;
1073289177Speter
1074289177Speter  /*
1075289177Speter   * Version      ::=      INTEGER  {      v1(0), v2(1), v3(2)  }
1076289177Speter   *
1077289177Speter   * CertificateSerialNumber      ::=      INTEGER
1078289177Speter   *
1079289177Speter   * signature                    AlgorithmIdentifier
1080289177Speter   */
1081289177Speter  SVN_ERR(x509_get_version(&p, end, &crt->version));
1082289177Speter  SVN_ERR(x509_get_serial(&p, end, &crt->serial));
1083289177Speter  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid1));
1084289177Speter
1085289177Speter  crt->version++;
1086289177Speter
1087289177Speter  if (crt->version > 3)
1088289177Speter    return svn_error_create(SVN_ERR_X509_CERT_UNKNOWN_VERSION, NULL, NULL);
1089289177Speter
1090289177Speter  /*
1091289177Speter   * issuer                               Name
1092289177Speter   */
1093289177Speter  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
1094289177Speter  if (err)
1095289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1096289177Speter
1097289177Speter  SVN_ERR(x509_get_name(&p, p + len, &crt->issuer, scratch_pool));
1098289177Speter
1099289177Speter  /*
1100289177Speter   * Validity ::= SEQUENCE {
1101289177Speter   *              notBefore          Time,
1102289177Speter   *              notAfter           Time }
1103289177Speter   *
1104289177Speter   */
1105289177Speter  SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end,
1106289177Speter                         scratch_pool));
1107289177Speter
1108289177Speter  /*
1109289177Speter   * subject                              Name
1110289177Speter   */
1111289177Speter  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
1112289177Speter  if (err)
1113289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1114289177Speter
1115289177Speter  SVN_ERR(x509_get_name(&p, p + len, &crt->subject, scratch_pool));
1116289177Speter
1117289177Speter  /*
1118289177Speter   * SubjectPublicKeyInfo  ::=  SEQUENCE
1119289177Speter   *              algorithm                        AlgorithmIdentifier,
1120289177Speter   *              subjectPublicKey         BIT STRING      }
1121289177Speter   */
1122289177Speter  err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE);
1123289177Speter  if (err)
1124289177Speter    return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1125289177Speter
1126289177Speter  /* Skip pubkey. */
1127289177Speter  p += len;
1128289177Speter
1129289177Speter  /*
1130289177Speter   *      issuerUniqueID  [1]      IMPLICIT UniqueIdentifier OPTIONAL,
1131289177Speter   *                                               -- If present, version shall be v2 or v3
1132289177Speter   *      subjectUniqueID [2]      IMPLICIT UniqueIdentifier OPTIONAL,
1133289177Speter   *                                               -- If present, version shall be v2 or v3
1134289177Speter   *      extensions              [3]      EXPLICIT Extensions OPTIONAL
1135289177Speter   *                                               -- If present, version shall be v3
1136289177Speter   */
1137289177Speter  crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *));
1138289177Speter
1139289177Speter  /* Try to parse issuerUniqueID, subjectUniqueID and extensions for *every*
1140289177Speter   * version (X.509 v1, v2 and v3), not just v2 or v3.  If they aren't present,
1141289177Speter   * we are fine, but we don't want to throw an error if they are.  v1 and v2
1142289177Speter   * certificates with the corresponding extra fields are ill-formed per RFC
1143289177Speter   * 5280 s. 4.1, but we suspect they could exist in the real world.  Other
1144289177Speter   * X.509 parsers (e.g., within OpenSSL or Microsoft CryptoAPI) aren't picky
1145289177Speter   * about these certificates, and we also allow them. */
1146289177Speter  SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1));
1147289177Speter  SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2));
1148289177Speter  SVN_ERR(x509_get_ext(crt->dnsnames, &p, end));
1149289177Speter
1150289177Speter  if (p != end)
1151289177Speter    {
1152289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
1153289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1154289177Speter    }
1155289177Speter
1156289177Speter  end = (const unsigned char*) buf + buflen;
1157289177Speter
1158289177Speter  /*
1159289177Speter   *      signatureAlgorithm       AlgorithmIdentifier,
1160289177Speter   *      signatureValue           BIT STRING
1161289177Speter   */
1162289177Speter  SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid2));
1163289177Speter
1164289177Speter  if (!oids_equal(&crt->sig_oid1, &crt->sig_oid2))
1165289177Speter    return svn_error_create(SVN_ERR_X509_CERT_SIG_MISMATCH, NULL, NULL);
1166289177Speter
1167289177Speter  SVN_ERR(x509_get_sig(&p, end, &crt->sig));
1168289177Speter
1169289177Speter  if (p != end)
1170289177Speter    {
1171289177Speter      err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
1172289177Speter      return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL);
1173289177Speter    }
1174289177Speter
1175289177Speter  ci = apr_pcalloc(result_pool, sizeof(*ci));
1176289177Speter
1177289177Speter  /* Get the subject name */
1178289177Speter  SVN_ERR(x509_name_to_certinfo(&ci->subject, &crt->subject,
1179289177Speter                                scratch_pool, result_pool));
1180289177Speter
1181289177Speter  /* Get the issuer name */
1182289177Speter  SVN_ERR(x509_name_to_certinfo(&ci->issuer, &crt->issuer,
1183289177Speter                                scratch_pool, result_pool));
1184289177Speter
1185289177Speter  /* Copy the validity range */
1186289177Speter  ci->valid_from = crt->valid_from;
1187289177Speter  ci->valid_to = crt->valid_to;
1188289177Speter
1189289177Speter  /* Calculate the SHA1 digest of the certificate, otherwise known as
1190289177Speter    the fingerprint */
1191289177Speter  SVN_ERR(svn_checksum(&ci->digest, svn_checksum_sha1, buf, buflen,
1192289177Speter                       result_pool));
1193289177Speter
1194289177Speter  /* Construct the array of host names */
1195289177Speter  x509parse_get_hostnames(ci, crt, result_pool, scratch_pool);
1196289177Speter
1197289177Speter  *certinfo = ci;
1198289177Speter  return SVN_NO_ERROR;
1199289177Speter}
1200289177Speter
1201